More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 607 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Approve | 21617335 | 23 days ago | IN | 0 ETH | 0.00038054 | ||||
Approve | 21561798 | 31 days ago | IN | 0 ETH | 0.00039613 | ||||
Transfer | 21559410 | 31 days ago | IN | 0 ETH | 0.00052155 | ||||
Approve | 21424333 | 50 days ago | IN | 0 ETH | 0.00093383 | ||||
Approve | 21380233 | 56 days ago | IN | 0 ETH | 0.00151469 | ||||
Approve | 21342019 | 61 days ago | IN | 0 ETH | 0.00051613 | ||||
Approve | 21289185 | 69 days ago | IN | 0 ETH | 0.00037697 | ||||
Approve | 21205827 | 80 days ago | IN | 0 ETH | 0.00045027 | ||||
Approve | 21069639 | 99 days ago | IN | 0 ETH | 0.00029593 | ||||
Transfer | 21042686 | 103 days ago | IN | 0 ETH | 0.00024888 | ||||
Approve | 21036479 | 104 days ago | IN | 0 ETH | 0.00033848 | ||||
Approve | 21036479 | 104 days ago | IN | 0 ETH | 0.00059647 | ||||
Transfer | 21034839 | 104 days ago | IN | 0 ETH | 0.00030099 | ||||
Transfer | 21033037 | 105 days ago | IN | 0 ETH | 0.0002569 | ||||
Approve | 21033017 | 105 days ago | IN | 0 ETH | 0.00041404 | ||||
Approve | 21033011 | 105 days ago | IN | 0 ETH | 0.00023845 | ||||
Approve | 21032986 | 105 days ago | IN | 0 ETH | 0.00045235 | ||||
Approve | 21032980 | 105 days ago | IN | 0 ETH | 0.00021533 | ||||
Approve | 21032965 | 105 days ago | IN | 0 ETH | 0.0003349 | ||||
Approve | 21032960 | 105 days ago | IN | 0 ETH | 0.0001864 | ||||
Approve | 21032933 | 105 days ago | IN | 0 ETH | 0.00037177 | ||||
Approve | 21032928 | 105 days ago | IN | 0 ETH | 0.00017619 | ||||
Approve | 21032909 | 105 days ago | IN | 0 ETH | 0.00023249 | ||||
Approve | 21032893 | 105 days ago | IN | 0 ETH | 0.00043464 | ||||
Approve | 21032875 | 105 days ago | IN | 0 ETH | 0.00025044 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
USDXToken
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; contract USDXToken is ERC20Burnable, Ownable, Pausable, AccessControlEnumerable{ bytes32 public constant OPERATOR = keccak256("OPERATOR"); constructor( address initialOwner, address initialAdmin) ERC20("USDXToken", "USDX") Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function _update(address from, address to, uint256 value) internal virtual override whenNotPaused { super._update(from, to, value); } function mint(address to, uint256 amount) public onlyRole(OPERATOR) { _mint(to, amount); } function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { _pause(); } function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../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: * * ```solidity * 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}: * * ```solidity * 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. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ 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 returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @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 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 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 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 `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @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 Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol) pragma solidity ^0.8.20; import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol"; import {AccessControl} from "../AccessControl.sol"; import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { using EnumerableSet for EnumerableSet.AddressSet; mapping(bytes32 role => EnumerableSet.AddressSet) private _roleMembers; /**w * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) { return _roleMembers[role].at(index); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) { return _roleMembers[role].length(); } /** * @dev Overload {AccessControl-_grantRole} to track enumerable memberships */ function _grantRole(bytes32 role, address account) internal virtual override returns (bool) { bool granted = super._grantRole(role, account); if (granted) { _roleMembers[role].add(account); } return granted; } /** * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships */ function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) { bool revoked = super._revokeRole(role, account); if (revoked) { _roleMembers[role].remove(account); } return revoked; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol) pragma solidity ^0.8.20; import {IAccessControl} from "../IAccessControl.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerable is IAccessControl { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @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. */ 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 `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; import {Context} from "../../utils/Context.sol"; import {IERC20Errors} from "../../interfaces/draft-IERC6093.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}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. */ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { mapping(address account => uint256) private _balances; mapping(address account => mapping(address spender => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual 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 `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `value` 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 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); 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 `value`. * - the caller must have allowance for ``from``'s tokens of at least * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @dev Moves a `value` 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. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(from, to, value); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { if (from == address(0)) { // Overflow check required: The rest of the code assumes that totalSupply never overflows _totalSupply += value; } else { uint256 fromBalance = _balances[from]; if (fromBalance < value) { revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { // Overflow not possible: value <= fromBalance <= totalSupply. _balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. _totalSupply -= value; } } else { unchecked { // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. _balances[to] += value; } } emit Transfer(from, to, value); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } _update(account, address(0), value); } /** * @dev Sets `value` 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. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { _approve(owner, spender, value, true); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * ``` * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } _allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Context} from "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys a `value` amount of tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 value) public virtual { _burn(_msgSender(), value); } /** * @dev Destroys a `value` amount of tokens from `account`, deducting from * the caller's allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `value`. */ function burnFrom(address account, uint256 value) public virtual { _spendAllowance(account, _msgSender(), value); _burn(account, value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; /** * @dev Extension of {ERC20} that adds a cap to the supply of tokens. */ abstract contract ERC20Capped is ERC20 { uint256 private immutable _cap; /** * @dev Total supply cap has been exceeded. */ error ERC20ExceededCap(uint256 increasedSupply, uint256 cap); /** * @dev The supplied cap is not a valid cap. */ error ERC20InvalidCap(uint256 cap); /** * @dev Sets the value of the `cap`. This value is immutable, it can only be * set once during construction. */ constructor(uint256 cap_) { if (cap_ == 0) { revert ERC20InvalidCap(0); } _cap = cap_; } /** * @dev Returns the cap on the token's total supply. */ function cap() public view virtual returns (uint256) { return _cap; } /** * @dev See {ERC20-_update}. */ function _update(address from, address to, uint256 value) internal virtual override { super._update(from, to, value); if (from == address(0)) { uint256 maxSupply = cap(); uint256 supply = totalSupply(); if (supply > maxSupply) { revert ERC20ExceededCap(supply, maxSupply); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Pausable.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Pausable} from "../../../utils/Pausable.sol"; /** * @dev ERC20 token with pausable token transfers, minting and burning. * * Useful for scenarios such as preventing trades until the end of an evaluation * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. * * IMPORTANT: This contract does not include public pause and unpause functions. In * addition to inheriting this contract, you must define both functions, invoking the * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will * make the contract pause mechanism of the contract unreachable, and thus unusable. */ abstract contract ERC20Pausable is ERC20, Pausable { /** * @dev See {ERC20-_update}. * * Requirements: * * - the contract must not be paused. */ function _update(address from, address to, uint256 value) internal virtual override whenNotPaused { super._update(from, to, value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @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; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./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); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { bool private _paused; /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @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), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @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) { uint256 localValue = value; 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] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } 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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Callback for IUniswapV3PoolActions#swap /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface interface IUniswapV3SwapCallback { /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. /// @dev In the implementation you must pay the pool tokens owed for the swap. /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function uniswapV3SwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; pragma abicoder v2; /// @title Quoter Interface /// @notice Supports quoting the calculated amounts from exact input or exact output swaps /// @dev These functions are not marked view because they rely on calling non-view functions and reverting /// to compute the result. They are also not gas efficient and should not be called on-chain. interface IQuoter { /// @notice Returns the amount out received for a given exact input swap without executing the swap /// @param path The path of the swap, i.e. each token pair and the pool fee /// @param amountIn The amount of the first token to swap /// @return amountOut The amount of the last token that would be received function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut); /// @notice Returns the amount out received for a given exact input but for a swap of a single pool /// @param tokenIn The token being swapped in /// @param tokenOut The token being swapped out /// @param fee The fee of the token pool to consider for the pair /// @param amountIn The desired input amount /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap /// @return amountOut The amount of `tokenOut` that would be received function quoteExactInputSingle( address tokenIn, address tokenOut, uint24 fee, uint256 amountIn, uint160 sqrtPriceLimitX96 ) external returns (uint256 amountOut); /// @notice Returns the amount in required for a given exact output swap without executing the swap /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order /// @param amountOut The amount of the last token to receive /// @return amountIn The amount of first token required to be paid function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn); /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool /// @param tokenIn The token being swapped in /// @param tokenOut The token being swapped out /// @param fee The fee of the token pool to consider for the pair /// @param amountOut The desired output amount /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` function quoteExactOutputSingle( address tokenIn, address tokenOut, uint24 fee, uint256 amountOut, uint160 sqrtPriceLimitX96 ) external returns (uint256 amountIn); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; pragma abicoder v2; import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface ISwapRouter is IUniswapV3SwapCallback { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; library TransferHelper { /// @notice Transfers tokens from the targeted address to the given destination /// @notice Errors with 'STF' if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom( address token, address from, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF'); } /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST'); } /// @notice Approves the stipulated contract to spend the given allowance in the given token /// @dev Errors with 'SA' if transfer fails /// @param token The contract address of the token to be approved /// @param to The target of the approval /// @param value The amount of the given token the target will be allowed to spend function safeApprove( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA'); } /// @notice Transfers ETH to the recipient address /// @dev Fails with `STE` /// @param to The destination of the transfer /// @param value The value to be transferred function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); require(success, 'STE'); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "./Const.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; // import "hardhat/console.sol"; // Access control: owner sets default admin, admin manages roles; // owner and admin should be different otherwise this contract will be at risk when owner is unreachable contract BankVaultL is Ownable, AccessControlEnumerable, Pausable { using SafeERC20 for IERC20; bytes32 public constant OPERATOR = keccak256("OPERATOR"); // a contract where BankVaultL sends money to address public predefinedContract; uint private maxAmountPerTrans = 200000 * Const.MULTIPLIER_18; uint[] private transactionTimeArr; uint private allowedAmountCap = 1000000 * Const.MULTIPLIER_18; uint private transferredAmount; address public A_leverage; event TransferDYDX2Leverage(uint amount); constructor( address initialOwner, address initialAdmin, address contractAddr, address a_leverage ) Ownable(initialOwner) { // Grant the default admin role: it will be able to grant and revoke any roles // default admin role can have multiple accounts, but we will try to make it have only one account _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); require(contractAddr != address(0), "Invalid address provided"); predefinedContract = contractAddr; a_leverage = A_leverage; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function transferDYDX2Leverage(address tokenAddress, uint amount) external { // only allow leverage contract to call require(msg.sender == A_leverage, "Unauthorized"); IERC20 token = IERC20(tokenAddress); token.safeTransfer(A_leverage, amount); emit TransferDYDX2Leverage(amount); } function transfer2Contract(uint amount) public whenNotPaused onlyRole(OPERATOR) { require(predefinedContract != address(0), "Invalid predefinedContract"); require(amount <= maxAmountPerTrans, "amount must be less than max amount per transaction"); IERC20 dydx = IERC20(Const.A_DYDX); require(amount <= dydx.balanceOf(address(this)), "Not enough DYDX fund"); require(_checkExceedLimitRate(), "Exeed daily transaction limit"); transferredAmount += amount; require(_checkExeedTransferredAmt(), "Exeed transferred amount cap"); dydx.safeTransfer(predefinedContract, amount); } function transfer(address addr, uint amount) public whenNotPaused onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address"); require(amount <= maxAmountPerTrans, "amount must be less than max amount per transaction"); IERC20 dydx = IERC20(Const.A_DYDX); require(amount <= dydx.balanceOf(address(this)), "Not enough DYDX fund"); require(_checkExceedLimitRate(), "Exeed daily transaction limit"); transferredAmount += amount; require(_checkExeedTransferredAmt(), "Exeed transferred amount cap"); dydx.safeTransfer(addr, amount); } function _checkExceedLimitRate() private returns (bool){ uint len = transactionTimeArr.length; if(len > 5 && block.timestamp - transactionTimeArr[len - 5] <= 86400){ return false; } transactionTimeArr.push(block.timestamp); return true; } function _checkExeedTransferredAmt() private view returns (bool){ return transferredAmount <= allowedAmountCap; } function setMaxAmountPerTrans(uint val) external onlyRole(OPERATOR) { maxAmountPerTrans = val; } function setAllowedAmountCap(uint val) external onlyRole(OPERATOR) { allowedAmountCap = val; } function pause() public onlyOwner { _pause(); } function unpause() public onlyOwner { _unpause(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "./Const.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; // import "hardhat/console.sol"; // Access control: owner sets default admin, admin manages roles; // owner and admin should be different otherwise this contract will be at risk when owner is unreachable contract BankVaultX is Ownable, AccessControlEnumerable, Pausable { using SafeERC20 for IERC20; bytes32 public constant OPERATOR = keccak256("OPERATOR"); // a contract where BankVaultX sends money to address public predefinedContract; uint private maxAmountPerTrans = 200000 * Const.MULTIPLIER_18; uint[] private transactionTimeArr; uint private allowedAmountCap = 1000000 * Const.MULTIPLIER_18; uint private transferredAmount; event Price(uint indexed price); constructor( address initialOwner, address initialAdmin, address contractAddr ) Ownable(initialOwner) { // Grant the default admin role: it will be able to grant and revoke any roles // default admin role can have multiple accounts! _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); require(contractAddr != address(0), "Invalid address provided"); predefinedContract = contractAddr; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function transfer2Contract(uint amount) public whenNotPaused onlyRole(OPERATOR) { require(predefinedContract != address(0), "Invalid predefinedContract"); require(amount <= maxAmountPerTrans, "Amount must be less than max amount per transaction"); IERC20 dydx = IERC20(Const.A_DYDX); require(amount <= dydx.balanceOf(address(this)), "Not enough DYDX fund"); require(_checkExceedLimitRate(), "Exeed daily transaction limit"); transferredAmount += amount; require(_checkExeedTransferredAmt(), "Exeed transferred amount cap"); dydx.safeTransfer(predefinedContract, amount); } function transfer(address addr, uint amount) public whenNotPaused onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address"); require(amount <= maxAmountPerTrans, "Amount must be less than max amount per transaction"); IERC20 dydx = IERC20(Const.A_DYDX); require(amount <= dydx.balanceOf(address(this)), "Not enough DYDX fund"); require(_checkExceedLimitRate(), "Exeed daily transaction limit"); transferredAmount += amount; require(_checkExeedTransferredAmt(), "Exeed transferred amount cap"); dydx.safeTransfer(addr, amount); } function _checkExceedLimitRate() private returns (bool){ uint len = transactionTimeArr.length; if(len > 5 && block.timestamp - transactionTimeArr[len - 5] <= 86400){ return false; } transactionTimeArr.push(block.timestamp); return true; } function _checkExeedTransferredAmt() private view returns (bool){ return transferredAmount <= allowedAmountCap; } function setMaxAmountPerTrans(uint val) external onlyRole(OPERATOR) { maxAmountPerTrans = val; } function setAllowedAmountCap(uint val) external onlyRole(OPERATOR) { allowedAmountCap = val; } function pause() public onlyOwner { _pause(); } function unpause() public onlyOwner { _unpause(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; library Const { uint public constant MULTIPLIER_18 = 10 ** 18; uint public constant MULTIPLIER_6 = 10 ** 6; address public constant A_USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; // address public constant A_DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; address public constant A_DYDX = 0x92D6C1e31e14520e676a687F0a93788B716BEff5; address public constant A_DYDX_USDT_POOL = 0x6C4AB1907805AdCB0B7ae911A5d1B0B99d608B3C; address public constant A_UNI_QUOTER = 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; contract Invitation is Ownable, AccessControlEnumerable { // Key: account A; Value: whether A is registered mapping(address => bool) public registeredMap; // Track who invited whom(me). Key: account A; Value: A's inviter mapping(address => address) public inviterOf; // Key: account A; Value: A's root inviter mapping(address => address) public rootInviterOf; // Key: account A; Value: acccounts that A has invited mapping(address => address[]) public inviteesOf; error SameAdminAddress(); error SameInviterAddress(); error InvalidAddress(); error AlreadyRegistered(); error InviterUnregistered(); error AccountUnregistered(); error SelfInvitationNotAllowed(); event Invite(address indexed inviter, address indexed invitee); event AdminInvite(address indexed inviter, address indexed invitee); constructor( address initialOwner, address initialAdmin ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); if(currentAdmin == addr) revert SameAdminAddress(); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function register(address inviter) public { if(registeredMap[msg.sender]) revert AlreadyRegistered(); // there is an inviter if(inviter != address(0)){ if(!registeredMap[inviter]) revert InviterUnregistered(); inviterOf[msg.sender] = inviter; if(!_elementExists(inviteesOf[inviter], msg.sender)){ inviteesOf[inviter].push(msg.sender); } rootInviterOf[msg.sender] = _getRootInviter(inviter); } registeredMap[msg.sender] = true; emit Invite(inviter, msg.sender); } function adminSetInviter(address addr, address inviter) public onlyRole(DEFAULT_ADMIN_ROLE) { if(addr == address(0)) revert InvalidAddress(); if(!registeredMap[addr]) revert AccountUnregistered(); if(inviter != address(0) && !registeredMap[inviter]) revert InviterUnregistered(); if(addr == inviter) revert SelfInvitationNotAllowed(); address currentInviter = inviterOf[addr]; if(inviter == currentInviter) revert SameInviterAddress(); inviterOf[addr] = inviter; _removeElement(inviteesOf[currentInviter], addr); if(inviter != address(0) && !_elementExists(inviteesOf[inviter], addr)){ inviteesOf[inviter].push(addr); } rootInviterOf[addr] = _getRootInviter(inviter); _setRootInviter4Invitees(inviteesOf[addr], addr, inviter); emit AdminInvite(inviter, addr); } function _setRootInviter4Invitees(address[] memory inviteesArr, address addr, address inviter) private { uint len = inviteesArr.length; for(uint i; i < len; i++){ rootInviterOf[inviteesArr[i]] = inviter==address(0) ? addr : _getRootInviter(inviter); _setRootInviter4Invitees(inviteesOf[inviteesArr[i]], inviteesArr[i], inviterOf[inviteesArr[i]]); } } function _getRootInviter(address inviter) view private returns(address){ // the account is root, so its inviter and root inviter is address(0) if(inviter == address(0)) return address(0); return (rootInviterOf[inviter] == address(0)) ? inviter : rootInviterOf[inviter]; } function _removeElement(address[] storage array, address e) private { uint len = array.length; for (uint i = 0; i < len; i++) { if (array[i] == e) { array[i] = array[len - 1]; array.pop(); } } } function _elementExists(address[] memory array, address target) private pure returns (bool) { for (uint i = 0; i < array.length; i++) { if (array[i] == target) { return true; } } return false; } function getInvitees(address addr) public view returns (address[] memory) { return inviteesOf[addr]; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "./IStaking.sol"; import "hardhat/console.sol"; interface IInvitation { function inviterOf(address _account) external view returns (address); function rootInviterOf(address _account) external view returns (address); function inviteesOf(address _account) external view returns (address[] memory); } interface ISavings { function listAllSStakingContracts() external view returns (address[] memory); } contract InviteReward is Ownable, Pausable, AccessControlEnumerable { using SafeERC20 for IERC20; bytes32 public constant OPERATOR = keccak256("OPERATOR"); uint inviteRewardRate = 5; //5% uint indirectInviteRewardRate = 3; //3% bool claimIndirectInvitationRewards = true; address A_t100x; address A_staking100xt; address A_savings; address A_Invitation; // Key: account A; Value: A's last claimed block number mapping(address => uint) lastClaimedBlockNO; // Key: account A; Value: A's total claimed 100xt from invitations mapping(address => uint) public claimed; constructor( address initialOwner, address initialAdmin, address a_t100x, address a_invitation ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); A_t100x = a_t100x; A_Invitation = a_invitation; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function getInvitationRewards(address addr) public view returns (uint){ IInvitation inviteContract = IInvitation(A_Invitation); address[] memory invitees = inviteContract.inviteesOf(addr); uint inviteesRewards; uint indirectInviteesRewards; for (uint i = 0; i < invitees.length; i++) { inviteesRewards += getContractsRewards(invitees[i]); if(claimIndirectInvitationRewards){ address[] memory indirectInvitees = inviteContract.inviteesOf(invitees[i]); for (uint j = 0; j < indirectInvitees.length; j++) { indirectInviteesRewards += getContractsRewards(indirectInvitees[j]); } } } return (inviteesRewards * inviteRewardRate + indirectInviteesRewards * indirectInviteRewardRate) / 100; } function getContractsRewards(address addr) public view returns (uint){ ISavings savingsContract = ISavings(A_savings); address[] memory addresses = savingsContract.listAllSStakingContracts(); uint length = addresses.length; uint rewards; for (uint i = 0; i < length; ++i) { IStaking sStakingContract = IStaking(addresses[i]); rewards += sStakingContract.rewards(addr, lastClaimedBlockNO[addr]); // rewards += sStakingContract.rewards(addr, lastClaimedBlockNO[msg.sender]); } if(A_staking100xt != address(0)){ IStaking staking100xtContract = IStaking(A_staking100xt); rewards += staking100xtContract.rewards(addr, lastClaimedBlockNO[addr]); // rewards += staking100xtContract.rewards(addr, lastClaimedBlockNO[msg.sender]); } return rewards; } /** * Manual Operation: mint 100xt to this contract for rewarding. * A child withdraw all the money, I may lose rewards from him,so claiming regularly is a good practice. */ function claimInvitationRewards() public whenNotPaused returns (uint){ uint totalAmount = getInvitationRewards(msg.sender); claimed[msg.sender] += totalAmount; lastClaimedBlockNO[msg.sender] = block.number; // transfer the rewards IERC20 token = IERC20(A_t100x); token.safeTransfer(msg.sender, totalAmount); return totalAmount; } /** * For calculating leverage ratio */ function getLeverageDepositAmt(address addr) public view returns (uint){ ISavings savingsContract = ISavings(A_savings); address[] memory addresses = savingsContract.listAllSStakingContracts(); uint length = addresses.length; uint amount; for (uint i = 0; i < length; ++i) { IStaking sStakingContract = IStaking(addresses[i]); amount += sStakingContract.balanceOf(addr); } return amount; } // 100XT amount function getLeverageAmt(address addr) public view returns (uint){ uint invitateRewardAmt = claimed[addr]; uint myReward; ISavings savingsContract = ISavings(A_savings); address[] memory addresses = savingsContract.listAllSStakingContracts(); uint length = addresses.length; for (uint i = 0; i < length; ++i) { IStaking sStakingContract = IStaking(addresses[i]); myReward += sStakingContract.getMyClaimed(addr); } if(A_staking100xt != address(0)){ IStaking staking100xtContract = IStaking(A_staking100xt); myReward += staking100xtContract.getMyClaimed(addr); } return invitateRewardAmt + myReward * 20 / 100; } function setClaimIndirectInvitationRewards(bool flag) external onlyRole(OPERATOR) { claimIndirectInvitationRewards = flag; } function setInviteRewardRate(uint rate) external onlyRole(OPERATOR) { require(rate >= 0, "value needs to be greater than 0"); require(rate < 20, "value needs to be less than 20"); inviteRewardRate = rate; } function setIndirectInviteRewardRate(uint rate) external onlyRole(OPERATOR) { require(rate >= 0, "value needs to be greater than 0"); require(rate < 10, "value needs to be less than 10"); indirectInviteRewardRate = rate; } function set100XTAddr(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_t100x = addr; } function setStaking100XTAddr(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_staking100xt = addr; } function setSavingsAddr(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_savings = addr; } function setInvitationAddr(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_Invitation = addr; } function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { _pause(); } function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; interface IOracle { /** * @param oracleType 1: system's preset value 2: uniswap 3: other oracle source like chainlink etc * * e.g. tokenIn=DYDX tokenOut=100XT and (1 DYDX)=(2.05 100XT) * return value will be 2.05*(10**18): 18 is 100XT's decimal * Note: if want to get a token's USD price, tokenOut can be set to "USDT" * Note:for future oracle implementation: if the token/baseToken pair does not exist in mapping, use 3rd-party oracle! */ function getPrice(string calldata tokenInSymbol, string calldata tokenOutSymbol, uint oracleType) external returns (uint); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; // For refering staking contracts in Invitation.sol, so we only define this method for now interface IStaking { function rewards(address addr, uint startBlockNO) external view returns (uint); function getMyClaimed(address addr) external view returns (uint); function balanceOf(address _account) external view returns (uint); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import "./IOracle.sol"; // import "hardhat/console.sol"; import "./Const.sol"; // todo: admin to set ratio and leverage amount for particular account! interface ISavings { function transfer2Leverage(address tokenAddress, uint amount) external; } interface IBankVaultL { function transferDYDX2Leverage(address tokenAddress, uint amount) external; } interface IInviteReward { function getLeverageDepositAmt(address addr) external view returns (uint); function claimed(address addr) external view returns (uint); function getLeverageAmt(address addr) external view returns (uint); } interface IInvitation { function inviterOf(address _account) external view returns (address); function rootInviterOf(address _account) external view returns (address); function inviteesOf(address _account) external view returns (address[] memory); } // need to set system address during/after deployment contract Leverage is Ownable, Pausable, AccessControlEnumerable { using SafeERC20 for IERC20; bytes32 private constant OPERATOR = keccak256("OPERATOR"); ISwapRouter private immutable swapRouter; address private A_USDX; address private A_100XT; address private A_Savings; address private A_Invitation; address private A_InvitReward; address private A_BankVault; address private A_OracleProxy; // system address to receive earnings if there are no inviters address public A_System; // if leverage ratio=2, user pay 2*10=20 100xt uint public leverage100xtFeeRate = 10 * Const.MULTIPLIER_18; uint public leverageFeeRate = 1000; // leverage fee = 0.1%. uint16 public poolFee = 3000; // 0.3% // ratio increment 1, per 20,000 USD uint public ratioPerAmount = 20000 * Const.MULTIPLIER_18; uint16 public systemRatioLimit = 100; uint public sysLeverageShortAmtLimit = 10000; uint private swapAmtOutMinRate = 80; //80% uint public USDTLimitPerSwap = 50000 * Const.MULTIPLIER_6; // balances' key will be USDT or USDX to distinguish different type of trade struct User { mapping(string => uint) dydxbalances; mapping(string => uint) borrowedbalances; mapping(string => uint) principalAmt;//new // mapping(string => uint) withdrawalAmt;//new uint usedLeverageShortAmt; // 10,000 for USDX + USDT } mapping(address => User) public user; uint public sysProfitRate = 5; uint public inviterProfitRate = 5; uint public rootInviterProfitRate =10; uint private t100xUsdtPriceType = 1; uint private dydxUsdxPriceType = 1; uint private dydxUsdtPriceType = 1; constructor( address initialOwner, address initialAdmin, ISwapRouter _swapRouter, address _a_usdx, address _a_t100xt, address _a_savings, address _a_invitation, address _a_invite_reward, address _a_oracle_proxy ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); swapRouter = _swapRouter; require(_a_usdx != address(0), "Invalid address provided"); require(_a_t100xt != address(0), "Invalid address provided"); require(_a_savings != address(0), "Invalid address provided"); require(_a_invitation != address(0), "Invalid address provided"); require(_a_invite_reward != address(0), "Invalid address provided"); require(_a_oracle_proxy != address(0), "Invalid address provided"); A_USDX = _a_usdx; A_100XT = _a_t100xt; A_Savings = _a_savings; A_Invitation = _a_invitation; A_InvitReward = _a_invite_reward; A_OracleProxy = _a_oracle_proxy; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } //usdx or usdt function useLeverage(address tokenAddr, uint amountIn, uint16 ratio) external whenNotPaused returns (uint amountOut) { require(tokenAddr == Const.A_USDT || tokenAddr == A_USDX, "Token must be USDX or USDT"); // check max ratio uint allowedMaxRatio = getAllowedMaxRatio(); require(ratio <= allowedMaxRatio, string(abi.encodePacked("Exeed max ratio: ", Strings.toString(allowedMaxRatio)))); // check max leverage amount, make sure the amount does not exceed limit even if the user has multiple leverages uint shortAmtIn = _getShortAmt(tokenAddr, amountIn); uint allowedShortAmt = getAllowedLeverageShortAmt(msg.sender); uint usedShortAmt = user[msg.sender].usedLeverageShortAmt; require(allowedShortAmt > usedShortAmt, string(abi.encodePacked("Leverage short amount used: ", Strings.toString(usedShortAmt)))); uint currentAllowedShortAmt = allowedShortAmt - usedShortAmt; require(shortAmtIn <= currentAllowedShortAmt, string(abi.encodePacked("Exceed current allowed leverage short amount: ", Strings.toString(currentAllowedShortAmt)))); // msg.sender must approve this contract!!! R: Should be done on the web3 side! // pay principal: Transfer the specified amount of token(usdx/usdt) to this contract. TransferHelper.safeTransferFrom(tokenAddr, msg.sender, address(this), amountIn); // pay 100x IERC20 t100x = IERC20(A_100XT); // frontend to call approve t100x.safeTransferFrom(msg.sender, address(this), ratio * leverage100xtFeeRate); user[msg.sender].usedLeverageShortAmt += amountIn / _decimals(tokenAddr); user[msg.sender].principalAmt[_symbol(tokenAddr)] += amountIn; user[msg.sender].borrowedbalances[_symbol(tokenAddr)] += amountIn * ratio; // borrow money from savings // TODO consider UX when not enough money to borrow ISavings savingsContract = ISavings(A_Savings); savingsContract.transfer2Leverage(tokenAddr, amountIn * ratio); // calculate fees uint totalAmount = amountIn * (ratio + 1); uint swapAmount = _distributeFees(tokenAddr, totalAmount); // swap // TODO: consider big swap strategy! multiple leverages for one user! to store how much a user has used leverage! amountOut = _swap(tokenAddr, Const.A_DYDX, swapAmount, A_BankVault); user[msg.sender].dydxbalances[_symbol(tokenAddr)] += amountOut; } /** * @param tokenAddr indicate selling for USDX OR USDT */ function sell(uint dydxAmountIn, address tokenAddr) external whenNotPaused returns (uint amountOut) { require(user[msg.sender].dydxbalances[_symbol(tokenAddr)] >= dydxAmountIn, "Not enough dydx amount in user's account"); require(ifAllowSelling(tokenAddr, msg.sender), "Selling is blocked due to shrinked asset"); IERC20 token = IERC20(tokenAddr); // transfer dydx from VaultL to this contract IBankVaultL bankVault = IBankVaultL(A_BankVault); bankVault.transferDYDX2Leverage(Const.A_DYDX, dydxAmountIn); amountOut = _swap(Const.A_DYDX, tokenAddr, dydxAmountIn, address(this)); user[msg.sender].dydxbalances[_symbol(tokenAddr)] -= dydxAmountIn; // calculate fees amountOut = _distributeFees(tokenAddr, amountOut); // return borrowed money uint borrowedAmt = user[msg.sender].borrowedbalances[_symbol(tokenAddr)]; if(borrowedAmt > 0){ uint returnAmt = (borrowedAmt > amountOut) ? amountOut : borrowedAmt; user[msg.sender].borrowedbalances[_symbol(tokenAddr)] -= returnAmt; amountOut -= returnAmt; token.safeTransfer(A_Savings, returnAmt); } // calculate profit if(amountOut > 0){ // return principal uint principalAmt = user[msg.sender].principalAmt[_symbol(tokenAddr)]; // pay back principal first if(principalAmt > 0 && principalAmt >= amountOut){ user[msg.sender].principalAmt[_symbol(tokenAddr)] -= amountOut; token.safeTransfer(msg.sender, amountOut); // pay back all the principal }else if(principalAmt > 0 && principalAmt < amountOut){ amountOut -= principalAmt; user[msg.sender].principalAmt[_symbol(tokenAddr)] = 0; amountOut = _distributeProfit(token, amountOut); token.safeTransfer(msg.sender, principalAmt + amountOut); }else{ // the account has earned back all the principal amount already amountOut = _distributeProfit(token, amountOut); token.safeTransfer(msg.sender, amountOut); } } // return 100xt } /** * @param tokenAddr USDX address or USDT address * @param addr caller's address * return true if user's dydx'value is greater than the borrowed coins */ function ifAllowSelling(address tokenAddr, address addr) public returns (bool) { IOracle oracle = IOracle(A_OracleProxy); string memory symbol = _symbol(tokenAddr); uint priceType = (keccak256(abi.encodePacked(symbol)) == keccak256(abi.encodePacked("USDX"))) ? dydxUsdxPriceType : dydxUsdtPriceType; uint dydxPrice = oracle.getPrice("DYDX", symbol, priceType); return user[addr].dydxbalances[symbol] * dydxPrice > user[addr].borrowedbalances[_symbol(tokenAddr)]; } function _distributeProfit(IERC20 token, uint amount) private returns (uint pay2user) { uint pay2sysAmt = amount * sysProfitRate / 100; uint pay2inviterAmt = amount * inviterProfitRate / 100; uint pay2rootInviterAmt = amount * rootInviterProfitRate / 100; IInvitation inviteContract = IInvitation(A_Invitation); token.safeTransfer(inviteContract.inviterOf(msg.sender), pay2inviterAmt); address rootInviterAddr = inviteContract.rootInviterOf(msg.sender); if(rootInviterAddr != address(0)){ token.safeTransfer(rootInviterAddr, pay2rootInviterAmt); token.safeTransfer(A_System, pay2sysAmt); }else{ // if root address does not exist, use system address instead! token.safeTransfer(A_System, pay2rootInviterAmt + pay2sysAmt); } pay2user = amount - pay2sysAmt - pay2inviterAmt - pay2rootInviterAmt; } function _distributeFees(address tokenAddr, uint amount) private returns (uint) { uint leverageFee = amount * leverageFeeRate / 1000000; uint pay2inviterAmt = leverageFee / 2; uint pay2rootInviterAmt = leverageFee - pay2inviterAmt; IERC20 token = IERC20(tokenAddr); IInvitation inviteContract = IInvitation(A_Invitation); token.safeTransfer(inviteContract.inviterOf(msg.sender), pay2inviterAmt); address rootInviterAddr = inviteContract.rootInviterOf(msg.sender); // check: if root address does not exist, use system address instead! token.safeTransfer((rootInviterAddr==address(0)) ? A_System : rootInviterAddr, pay2rootInviterAmt); return amount - leverageFee; } // The calling address must approve this contract to spend at least `amountIn` worth of its USDT for this function to succeed. function _swap(address tokenIn, address tokenOut, uint amountIn, address outAddr) private returns (uint amountOut) { // Approve the router to spend USDT TransferHelper.safeApprove(tokenIn, address(swapRouter), amountIn); // only swap max 50K USDT a time. Leftover will be swapped next time along with others' funds uint swapAmount = amountIn; // uint swapAmount = getSwapAmount(amountIn, address(this).balance); // Naively set amountOutMinimum to 0. In production, use an oracle or other data source to choose a safer value for amountOutMinimum. // We also set the sqrtPriceLimitx96 to be 0 to ensure we swap our exact input amount. ISwapRouter.ExactInputSingleParams memory params = ISwapRouter .ExactInputSingleParams({ tokenIn: tokenIn, tokenOut: tokenOut, fee: poolFee, recipient: outAddr, deadline: block.timestamp, amountIn: swapAmount, amountOutMinimum: _getAmountOutMinimum(swapAmount), sqrtPriceLimitX96: 0 }); return swapRouter.exactInputSingle(params); } function getSwapAmount(uint amountIn, uint contractBalance) private view returns (uint swapAmount) { if (amountIn > USDTLimitPerSwap) { swapAmount = USDTLimitPerSwap; } else if (amountIn + contractBalance > USDTLimitPerSwap) { swapAmount = USDTLimitPerSwap; } else { swapAmount = amountIn + contractBalance; } return swapAmount; } function _getAmountOutMinimum(uint amountIn) private returns (uint amountOutMin) { IOracle oracle = IOracle(A_OracleProxy); uint dydxPrice = oracle.getPrice("DYDX", "USDX", dydxUsdxPriceType); // dydxAmount * dydxPrice = usdxAmount * usdxPrice -> dydxAmount = usdxAmount/dydxPrice amountOutMin = amountIn * swapAmtOutMinRate / 100 / dydxPrice; } function getAllowedMaxRatio() public view returns (uint ratio) { IInvitation inviteContract = IInvitation(A_Invitation); IInviteReward inviteRewardContract = IInviteReward(A_InvitReward); address[] memory children = inviteContract.inviteesOf(msg.sender); uint childrenTotalAmount; for (uint i = 0; i < children.length; i++) { childrenTotalAmount += inviteRewardContract.getLeverageDepositAmt(children[i]); } return _calculateMaxLeverageRatio(childrenTotalAmount, ratioPerAmount, systemRatioLimit); } function _calculateMaxLeverageRatio( uint _childrenTotalAmount, uint _ratioPerAmount, uint16 _systemRatioLimit ) private pure returns (uint) { uint maxRatio = _childrenTotalAmount / _ratioPerAmount; maxRatio = (maxRatio == 0) ? 1 : maxRatio; return (maxRatio > _systemRatioLimit) ? _systemRatioLimit : maxRatio; } function _getShortAmt(address token, uint amount) private pure returns (uint) { return amount / ((token == Const.A_USDT) ? Const.MULTIPLIER_6 : Const.MULTIPLIER_18); } /** * @param token USDT or USDX */ function _symbol(address token) private pure returns(string memory){ return (token == Const.A_USDT) ? "USDT" : "USDX"; } /** * @param token USDT or USDX */ function _decimals(address token) private pure returns(uint){ return (token == Const.A_USDT) ? Const.MULTIPLIER_6 : Const.MULTIPLIER_18; } /** * 'ShortAmt' in the function name refers to the amount without decimals * Considered rewards amount and system amount limit */ function getAllowedLeverageShortAmt(address addr) public returns (uint) { // the user has used all the leverage amount // if(user[msg.sender].usedLeverageAmt >= sysLeverageShortAmtLimit) return 0; IInviteReward inviteRewardContract = IInviteReward(A_InvitReward); uint leverageAmt = inviteRewardContract.getLeverageAmt(addr); IOracle oracle = IOracle(A_OracleProxy); uint t100xPrice = oracle.getPrice("T100X", "USDT", t100xUsdtPriceType); uint rewardAllowedUSDTShortAmt = leverageAmt * t100xPrice / Const.MULTIPLIER_6; uint allowedAmt = (rewardAllowedUSDTShortAmt > sysLeverageShortAmtLimit) ? sysLeverageShortAmtLimit : rewardAllowedUSDTShortAmt; return allowedAmt; } function setLeverage100xtFeeRate(uint rate) external onlyRole(DEFAULT_ADMIN_ROLE) { leverage100xtFeeRate = rate; } function setSystemAddress(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_System = addr; } function setBankVaultAddr(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_BankVault = addr; } function setInvitationAddr(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_Invitation = addr; } function setSwapAmtOutMinRate(uint _val) external onlyRole(OPERATOR) { require(_val <= 100, "Value must be less than 100"); require(_val >= 50, "Value must be greater than 50"); swapAmtOutMinRate = _val; } //TODO set functions for other variables function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { _pause(); } function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; pragma abicoder v2; import "./LeverageBase.sol"; import "./Const.sol"; // todo: admin to set ratio and leverage amount for particular account! // need to set system address during/after deployment contract Leverage is LeverageBase { constructor( address initialOwner, address initialAdmin, ISwapRouter swapRouter, address a_usdx, address a_t100xt, address a_savings, address a_invitation, address a_invite_reward, address a_oracle_proxy ) LeverageBase(initialOwner, initialAdmin, swapRouter, a_usdx, a_t100xt, a_savings, a_invitation, a_invite_reward, a_oracle_proxy) {} }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import "./IOracle.sol"; // import "hardhat/console.sol"; import "./Const.sol"; // todo: admin to set ratio and leverage amount for particular account! interface ISavings { function transfer2Leverage(address tokenAddress, uint amount) external; } interface IBankVaultL { function transferDYDX2Leverage(address tokenAddress, uint amount) external; } interface IInviteReward { function getLeverageDepositAmt(address addr) external view returns (uint); function claimed(address addr) external view returns (uint); function getLeverageAmt(address addr) external view returns (uint); } interface IInvitation { function inviterOf(address _account) external view returns (address); function rootInviterOf(address _account) external view returns (address); function inviteesOf(address _account) external view returns (address[] memory); } // need to set system address during/after deployment abstract contract LeverageBase is Ownable, Pausable, AccessControlEnumerable { using SafeERC20 for IERC20; bytes32 private constant OPERATOR = keccak256("OPERATOR"); ISwapRouter private immutable swapRouter; address private A_USDX; address private A_100XT; address private A_Savings; address private A_Invitation; address private A_InvitReward; address private A_BankVault; address private A_OracleProxy; // system address to receive earnings if there are no inviters address public A_System; // if leverage ratio=2, user pay 2*10=20 100xt uint public leverage100xtFeeRate = 10 * Const.MULTIPLIER_18; uint public leverageFeeRate = 1000; // leverage fee = 0.1%. uint16 public poolFee = 3000; // 0.3% // ratio increment 1, per 20,000 USD uint public ratioPerAmount = 20000 * Const.MULTIPLIER_18; uint16 public systemRatioLimit = 100; uint public sysLeverageShortAmtLimit = 10000; uint private swapAmtOutMinRate = 80; //80% uint public USDTLimitPerSwap = 50000 * Const.MULTIPLIER_6; // balances' key will be USDT or USDX to distinguish different type of trade struct User { mapping(string => uint) dydxbalances; mapping(string => uint) borrowedbalances; mapping(string => uint) principalAmt;//new // mapping(string => uint) withdrawalAmt;//new uint usedLeverageShortAmt; // 10,000 for USDX + USDT } mapping(address => User) public user; uint public sysProfitRate = 5; uint public inviterProfitRate = 5; uint public rootInviterProfitRate =10; uint private t100xUsdtPriceType = 1; uint private dydxUsdxPriceType = 1; uint private dydxUsdtPriceType = 1; constructor( address initialOwner, address initialAdmin, ISwapRouter _swapRouter, address _a_usdx, address _a_t100xt, address _a_savings, address _a_invitation, address _a_invite_reward, address _a_oracle_proxy ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); swapRouter = _swapRouter; require(_a_usdx != address(0), "Invalid address provided"); require(_a_t100xt != address(0), "Invalid address provided"); require(_a_savings != address(0), "Invalid address provided"); require(_a_invitation != address(0), "Invalid address provided"); require(_a_invite_reward != address(0), "Invalid address provided"); require(_a_oracle_proxy != address(0), "Invalid address provided"); A_USDX = _a_usdx; A_100XT = _a_t100xt; A_Savings = _a_savings; A_Invitation = _a_invitation; A_InvitReward = _a_invite_reward; A_OracleProxy = _a_oracle_proxy; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } //usdx or usdt function useLeverage(address tokenAddr, uint amountIn, uint16 ratio) external whenNotPaused returns (uint amountOut) { require(tokenAddr == Const.A_USDT || tokenAddr == A_USDX, "Token must be USDX or USDT"); // check max ratio uint allowedMaxRatio = getAllowedMaxRatio(); require(ratio <= allowedMaxRatio, string(abi.encodePacked("Exeed max ratio: ", Strings.toString(allowedMaxRatio)))); // check max leverage amount, make sure the amount does not exceed limit even if the user has multiple leverages uint shortAmtIn = _getShortAmt(tokenAddr, amountIn); uint allowedShortAmt = getAllowedLeverageShortAmt(msg.sender); uint usedShortAmt = user[msg.sender].usedLeverageShortAmt; require(allowedShortAmt > usedShortAmt, string(abi.encodePacked("Leverage short amount used: ", Strings.toString(usedShortAmt)))); uint currentAllowedShortAmt = allowedShortAmt - usedShortAmt; require(shortAmtIn <= currentAllowedShortAmt, string(abi.encodePacked("Exceed current allowed leverage short amount: ", Strings.toString(currentAllowedShortAmt)))); // msg.sender must approve this contract!!! R: Should be done on the web3 side! // pay principal: Transfer the specified amount of token(usdx/usdt) to this contract. TransferHelper.safeTransferFrom(tokenAddr, msg.sender, address(this), amountIn); // pay 100x IERC20 t100x = IERC20(A_100XT); // frontend to call approve t100x.safeTransferFrom(msg.sender, address(this), ratio * leverage100xtFeeRate); user[msg.sender].usedLeverageShortAmt += amountIn / _decimals(tokenAddr); user[msg.sender].principalAmt[_symbol(tokenAddr)] += amountIn; user[msg.sender].borrowedbalances[_symbol(tokenAddr)] += amountIn * ratio; // borrow money from savings // TODO consider UX when not enough money to borrow ISavings savingsContract = ISavings(A_Savings); savingsContract.transfer2Leverage(tokenAddr, amountIn * ratio); // calculate fees uint totalAmount = amountIn * (ratio + 1); uint swapAmount = _distributeFees(tokenAddr, totalAmount); // swap // TODO: consider big swap strategy! amountOut = _swap(tokenAddr, Const.A_DYDX, swapAmount, A_BankVault); user[msg.sender].dydxbalances[_symbol(tokenAddr)] += amountOut; } /** * @param tokenAddr indicate selling for USDX OR USDT */ function sell(uint dydxAmountIn, address tokenAddr) external whenNotPaused returns (uint amountOut) { require(user[msg.sender].dydxbalances[_symbol(tokenAddr)] >= dydxAmountIn, "Not enough dydx amount in user's account"); require(ifAllowSelling(tokenAddr, msg.sender), "Selling is blocked due to shrinked asset"); IERC20 token = IERC20(tokenAddr); // transfer dydx from VaultL to this contract IBankVaultL bankVault = IBankVaultL(A_BankVault); bankVault.transferDYDX2Leverage(Const.A_DYDX, dydxAmountIn); amountOut = _swap(Const.A_DYDX, tokenAddr, dydxAmountIn, address(this)); user[msg.sender].dydxbalances[_symbol(tokenAddr)] -= dydxAmountIn; // calculate fees amountOut = _distributeFees(tokenAddr, amountOut); // return borrowed money uint borrowedAmt = user[msg.sender].borrowedbalances[_symbol(tokenAddr)]; if(borrowedAmt > 0){ uint returnAmt = (borrowedAmt > amountOut) ? amountOut : borrowedAmt; user[msg.sender].borrowedbalances[_symbol(tokenAddr)] -= returnAmt; amountOut -= returnAmt; token.safeTransfer(A_Savings, returnAmt); } // calculate profit if(amountOut > 0){ // return principal uint principalAmt = user[msg.sender].principalAmt[_symbol(tokenAddr)]; // pay back principal first if(principalAmt > 0 && principalAmt >= amountOut){ user[msg.sender].principalAmt[_symbol(tokenAddr)] -= amountOut; token.safeTransfer(msg.sender, amountOut); // pay back all the principal }else if(principalAmt > 0 && principalAmt < amountOut){ amountOut -= principalAmt; user[msg.sender].principalAmt[_symbol(tokenAddr)] = 0; amountOut = _distributeProfit(token, amountOut); token.safeTransfer(msg.sender, principalAmt + amountOut); }else{ // the account has earned back all the principal amount already amountOut = _distributeProfit(token, amountOut); token.safeTransfer(msg.sender, amountOut); } } // return 100xt } /** * @param tokenAddr USDX address or USDT address * @param addr caller's address * return true if user's dydx'value is greater than the borrowed coins */ function ifAllowSelling(address tokenAddr, address addr) public returns (bool) { IOracle oracle = IOracle(A_OracleProxy); string memory symbol = _symbol(tokenAddr); uint priceType = (keccak256(abi.encodePacked(symbol)) == keccak256(abi.encodePacked("USDX"))) ? dydxUsdxPriceType : dydxUsdtPriceType; uint dydxPrice = oracle.getPrice("DYDX", symbol, priceType); return user[addr].dydxbalances[symbol] * dydxPrice > user[addr].borrowedbalances[_symbol(tokenAddr)]; } function _distributeProfit(IERC20 token, uint amount) private returns (uint pay2user) { uint pay2sysAmt = amount * sysProfitRate / 100; uint pay2inviterAmt = amount * inviterProfitRate / 100; uint pay2rootInviterAmt = amount * rootInviterProfitRate / 100; IInvitation inviteContract = IInvitation(A_Invitation); token.safeTransfer(inviteContract.inviterOf(msg.sender), pay2inviterAmt); address rootInviterAddr = inviteContract.rootInviterOf(msg.sender); if(rootInviterAddr != address(0)){ token.safeTransfer(rootInviterAddr, pay2rootInviterAmt); token.safeTransfer(A_System, pay2sysAmt); }else{ // if root address does not exist, use system address instead! token.safeTransfer(A_System, pay2rootInviterAmt + pay2sysAmt); } pay2user = amount - pay2sysAmt - pay2inviterAmt - pay2rootInviterAmt; } function _distributeFees(address tokenAddr, uint amount) private returns (uint) { uint leverageFee = amount * leverageFeeRate / 1000000; uint pay2inviterAmt = leverageFee / 2; uint pay2rootInviterAmt = leverageFee - pay2inviterAmt; IERC20 token = IERC20(tokenAddr); IInvitation inviteContract = IInvitation(A_Invitation); token.safeTransfer(inviteContract.inviterOf(msg.sender), pay2inviterAmt); address rootInviterAddr = inviteContract.rootInviterOf(msg.sender); // check: if root address does not exist, use system address instead! token.safeTransfer((rootInviterAddr==address(0)) ? A_System : rootInviterAddr, pay2rootInviterAmt); return amount - leverageFee; } // The calling address must approve this contract to spend at least `amountIn` worth of its USDT for this function to succeed. function _swap(address tokenIn, address tokenOut, uint amountIn, address outAddr) private returns (uint amountOut) { // Approve the router to spend USDT TransferHelper.safeApprove(tokenIn, address(swapRouter), amountIn); // only swap max 50K USDT a time. Leftover will be swapped next time along with others' funds uint swapAmount = amountIn; // uint swapAmount = getSwapAmount(amountIn, address(this).balance); // Naively set amountOutMinimum to 0. In production, use an oracle or other data source to choose a safer value for amountOutMinimum. // We also set the sqrtPriceLimitx96 to be 0 to ensure we swap our exact input amount. ISwapRouter.ExactInputSingleParams memory params = ISwapRouter .ExactInputSingleParams({ tokenIn: tokenIn, tokenOut: tokenOut, fee: poolFee, recipient: outAddr, deadline: block.timestamp, amountIn: swapAmount, amountOutMinimum: _getAmountOutMinimum(swapAmount), sqrtPriceLimitX96: 0 }); return swapRouter.exactInputSingle(params); } function getSwapAmount(uint amountIn, uint contractBalance) private view returns (uint swapAmount) { if (amountIn > USDTLimitPerSwap) { swapAmount = USDTLimitPerSwap; } else if (amountIn + contractBalance > USDTLimitPerSwap) { swapAmount = USDTLimitPerSwap; } else { swapAmount = amountIn + contractBalance; } return swapAmount; } function _getAmountOutMinimum(uint amountIn) private returns (uint amountOutMin) { IOracle oracle = IOracle(A_OracleProxy); uint dydxPrice = oracle.getPrice("DYDX", "USDX", dydxUsdxPriceType); // dydxAmount * dydxPrice = usdxAmount * usdxPrice -> dydxAmount = usdxAmount/dydxPrice amountOutMin = amountIn * swapAmtOutMinRate / 100 / dydxPrice; } function getAllowedMaxRatio() public view returns (uint ratio) { IInvitation inviteContract = IInvitation(A_Invitation); IInviteReward inviteRewardContract = IInviteReward(A_InvitReward); address[] memory children = inviteContract.inviteesOf(msg.sender); uint childrenTotalAmount; for (uint i = 0; i < children.length; i++) { childrenTotalAmount += inviteRewardContract.getLeverageDepositAmt(children[i]); } return _calculateMaxLeverageRatio(childrenTotalAmount, ratioPerAmount, systemRatioLimit); } function _calculateMaxLeverageRatio( uint _childrenTotalAmount, uint _ratioPerAmount, uint16 _systemRatioLimit ) private pure returns (uint) { uint maxRatio = _childrenTotalAmount / _ratioPerAmount; maxRatio = (maxRatio == 0) ? 1 : maxRatio; return (maxRatio > _systemRatioLimit) ? _systemRatioLimit : maxRatio; } function _getShortAmt(address token, uint amount) private pure returns (uint) { return amount / ((token == Const.A_USDT) ? Const.MULTIPLIER_6 : Const.MULTIPLIER_18); } /** * @param token USDT or USDX */ function _symbol(address token) private pure returns(string memory){ return (token == Const.A_USDT) ? "USDT" : "USDX"; } /** * @param token USDT or USDX */ function _decimals(address token) private pure returns(uint){ return (token == Const.A_USDT) ? Const.MULTIPLIER_6 : Const.MULTIPLIER_18; } /** * 'ShortAmt' in the function name refers to the amount without decimals * Considered rewards amount and system amount limit */ function getAllowedLeverageShortAmt(address addr) public returns (uint) { // the user has used all the leverage amount // if(user[msg.sender].usedLeverageAmt >= sysLeverageShortAmtLimit) return 0; IInviteReward inviteRewardContract = IInviteReward(A_InvitReward); uint leverageAmt = inviteRewardContract.getLeverageAmt(addr); IOracle oracle = IOracle(A_OracleProxy); uint t100xPrice = oracle.getPrice("T100X", "USDT", t100xUsdtPriceType); uint rewardAllowedUSDTShortAmt = leverageAmt * t100xPrice / Const.MULTIPLIER_6; uint allowedAmt = (rewardAllowedUSDTShortAmt > sysLeverageShortAmtLimit) ? sysLeverageShortAmtLimit : rewardAllowedUSDTShortAmt; return allowedAmt; } function setLeverage100xtFeeRate(uint rate) external onlyRole(OPERATOR) { leverage100xtFeeRate = rate; } function setSystemAddress(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_System = addr; } function setBankVaultAddr(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_BankVault = addr; } function setInvitationAddr(address addr) external onlyRole(OPERATOR) { require(addr != address(0), "Invalid address provided"); A_Invitation = addr; } function setSwapAmtOutMinRate(uint _val) external onlyRole(OPERATOR) { require(_val <= 100, "Value must be less than 100"); require(_val >= 50, "Value must be greater than 50"); swapAmtOutMinRate = _val; } //TODO set functions for other variables function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { _pause(); } function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@uniswap/v3-periphery/contracts/interfaces/IQuoter.sol"; import "./Const.sol"; import "./IOracle.sol"; contract OracleProxy is Ownable, AccessControlEnumerable, IOracle { bytes32 public constant OPERATOR = keccak256("OPERATOR"); mapping(string => address) public tokenAddressMap; mapping(string => uint) public tokenDecimalMap; address[] private oracleContracts; event SetPrice(string key, uint price); constructor( address initialOwner, address initialAdmin ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function getPrice(string calldata tokenInSymbol, string calldata tokenOutSymbol, uint oracleType) public override returns (uint){ IOracle oracle = IOracle(oracleContracts[oracleType - 1]); return oracle.getPrice(tokenInSymbol, tokenOutSymbol, oracleType); } /** * Manual operation: set oracle contracts' addresses after deploying an oracle contract * address array sequence is important: V1, V2 ... */ function setOracleContracts(address[] calldata addr) external onlyRole(OPERATOR) { oracleContracts = addr; } /** * Manual operation: key: "USDT", value: 0x...... */ function setTokenAddressMap(string calldata symbol, address addr) external onlyRole(OPERATOR){ tokenAddressMap[symbol] = addr; } /** * Manual operation: key: "USDT", value: 6 */ function setTokenDecimalMap(string calldata symbol, uint decimals) external onlyRole(OPERATOR){ tokenDecimalMap[symbol] = decimals; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "./IOracle.sol"; contract OracleV1 is Ownable, AccessControlEnumerable, IOracle { bytes32 public constant OPERATOR = keccak256("OPERATOR"); mapping(string => uint) public priceMap; address A_oracleProxy; event SetPrice(string key, uint price); constructor( address initialOwner, address initialAdmin, address a_oracleProxy ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); A_oracleProxy = a_oracleProxy; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function getPrice(string calldata tokenInSymbol, string calldata tokenOutSymbol, uint oracleType) public view override returns (uint){ require(oracleType == 1, "oracle type is invalid"); string memory key = string.concat(tokenInSymbol, "-", tokenOutSymbol); return priceMap[key]; } // augment tokenInSymbol=DYDX, tokenOutSymbol=100XT, price=2,05*(10**100XT.decimals()) means (1 DYDX)=(2.05 100XT) function setPrice(string calldata tokenInSymbol, string calldata tokenOutSymbol, uint price) external onlyRole(OPERATOR){ require(price > 0, "price must be greater than 0"); string memory key = string.concat(tokenInSymbol, "-", tokenOutSymbol); priceMap[key] = price; emit SetPrice(key, price); } function deletePrice(string calldata tokenInSymbol, string calldata tokenOutSymbol) external onlyRole(OPERATOR){ string memory key = string.concat(tokenInSymbol, "-", tokenOutSymbol); priceMap[key] = 0; emit SetPrice(key, 0); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@uniswap/v3-periphery/contracts/interfaces/IQuoter.sol"; import "./Const.sol"; import "./IOracle.sol"; // import "hardhat/console.sol"; interface IOracleProxy { function tokenAddressMap(string calldata symbol) external view returns (address); function tokenDecimalMap(string calldata symbol) external view returns (uint); } contract OracleV2 is Ownable, AccessControlEnumerable, IOracle { bytes32 public constant OPERATOR = keccak256("OPERATOR"); address A_oracleProxy; constructor( address initialOwner, address initialAdmin, address a_oracleProxy ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); A_oracleProxy = a_oracleProxy; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function getPrice(string calldata tokenInSymbol, string calldata tokenOutSymbol, uint oracleType) public override returns (uint){ require(oracleType == 2, "oracle type is invalid"); IOracleProxy oP = IOracleProxy(A_oracleProxy); uint ou = getPriceForTokenIn(oP.tokenAddressMap(tokenInSymbol), oP.tokenAddressMap(tokenOutSymbol), 10**oP.tokenDecimalMap(tokenInSymbol)); return ou; } function getPriceForTokenIn( address tokenIn, address tokenOut, uint amountIn ) private returns (uint256) { uint24 fee = 3000; IQuoter uniQuoter = IQuoter(Const.A_UNI_QUOTER); uint amountOut = uniQuoter.quoteExactInputSingle( tokenIn, tokenOut, fee, amountIn, 0 ); return amountOut; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "hardhat/console.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; // stake usdx, reward 100xt contract Savings is Ownable, Pausable, AccessControlEnumerable { bytes32 public constant OPERATOR = keccak256("OPERATOR"); using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; uint public totalStaked = 0; address public A_leverage; // contracts which return 100xt as rewards EnumerableSet.AddressSet private sStakingContractsSet; event Lend(address addr, uint amount); event Withdraw(IERC20 token, address addr, uint amount); constructor( address initialOwner, address initialAdmin ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } // usdx or usdt function transfer2Leverage(address tokenAddress, uint amount) external { // only allow leverage contract to call require(msg.sender == A_leverage, "Unauthorized"); IERC20 token = IERC20(tokenAddress); token.safeTransfer(A_leverage, amount); emit Lend(tokenAddress, amount); } // usdx, for staking contracts to withdraw/unstake function withdraw(IERC20 token, address to, uint amount) external { //only allow several contracts to call! require(sStakingContains(msg.sender), "Unauthorized"); token.safeTransfer(to, amount); emit Withdraw(token, to, amount); } function addSStakingContract(address addr) public returns (bool) { return EnumerableSet.add(sStakingContractsSet, addr); } function removeSStakingContract(address addr) public returns (bool) { return EnumerableSet.remove(sStakingContractsSet, addr); } function sStakingContains(address addr) private view returns (bool) { return EnumerableSet.contains(sStakingContractsSet, addr); } function listAllSStakingContracts() external view returns (address[] memory) { uint256 length = sStakingContractsSet.length(); address[] memory addresses = new address[](length); for (uint256 i = 0; i < length; ++i) { addresses[i] = sStakingContractsSet.at(i); } return addresses; } function setLeverageAddress(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_leverage = addr; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; // import "hardhat/console.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "./IStaking.sol"; interface ISavings { function withdraw(IERC20 _token, address _to, uint _amount) external; } /** * SStakingBase is short for SavingsStakingBase */ abstract contract SStakingBase is IStaking, Ownable, Pausable, AccessControlEnumerable { bytes32 constant OPERATOR = keccak256("OPERATOR"); // allows you to call the safe methods provided by SafeERC20 on any token that is an instance of IERC20 using SafeERC20 for IERC20; IERC20 immutable token; IERC20 immutable rewardToken; address A_Savings; uint public totalStaked = 0; mapping(address => uint) public balanceOf; // track the block number when an account interacts with the contract mapping(address => uint) internal lastUpdatedBlockNO; mapping(address => uint) public claimed; event Stake(address address_, uint amount); event Claim(address address_, uint amount); event Unstake(address address_, uint amount); constructor(address initialOwner, address initialAdmin, IERC20 token_, IERC20 rewardToken_) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); token = token_; rewardToken = rewardToken_; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } function stake(uint amount) public virtual whenNotPaused { require(A_Savings != address(0), "Invalid savings address provided"); claim(); balanceOf[msg.sender] += amount; lastUpdatedBlockNO[msg.sender] = block.number; totalStaked += amount; token.safeTransferFrom(msg.sender, A_Savings, amount); emit Stake(msg.sender, amount); } function rewards(address addr, uint startBlockNO) public view virtual returns (uint); function claim() internal virtual whenNotPaused { uint amount = rewards(msg.sender, 0); rewardToken.safeTransfer(msg.sender, amount); claimed[msg.sender] += amount; lastUpdatedBlockNO[msg.sender] = block.number; emit Claim(msg.sender, amount); } function unstake(uint amount) external whenNotPaused { require(amount > 0, "The amount to withdraw must be greater than zero"); require(balanceOf[msg.sender] >= amount, "Insufficient funds for the account"); require(token.balanceOf(A_Savings) >= amount, "Insufficient funds of Savings contract"); balanceOf[msg.sender] -= amount; totalStaked -= amount; claim(); ISavings savingsContract = ISavings(A_Savings); savingsContract.withdraw(token, msg.sender, amount); // token.safeTransfer(msg.sender, amount); emit Unstake(msg.sender, amount); } function setSavingsAddress(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_Savings = addr; } function getMyClaimed(address addr) public view returns (uint){ return claimed[addr]; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; // import "hardhat/console.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./SStakingBase.sol"; import "./Const.sol"; // stake usdx, reward 100xt contract SStakingStepAPR is SStakingBase { // allows you to call the safe methods provided by SafeERC20 on any token that is an instance of IERC20 using SafeERC20 for IERC20; // amount of rewardToken per block per 10*decimals() token uint public rewardsRate1 = 1; uint public rewardsRate2 = 1; uint public rewardsRate3 = 1; uint public rewardsRate4 = 1; uint public rewardsRate5 = 1; uint public rewardsRate6 = 1; uint public rewardsRate7 = 1; uint public rewardsRate8 = 1; uint public rewardsRate9 = 1; uint public rewardsRate10 = 1; uint public rewardsRate11 = 1; constructor( address initialOwner, address initialAdmin, IERC20 token, IERC20 rewardToken ) SStakingBase(initialOwner, initialAdmin, token, rewardToken) {} function rewards(address addr, uint _startBlockNO) public view override returns (uint) { uint rewardCalculationStartBlockNO = (_startBlockNO==0) ? lastUpdatedBlockNO[addr] : _startBlockNO; uint balance = balanceOf[addr]; return balance * getRewardRate(balance) * (block.number - rewardCalculationStartBlockNO); } function getRewardRate(uint amount) private view returns (uint) { uint rate; uint coins = amount / Const.MULTIPLIER_18; if(coins > 0 && coins < 1000){ rate = rewardsRate1; } else if(coins >= 1000 && coins < 3000){ rate = rewardsRate2; } else if(coins >= 3000 && coins < 5000){ rate = rewardsRate3; } else if(coins >= 5000 && coins < 7000){ rate = rewardsRate4; } else if(coins >= 7000 && coins < 9000){ rate = rewardsRate5; } else if(coins >= 9000 && coins < 11000){ rate = rewardsRate6; } else if(coins >= 11000 && coins < 13000){ rate = rewardsRate7; } else if(coins >= 13000 && coins < 15000){ rate = rewardsRate8; } else if(coins >= 15000 && coins < 17000){ rate = rewardsRate9; } else if(coins >= 17000 && coins < 20000){ rate = rewardsRate10; } else if(coins >= 20000 ){ rate = rewardsRate11; } return rate; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "./IStaking.sol"; // TODO what if no enough tokens for users to withdraw // TODO admin to set some parameters contract Staking100XT is IStaking, Ownable, Pausable, AccessControlEnumerable { bytes32 public constant OPERATOR = keccak256("OPERATOR"); // todo: get rid of struct and get rid of getMyClaimed function struct User{ uint balance; // keep track of when an account interacts with the contract uint lastUpdated; uint claimed; uint lastWithdrawed; } mapping(address => uint) public balanceOf; // using SafeERC20 for IERC20; IERC20 public immutable token; uint public baseRewardRate = 3000; // 30% annual return // auto increment 100(1%) per month. So annual return would be 30+12=42% after a year uint public extraRewardRateInterval = 100; uint public extraRewardRateLimit = 3000; // max extra reward is up to 30% annual return uint public constant secondsInAYear = 365 days; uint public constant secondsInAMonth = 30 days; uint public totalStaked = 0; mapping(address => User) public user; event Deposit(address addr_, uint amount_); event Claim(address addr_, uint amount_); event Compound(address addr_, uint amount_); event Withdraw(address addr_, uint amount_); constructor( address initialOwner, address initialAdmin, IERC20 token_ ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); token = token_; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if(getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0){ address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require(currentAdmin != addr, "New admin address is the same as the current one"); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } // In order to make sure we return the same value whether the total rewards are needed // internally or externally in the contract, we put the calculation into an internal function. // The external function then simply calls the internal one, removing the opportunity for a discrepancy. function totalRewards() external view returns (uint) { return _totalRewards(); } // track the number of reward tokens available = total tokens in the contract, minus the total tokens staked. function _totalRewards() internal view returns (uint) { return token.balanceOf(address(this)) - totalStaked; } function deposit(uint amount_) external whenNotPaused { _compound(); // need approval in advance require(token.transferFrom(msg.sender, address(this), amount_), "Transfer failed"); user[msg.sender].balance += amount_; user[msg.sender].lastUpdated = block.timestamp; if(user[msg.sender].lastWithdrawed == 0 ){ // set as the first deposit time user[msg.sender].lastWithdrawed = block.timestamp; } totalStaked += amount_; emit Deposit(msg.sender, amount_); } function rewards(address addr_, uint _startTime) external view returns (uint) { return _rewards(addr_, _startTime); } function _rewards(address addr_, uint _startTime) internal view returns (uint) { uint rewardCalculationStartTime = (_startTime==0) ? user[addr_].lastUpdated : _startTime; uint rewardRate = baseRewardRate + _getExtraRewardRate(user[addr_].lastWithdrawed); return user[addr_].balance * rewardRate * (block.timestamp - rewardCalculationStartTime) / 10000 / secondsInAYear; } function claim() external whenNotPaused { uint amount = _rewards(msg.sender, 0); require(token.transfer(msg.sender, amount), "Transfer failed"); user[msg.sender].claimed += amount; user[msg.sender].lastUpdated = block.timestamp; // TODO do this or not? // user[msg.sender].lastWithdrawed = block.timestamp; emit Claim(msg.sender, amount); } function compound() external { _compound(); } function _compound() internal { uint amount = _rewards(msg.sender, 0); // No transfer function called user[msg.sender].claimed += amount; user[msg.sender].balance += amount; totalStaked += amount; user[msg.sender].lastUpdated = block.timestamp; emit Compound(msg.sender, amount); } function withdraw(uint amount_) external whenNotPaused { require(amount_ > 0, "The amount to withdraw must be greater than zero"); require(user[msg.sender].balance >= amount_, "Insufficient funds"); _compound(); require(token.transfer(msg.sender, amount_), "Transfer failed"); user[msg.sender].balance -= amount_; user[msg.sender].lastWithdrawed = block.timestamp; totalStaked -= amount_; emit Withdraw(msg.sender, amount_); } function _getExtraRewardRate(uint lastWithdrawed_) private view returns (uint) { uint extraRate = (block.timestamp - lastWithdrawed_) * extraRewardRateInterval / secondsInAMonth; return (extraRate > extraRewardRateLimit) ? extraRewardRateLimit : extraRate; } function getMyClaimed(address addr) public view returns (uint) { return user[addr].claimed; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; contract T100X is ERC20Capped, ERC20Burnable, ERC20Pausable, Ownable, AccessControlEnumerable { bytes32 public constant OPERATOR = keccak256("OPERATOR"); constructor( address initialOwner, address initialAdmin, uint256 initialCap )Ownable(initialOwner) ERC20("100XToken", "100XT") ERC20Capped(initialCap * (10 ** decimals())) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); } function _update(address from, address to, uint256 value) internal override (ERC20Capped, ERC20, ERC20Pausable){ super._update(from, to, value); if(from == address(0)){ uint256 maxSupply = cap(); uint256 supply = totalSupply(); if(supply > maxSupply){ revert ERC20ExceededCap(supply, maxSupply); } } } function mint(address to, uint256 amount) public onlyRole(OPERATOR) { _mint(to, amount); } function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { _pause(); } function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.24; pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import "@uniswap/v3-periphery/contracts/interfaces/IQuoter.sol"; import "./Const.sol"; import "./IOracle.sol"; import "hardhat/console.sol"; contract X is Ownable, Pausable, AccessControlEnumerable { using SafeERC20 for IERC20; bytes32 public constant OPERATOR = keccak256("OPERATOR"); ISwapRouter public immutable swapRouter; address private A_USDX; address private A_100XT; address private A_BankVault; address private A_OracleProxy; // set the pool fee to 0.3%. uint16 private poolFee = 3000; uint depositMinAmt = 10 * Const.MULTIPLIER_6; // the portion of deposited usdt to swap dydx uint private swapRate = 100; //100% uint private usdtSwapLimit = 50000 * Const.MULTIPLIER_6; // remaining USDT amount waiting for swaping uint private swapRemainingAmt; uint private swapAmtOutMinRate = 80; //80% uint private payDuration100xt = 365 * 2; // 2 years, hard coded // the system issues max 3000 100xt per day uint private sysAmt100xtPerDay = 3000 * Const.MULTIPLIER_18; uint public issuedUSDXAmt; uint[] private recalculateArr; uint private dydxUsdtPriceType = 1; uint private t100xUsdtPriceType = 1; // for paying 100xt // TODO unit test init value=0 for these attributes struct User { uint t100xAmt; uint claimingAmtPerHour; uint startTime; uint lastUpdated; uint claimed; uint recalculateNO; } mapping(address => User) public user; uint userInQueueFor100xt; error MinDeposit(uint depositAmt, uint minAmt); event Price(uint indexed price); constructor( address initialOwner, address initialAdmin, ISwapRouter _swapRouter, address _a_usdx, address _a_100xt, address _a_oracle ) Ownable(initialOwner) { _grantRole(DEFAULT_ADMIN_ROLE, initialAdmin); _grantRole(OPERATOR, initialOwner); _grantRole(OPERATOR, initialAdmin); swapRouter = _swapRouter; require(_a_usdx != address(0), "Invalid USDX address"); require(_a_100xt != address(0), "Invalid 100XT address"); A_USDX = _a_usdx; A_100XT = _a_100xt; A_OracleProxy = _a_oracle; } // if this does not work, then use grantDefaultAdmin function setDefaultAdmin(address addr) external onlyOwner { if (getRoleMemberCount(DEFAULT_ADMIN_ROLE) > 0) { address currentAdmin = getRoleMember(DEFAULT_ADMIN_ROLE, 0); require( currentAdmin != addr, "New admin address is the same as the current one" ); _revokeRole(DEFAULT_ADMIN_ROLE, currentAdmin); } _grantRole(DEFAULT_ADMIN_ROLE, addr); } // only use when setDefaultAdmin does not work function grantDefaultAdmin(address addr) external onlyOwner { _grantRole(DEFAULT_ADMIN_ROLE, addr); } /** * swap a fixed amount of USDT for a maximum possible amount of DYDX; using the USDT/DYDX 0.3% pool * The calling address must approve this contract to spend at least `amountIn` worth of its USDT for this function to succeed */ function depositUSDT(uint amountIn) external whenNotPaused returns (uint amountOut) { if(amountIn < depositMinAmt) revert MinDeposit(amountIn, depositMinAmt); // Transfer the specified amount of USDT to this contract TransferHelper.safeTransferFrom(Const.A_USDT, msg.sender, address(this), amountIn); // Transfer USDX to the user IERC20 usdx = IERC20(A_USDX); uint usdxAmount = (amountIn / Const.MULTIPLIER_6) * Const.MULTIPLIER_18; usdx.safeTransfer(msg.sender, usdxAmount); issuedUSDXAmt += usdxAmount; if (swapRate == 0) return 0; uint newAmountIn = amountIn * swapRate / 100; //only swap max 50K USDT a time. Remaining will be swapped next time along with others' funds uint swapAmount = _getSwapAmount(newAmountIn, swapRemainingAmt); // this is to prevent from swapRemainingAmt being negative if (swapRemainingAmt < swapAmount - newAmountIn) { swapRemainingAmt = 0; } else { swapRemainingAmt += newAmountIn - swapAmount; } // Approve the router to spend USDT. TransferHelper.safeApprove(Const.A_USDT, address(swapRouter), swapAmount); // Naively set amountOutMinimum to 0. In production, use an oracle or other data source to choose a safer value for amountOutMinimum. // We also set the sqrtPriceLimitx96 to be 0 to ensure we swap our exact input amount. ISwapRouter.ExactInputSingleParams memory params = ISwapRouter .ExactInputSingleParams({ tokenIn: Const.A_USDT, tokenOut: Const.A_DYDX, fee: poolFee, recipient: A_BankVault, deadline: block.timestamp, amountIn: swapAmount, amountOutMinimum: _getAmountOutMinimum(swapAmount), sqrtPriceLimitX96: 0 }); return swapRouter.exactInputSingle(params); } /** * @param amount the amount for swaping, after swapRate * @param remainingAmount the amount remained in the contract, waiting for swaping */ function _getSwapAmount(uint amount, uint remainingAmount) public view returns (uint swapAmount) { if (amount > usdtSwapLimit) { swapAmount = usdtSwapLimit; } else if (amount + remainingAmount > usdtSwapLimit) { swapAmount = usdtSwapLimit; } else { swapAmount = amount + remainingAmount; } } function _getAmountOutMinimum(uint amountIn) private returns (uint amountOutMin) { IOracle oracle = IOracle(A_OracleProxy); uint dydxPrice = oracle.getPrice("DYDX", "USDT", dydxUsdtPriceType); // dydxAmount * dydxPrice = usdtAmount * usdtPrice -> dydxAmount = usdtAmount/dydxPrice amountOutMin = amountIn * swapAmtOutMinRate / 100 / dydxPrice; } // assume 1usdx=1usdt function withdraw(uint usdxAmt) external whenNotPaused { require(usdxAmt <= issuedUSDXAmt, "Withdrawal amount must be less than issued usdx"); IERC20 usdt = IERC20(Const.A_USDT); IERC20 dydx = IERC20(Const.A_DYDX); IERC20 usdx = IERC20(A_USDX); usdx.safeTransfer(address(this), usdxAmt); issuedUSDXAmt -= usdxAmt; // if this contract has usdt, return usdt first uint usdxWithoutDecimal = usdxAmt / Const.MULTIPLIER_18; uint contractUSDTAmount = usdt.balanceOf(address(this)); uint usdtWithoutDecimal = contractUSDTAmount / Const.MULTIPLIER_6; if (contractUSDTAmount > 0) { // if usdt is enough, only pay usdt back if (usdtWithoutDecimal >= usdxWithoutDecimal) { usdt.safeTransfer(msg.sender, usdxWithoutDecimal * Const.MULTIPLIER_6); return; } // contract's usdt is not enough, pay contract's usdt first usdt.safeTransfer(msg.sender, usdtWithoutDecimal * Const.MULTIPLIER_6); // remaining usdx amount after paying some usdt usdxAmt = (usdxWithoutDecimal - usdtWithoutDecimal) * Const.MULTIPLIER_18; } // get dydx value uint currrentContractUSDTAmt = usdt.balanceOf(address(this)); uint sysDYDXAmt = dydx.balanceOf(address(this)) + dydx.balanceOf(A_BankVault); // Manual Operation: transfer DYDX to this contract from BankVaultX IOracle oracle = IOracle(A_OracleProxy); uint dydxPrice = oracle.getPrice("DYDX", "USDT", dydxUsdtPriceType); if ((dydxPrice * sysDYDXAmt + currrentContractUSDTAmt) / Const.MULTIPLIER_6 > issuedUSDXAmt / Const.MULTIPLIER_18) { // calculate the amount of dydx to pay uint dydx2pay = ((usdxAmt * Const.MULTIPLIER_6) / Const.MULTIPLIER_18) / dydxPrice; dydx.safeTransfer(msg.sender, dydx2pay); } else { // pay dydx uint dydx2pay = (usdxAmt * sysDYDXAmt) / issuedUSDXAmt; uint dydx2payDiscount = (dydx2pay * 95) / 100; dydx.safeTransfer(msg.sender, dydx2payDiscount); // pay 100xt // assume we have USDT/100xt pool uint remainUSDTAmt = (usdxAmt * Const.MULTIPLIER_6) / Const.MULTIPLIER_18 - dydx2payDiscount * dydxPrice; // uint t100xPrice = getPriceForTokenIn(A_100XT, Const.A_USDT, 1 * Const.MULTIPLIER_18); uint t100xPrice = oracle.getPrice("T100X", "USDT", t100xUsdtPriceType); // merge if there is an existing withdrawal for the same user if (user[msg.sender].t100xAmt == 0) { userInQueueFor100xt += 1; } user[msg.sender].t100xAmt = remainUSDTAmt / t100xPrice + user[msg.sender].t100xAmt; user[msg.sender].claimingAmtPerHour = user[msg.sender].t100xAmt / payDuration100xt / 24; user[msg.sender].startTime = block.timestamp; user[msg.sender].lastUpdated = block.timestamp; } } function viewClaiming100xt() public view returns (uint) { uint amount = user[msg.sender].t100xAmt; if(amount == 0 || userInQueueFor100xt ==0) return 0; uint amountPerHour = user[msg.sender].claimingAmtPerHour; amount = _getReCalculateAmount(amount, user[msg.sender].recalculateNO); amountPerHour = _getReCalculateAmount(amountPerHour, user[msg.sender].recalculateNO); uint sysAmountPerHour = sysAmt100xtPerDay / userInQueueFor100xt / 24; uint claimingAmountPerHour = (amountPerHour < sysAmountPerHour) ? amountPerHour : sysAmountPerHour; uint claimingAmount = (claimingAmountPerHour * (block.timestamp - user[msg.sender].lastUpdated)) / 3600; return (claimingAmount > amount) ? amount : claimingAmount; } /** * Manual Operation: mint 100XT to this contract */ function claim100xt() external whenNotPaused { // recalculate uint recalculateArrLen = recalculateArr.length; if(user[msg.sender].recalculateNO < recalculateArrLen){ user[msg.sender].t100xAmt = _getReCalculateAmount(user[msg.sender].t100xAmt, user[msg.sender].recalculateNO); user[msg.sender].claimingAmtPerHour = _getReCalculateAmount(user[msg.sender].claimingAmtPerHour, user[msg.sender].recalculateNO); user[msg.sender].recalculateNO = recalculateArrLen; } IERC20 t100x = IERC20(A_100XT); uint amount = viewClaiming100xt(); if(user[msg.sender].t100xAmt <= amount){ userInQueueFor100xt = (userInQueueFor100xt >= 1) ? userInQueueFor100xt - 1 : 0; amount = user[msg.sender].t100xAmt; } user[msg.sender].claimed += amount; user[msg.sender].t100xAmt -= amount; user[msg.sender].lastUpdated = block.timestamp; t100x.safeTransfer(msg.sender, amount); } function _getReCalculateAmount(uint amount, uint index) private view returns(uint){ uint len = recalculateArr.length; for(uint i = index; i < len; i++){ amount = amount * recalculateArr[i] / 100; } return amount; } /** * When the price of 100xt changes a lot. Admin triggers this to adjust the amount of 100xt that should pay to users * @param percent 50 means the new 100xt amout to pay to a user is 50% of the original amount */ function reCalculate100xtClaiming(uint percent) external onlyRole(OPERATOR) { require(percent < 100, "percent must be less than 100"); recalculateArr.push(percent); } /** * Only used by Admin when recalculateArr is wrong. */ function setReCalculateArr(uint[] calldata arr) external onlyRole(DEFAULT_ADMIN_ROLE) { recalculateArr = arr; } function setBankVaultAddr(address addr) external onlyRole(DEFAULT_ADMIN_ROLE) { require(addr != address(0), "Invalid address provided"); A_BankVault = addr; } function setSwapRate(uint _rate) external onlyRole(OPERATOR) { require(_rate <= 100, "Value can not exceed 100"); swapRate = _rate; } function setPoolFee(uint16 _fee) external onlyRole(OPERATOR) { require(_fee >= 1000, "Value must be greater than 1000"); require(_fee <= 50000, "Value must be less than 50000"); poolFee = _fee; } function setUsdtSwapLimit(uint _val) external onlyRole(OPERATOR) { require(_val <= 200000 * Const.MULTIPLIER_6, "Value must be less than 200000"); require(_val >= 1000 * Const.MULTIPLIER_6, "Value must be greater than 1000"); usdtSwapLimit = _val; } function setSwapAmtOutMinRate(uint _val) external onlyRole(OPERATOR) { require(_val <= 100, "Value must be less than 100"); require(_val >= 50, "Value must be greater than 50"); swapAmtOutMinRate = _val; } function setsysAmt100xtPerDay(uint _val) external onlyRole(OPERATOR) { require(_val <= 100000 * Const.MULTIPLIER_18, "Value must be less than 100000"); require(_val >= 1000 * Const.MULTIPLIER_18, "Value must be greater than 1000"); sysAmt100xtPerDay = _val; } function setDydxUsdtPriceType(uint _val) external onlyRole(OPERATOR) { dydxUsdtPriceType = _val; } function setDepositMinAmt(uint _val) external onlyRole(OPERATOR) { depositMinAmt = _val; } function setT100xUsdtPriceType(uint _val) external onlyRole(OPERATOR) { t100xUsdtPriceType = _val; } function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { _pause(); } function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; function _sendLogPayloadImplementation(bytes memory payload) internal view { address consoleAddress = CONSOLE_ADDRESS; /// @solidity memory-safe-assembly assembly { pop( staticcall( gas(), consoleAddress, add(payload, 32), mload(payload), 0, 0 ) ) } } function _castToPure( function(bytes memory) internal view fnIn ) internal pure returns (function(bytes memory) pure fnOut) { assembly { fnOut := fnIn } } function _sendLogPayload(bytes memory payload) internal pure { _castToPure(_sendLogPayloadImplementation)(payload); } function log() internal pure { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); } function logUint(uint256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function logString(string memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint256 p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); } function log(string memory p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint256 p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); } function log(uint256 p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); } function log(uint256 p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); } function log(uint256 p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); } function log(string memory p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); } function log(string memory p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); } function log(bool p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint256 p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); } function log(address p0, string memory p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint256 p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); } function log(uint256 p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); } function log(uint256 p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); } function log(uint256 p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); } function log(uint256 p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); } function log(uint256 p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); } function log(uint256 p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); } function log(uint256 p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); } function log(uint256 p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); } function log(uint256 p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); } function log(uint256 p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); } function log(uint256 p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); } function log(uint256 p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); } function log(string memory p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); } function log(string memory p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); } function log(string memory p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); } function log(string memory p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); } function log(bool p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); } function log(bool p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); } function log(bool p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint256 p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); } function log(address p0, uint256 p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); } function log(address p0, uint256 p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); } function log(address p0, uint256 p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint256 p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); } function log(uint256 p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint256 p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint256 p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint256 p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal pure { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "viaIR": true, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"initialAdmin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","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":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR","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":"spender","type":"address"},{"internalType":"uint256","name":"value","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":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"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":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"grantDefaultAdmin","outputs":[],"stateMutability":"nonpayable","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":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","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":"address","name":"addr","type":"address"}],"name":"setDefaultAdmin","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":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","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":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080346200046c5762001b2d906001600160401b03601f19601f388590038181018316850190848211868310176200047157808691604098899485528339810103126200046c576200005184620004a7565b91620000616020809601620004a7565b936200006c62000487565b60098152682aa9a22c2a37b5b2b760b91b878201526200008b62000487565b90600494858352630aaa688b60e31b8984015281519284841162000363576003938454936001948581811c9116801562000461575b8d8210146200044c57908c8286859411620003f3575b50508c90858311600114620003845760009262000378575b505060001982871b1c191690841b1784555b8051948511620003635786548381811c9116801562000358575b8b8210146200034357828111620002f8575b50899185116001146200028f578495509084929160009562000283575b50501b92600019911b1c19161781555b6001600160a01b03918083169182156200026c5750620001c49082600554818682167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36001600160a81b03191617600555620001b985620004bc565b6200024b576200053d565b6200021d575b50620001d6826200053d565b620001eb575b835161149090816200065d8239f35b6007620002139360008051602062001b0d8339815191526000525283600020911690620005cf565b50388080620001dc565b620002439060008051602062001b0d8339815191526000526007855285600020620005cf565b5038620001ca565b6000805260078652620002658760002085871690620005cf565b506200053d565b6024906000885191631e4fbdf760e01b8352820152fd5b01519350388062000149565b92919484169286600052848a6000209460005b8c89838310620002e05750505010620002c5575b50505050811b01815562000159565b01519060f884600019921b161c1916905538808080620002b6565b868601518955909701969485019488935001620002a2565b876000528a6000208380880160051c8201928d891062000339575b0160051c019084905b8281106200032c5750506200012c565b600081550184906200031c565b9250819262000313565b602288634e487b7160e01b6000525260246000fd5b90607f16906200011a565b604187634e487b7160e01b6000525260246000fd5b015190503880620000ee565b908d918a8895168960005283600020936000905b828210620003d15750508411620003b8575b505050811b01845562000100565b015160001983891b60f8161c19169055388080620003aa565b91929395968291958786015181550195019301908f9189969594939262000398565b909192508760005285826000209181860160051c830193861062000442575b918891869594930160051c01915b8281106200043257508e9150620000d6565b6000815585945088910162000420565b9250819262000412565b60228a634e487b7160e01b6000525260246000fd5b90607f1690620000c0565b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b038111838210176200047157604052565b51906001600160a01b03821682036200046c57565b6001600160a01b031660008181527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8602052604081205490919060ff16620005395781805260066020526040822081835260205260408220600160ff19825416179055339160008051602062001aed8339815191528180a4600190565b5090565b6001600160a01b031660008181527f766fe29deb6965dde422bb334b5e1710f957ac4a1b6e40fb8517b43f1b011182602052604081205490919060008051602062001b0d8339815191529060ff16620005ca5780835260066020526040832082845260205260408320600160ff1982541617905560008051602062001aed833981519152339380a4600190565b505090565b919060018301600090828252806020526040822054156000146200065657845494680100000000000000008610156200064257600186018082558610156200062e57836040949596828552602085200155549382526020522055600190565b634e487b7160e01b83526032600452602483fd5b634e487b7160e01b83526041600452602483fd5b5092505056fe6080604081815260048036101561001557600080fd5b600092833560e01c90816301ffc9a714610c555750806306fdde0314610b78578063095ea7b314610acf57806315a41150146109a257806318160ddd1461098357806323b872dd14610946578063248a9ca31461091c5780632f2ff15d146108b1578063313ce5671461089557806336568abe1461084e5780633f4ba83a146107df57806340c10f19146106d357806342966c68146106b55780635c975abb1461068e57806370a0823114610657578063715018a6146105fa57806379cc6790146105c45780638456cb59146105635780638da5cb5b1461053a5780639010d07c146104fa57806391d14854146104b457806395d89b4114610392578063983d273714610357578063a217fddf1461033c578063a9059cbb1461030b578063ca15c873146102e4578063d547741f146102a5578063dd62ed3e1461025c578063e62f774f146101ff5763f2fde38b1461016d57600080fd5b346101fb5760203660031901126101fb57610186610d0c565b9061018f610d3d565b6001600160a01b039182169283156101e5575050600554826bffffffffffffffffffffffff60a01b821617600555167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b51631e4fbdf760e01b8152908101849052602490fd5b8280fd5b5050346102585760203660031901126102585761021a610d0c565b610222610d3d565b61022b81611189565b610233578280f35b8280526007602052908220610251916001600160a01b0316906113e7565b5038808280f35b5080fd5b5050346102585780600319360112610258578060209261027a610d0c565b610282610d27565b6001600160a01b0391821683526001865283832091168252845220549051908152f35b5090346101fb57806003193601126101fb576102e091356102db60016102c9610d27565b93838752600660205286200154610fb5565b610d69565b5080f35b50346101fb5760203660031901126101fb5760209282913581526007845220549051908152f35b50503461025857806003193601126102585760209061033561032b610d0c565b6024359033610e77565b5160018152f35b50503461025857816003193601126102585751908152602090f35b505034610258578160031936011261025857602090517f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c8152f35b5091903461025857816003193601126102585780519082845460018160011c90600183169283156104aa575b60209384841081146104975783885290811561047b5750600114610426575b505050829003601f01601f191682019267ffffffffffffffff841183851017610413575082918261040f925282610cc3565b0390f35b634e487b7160e01b815260418552602490fd5b8787529192508591837f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b83851061046757505050508301013880806103dd565b805488860183015293019284908201610451565b60ff1916878501525050151560051b84010190503880806103dd565b634e487b7160e01b895260228a52602489fd5b91607f16916103be565b50346101fb57816003193601126101fb578160209360ff926104d4610d27565b90358252600686528282206001600160a01b039091168252855220549151911615158152f35b50346101fb57816003193601126101fb5760209261052491358152600784528260243591206112b2565b905491519160018060a01b039160031b1c168152f35b50503461025857816003193601126102585760055490516001600160a01b039091168152602090f35b50503461025857816003193601126102585760207f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258916105a1610f5d565b6105a9611291565b6005805460ff60a01b1916600160a01b17905551338152a180f35b505034610258573660031901126105f7576105f46105e0610d0c565b602435906105ef823383610da4565b610fdb565b80f35b80fd5b83346105f757806003193601126105f757610613610d3d565b600580546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5050346102585760203660031901126102585760209181906001600160a01b0361067f610d0c565b16815280845220549051908152f35b50503461025857816003193601126102585760209060ff60055460a01c1690519015158152f35b838234610258576020366003190112610258576105f4903533610fdb565b5090346101fb57806003193601126101fb576106ed610d0c565b90602435917f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c808652600660205282862033875260205260ff8387205416156107c157506001600160a01b03169283156107ac57610749611291565b60025490838201809211610799575084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9260209260025585855284835280852082815401905551908152a380f35b634e487b7160e01b865260119052602485fd5b84602492519163ec442f0560e01b8352820152fd5b825163e2517d3f60e01b815233818701526024810191909152604490fd5b50346101fb57826003193601126101fb576107f8610f5d565b6005549060ff8260a01c1615610840575060ff60a01b1916600555513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a180f35b8251638dfc202b60e01b8152fd5b50919034610258578060031936011261025857610869610d27565b90336001600160a01b0383160361088657506102e0919235610d69565b5163334bd91960e11b81528390fd5b5050346102585781600319360112610258576020905160128152f35b50346101fb57816003193601126101fb5735906108cc610d27565b9082845260066020526108e460018286200154610fb5565b6108ee8284611216565b6108f6578380f35b9183526007602052908220610914916001600160a01b0316906113e7565b503880808380f35b50346101fb5760203660031901126101fb5781602093600192358152600685522001549051908152f35b50503461025857606036600319011261025857602090610335610967610d0c565b61096f610d27565b6044359161097e833383610da4565b610e77565b5050346102585781600319360112610258576020906002549051908152f35b50346101fb5760209182600319360112610acb576109be610d0c565b916109c7610d3d565b848052600784528185208054158015610a0d575b5050506109e782611189565b6109ef578380f35b8380526007909252908220610914916001600160a01b0316906113e7565b610ab8578552838520546001600160a01b03908116919084168214610a5c5750610a3681611082565b610a42575b80806109db565b610a5590858052600785528286206112e0565b5038610a3b565b825162461bcd60e51b8152908101859052603060248201527f4e65772061646d696e2061646472657373206973207468652073616d6520617360448201526f207468652063757272656e74206f6e6560801b6064820152608490fd5b634e487b7160e01b865260328252602486fd5b8380fd5b50346101fb57816003193601126101fb57610ae8610d0c565b602435903315610b61576001600160a01b0316918215610b4a57508083602095338152600187528181208582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b8351634a1406b160e11b8152908101859052602490fd5b835163e602df0560e01b8152808401869052602490fd5b509190346102585781600319360112610258578051908260035460018160011c9060018316928315610c4b575b60209384841081146104975783885290811561047b5750600114610bf557505050829003601f01601f191682019267ffffffffffffffff841183851017610413575082918261040f925282610cc3565b600387529192508591837fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b838510610c3757505050508301013880806103dd565b805488860183015293019284908201610c21565b91607f1691610ba5565b925050346101fb5760203660031901126101fb573563ffffffff60e01b81168091036101fb5760209250635a05180f60e01b8114908115610c98575b5015158152f35b637965db0b60e01b811491508115610cb2575b5038610c91565b6301ffc9a760e01b14905038610cab565b6020808252825181830181905290939260005b828110610cf857505060409293506000838284010152601f8019910116010190565b818101860151848201604001528501610cd6565b600435906001600160a01b0382168203610d2257565b600080fd5b602435906001600160a01b0382168203610d2257565b6005546001600160a01b03163303610d5157565b60405163118cdaa760e01b8152336004820152602490fd5b610d73828261110d565b9182610d7e57505090565b600091825260076020526040909120610da0916001600160a01b0316906112e0565b5090565b9160018060a01b038093169160009383855260016020526040938486209183169182875260205284862054926000198403610de3575b50505050505050565b848410610e4757508015610e2f578115610e1757855260016020528385209085526020520391205538808080808080610dda565b8451634a1406b160e11b815260048101879052602490fd5b845163e602df0560e01b815260048101879052602490fd5b8551637dc7a0d960e11b81526001600160a01b039190911660048201526024810184905260448101859052606490fd5b916001600160a01b03808416928315610f445716928315610f2b57610e9a611291565b60009083825281602052604082205490838210610ef9575091604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b60405163ec442f0560e01b815260006004820152602490fd5b604051634b637e8f60e11b815260006004820152602490fd5b3360009081527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8602052604081205460ff1615610f975750565b6044906040519063e2517d3f60e01b82523360048301526024820152fd5b80600052600660205260406000203360005260205260ff6040600020541615610f975750565b906001600160a01b038216908115610f4457610ff5611291565b600092828452836020526040842054908282106110505750817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef926020928587528684520360408620558060025403600255604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101829052606490fd5b6001600160a01b031660008181527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8602052604081205490919060ff1615610da0578180526006602052604082208183526020526040822060ff19815416905533917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b8180a4600190565b906000918083526006602052604083209160018060a01b03169182845260205260ff604084205416600014611184578083526006602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b505090565b6001600160a01b031660008181527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8602052604081205490919060ff16610da05781805260066020526040822081835260205260408220600160ff1982541617905533917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b906000918083526006602052604083209160018060a01b03169182845260205260ff604084205416156000146111845780835260066020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b60ff60055460a01c166112a057565b60405163d93c066560e01b8152600490fd5b80548210156112ca5760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b906001820190600092818452826020526040842054908115156000146113e057600019918083018181116113cc578254908482019182116113b85781810361136c575b505050805480156113585782019161133b83836112b2565b909182549160031b1b191690555582526020526040812055600190565b634e487b7160e01b86526031600452602486fd5b6113a361137c61138c93866112b2565b90549060031b1c928392866112b2565b819391549060031b91821b91600019901b19161790565b90558652846020526040862055388080611323565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b5050505090565b919060018301600090828252806020526040822054156000146114545784549468010000000000000000861015611440578361143061138c886001604098999a018555846112b2565b9055549382526020522055600190565b634e487b7160e01b83526041600452602483fd5b5092505056fea2646970667358221220a7a1b3c97cb32ce1ea9a2f62adb729dab8a11b626697c8756afc0876fcc0aca864736f6c634300081800332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c000000000000000000000000a51304555ebc9c8d498723166ccc669734203a8f000000000000000000000000db8a701f2eee438ed8f790ddc4d640dee5a93511
Deployed Bytecode
0x6080604081815260048036101561001557600080fd5b600092833560e01c90816301ffc9a714610c555750806306fdde0314610b78578063095ea7b314610acf57806315a41150146109a257806318160ddd1461098357806323b872dd14610946578063248a9ca31461091c5780632f2ff15d146108b1578063313ce5671461089557806336568abe1461084e5780633f4ba83a146107df57806340c10f19146106d357806342966c68146106b55780635c975abb1461068e57806370a0823114610657578063715018a6146105fa57806379cc6790146105c45780638456cb59146105635780638da5cb5b1461053a5780639010d07c146104fa57806391d14854146104b457806395d89b4114610392578063983d273714610357578063a217fddf1461033c578063a9059cbb1461030b578063ca15c873146102e4578063d547741f146102a5578063dd62ed3e1461025c578063e62f774f146101ff5763f2fde38b1461016d57600080fd5b346101fb5760203660031901126101fb57610186610d0c565b9061018f610d3d565b6001600160a01b039182169283156101e5575050600554826bffffffffffffffffffffffff60a01b821617600555167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b51631e4fbdf760e01b8152908101849052602490fd5b8280fd5b5050346102585760203660031901126102585761021a610d0c565b610222610d3d565b61022b81611189565b610233578280f35b8280526007602052908220610251916001600160a01b0316906113e7565b5038808280f35b5080fd5b5050346102585780600319360112610258578060209261027a610d0c565b610282610d27565b6001600160a01b0391821683526001865283832091168252845220549051908152f35b5090346101fb57806003193601126101fb576102e091356102db60016102c9610d27565b93838752600660205286200154610fb5565b610d69565b5080f35b50346101fb5760203660031901126101fb5760209282913581526007845220549051908152f35b50503461025857806003193601126102585760209061033561032b610d0c565b6024359033610e77565b5160018152f35b50503461025857816003193601126102585751908152602090f35b505034610258578160031936011261025857602090517f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c8152f35b5091903461025857816003193601126102585780519082845460018160011c90600183169283156104aa575b60209384841081146104975783885290811561047b5750600114610426575b505050829003601f01601f191682019267ffffffffffffffff841183851017610413575082918261040f925282610cc3565b0390f35b634e487b7160e01b815260418552602490fd5b8787529192508591837f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b83851061046757505050508301013880806103dd565b805488860183015293019284908201610451565b60ff1916878501525050151560051b84010190503880806103dd565b634e487b7160e01b895260228a52602489fd5b91607f16916103be565b50346101fb57816003193601126101fb578160209360ff926104d4610d27565b90358252600686528282206001600160a01b039091168252855220549151911615158152f35b50346101fb57816003193601126101fb5760209261052491358152600784528260243591206112b2565b905491519160018060a01b039160031b1c168152f35b50503461025857816003193601126102585760055490516001600160a01b039091168152602090f35b50503461025857816003193601126102585760207f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258916105a1610f5d565b6105a9611291565b6005805460ff60a01b1916600160a01b17905551338152a180f35b505034610258573660031901126105f7576105f46105e0610d0c565b602435906105ef823383610da4565b610fdb565b80f35b80fd5b83346105f757806003193601126105f757610613610d3d565b600580546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5050346102585760203660031901126102585760209181906001600160a01b0361067f610d0c565b16815280845220549051908152f35b50503461025857816003193601126102585760209060ff60055460a01c1690519015158152f35b838234610258576020366003190112610258576105f4903533610fdb565b5090346101fb57806003193601126101fb576106ed610d0c565b90602435917f523a704056dcd17bcf83bed8b68c59416dac1119be77755efe3bde0a64e46e0c808652600660205282862033875260205260ff8387205416156107c157506001600160a01b03169283156107ac57610749611291565b60025490838201809211610799575084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9260209260025585855284835280852082815401905551908152a380f35b634e487b7160e01b865260119052602485fd5b84602492519163ec442f0560e01b8352820152fd5b825163e2517d3f60e01b815233818701526024810191909152604490fd5b50346101fb57826003193601126101fb576107f8610f5d565b6005549060ff8260a01c1615610840575060ff60a01b1916600555513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a180f35b8251638dfc202b60e01b8152fd5b50919034610258578060031936011261025857610869610d27565b90336001600160a01b0383160361088657506102e0919235610d69565b5163334bd91960e11b81528390fd5b5050346102585781600319360112610258576020905160128152f35b50346101fb57816003193601126101fb5735906108cc610d27565b9082845260066020526108e460018286200154610fb5565b6108ee8284611216565b6108f6578380f35b9183526007602052908220610914916001600160a01b0316906113e7565b503880808380f35b50346101fb5760203660031901126101fb5781602093600192358152600685522001549051908152f35b50503461025857606036600319011261025857602090610335610967610d0c565b61096f610d27565b6044359161097e833383610da4565b610e77565b5050346102585781600319360112610258576020906002549051908152f35b50346101fb5760209182600319360112610acb576109be610d0c565b916109c7610d3d565b848052600784528185208054158015610a0d575b5050506109e782611189565b6109ef578380f35b8380526007909252908220610914916001600160a01b0316906113e7565b610ab8578552838520546001600160a01b03908116919084168214610a5c5750610a3681611082565b610a42575b80806109db565b610a5590858052600785528286206112e0565b5038610a3b565b825162461bcd60e51b8152908101859052603060248201527f4e65772061646d696e2061646472657373206973207468652073616d6520617360448201526f207468652063757272656e74206f6e6560801b6064820152608490fd5b634e487b7160e01b865260328252602486fd5b8380fd5b50346101fb57816003193601126101fb57610ae8610d0c565b602435903315610b61576001600160a01b0316918215610b4a57508083602095338152600187528181208582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b8351634a1406b160e11b8152908101859052602490fd5b835163e602df0560e01b8152808401869052602490fd5b509190346102585781600319360112610258578051908260035460018160011c9060018316928315610c4b575b60209384841081146104975783885290811561047b5750600114610bf557505050829003601f01601f191682019267ffffffffffffffff841183851017610413575082918261040f925282610cc3565b600387529192508591837fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b838510610c3757505050508301013880806103dd565b805488860183015293019284908201610c21565b91607f1691610ba5565b925050346101fb5760203660031901126101fb573563ffffffff60e01b81168091036101fb5760209250635a05180f60e01b8114908115610c98575b5015158152f35b637965db0b60e01b811491508115610cb2575b5038610c91565b6301ffc9a760e01b14905038610cab565b6020808252825181830181905290939260005b828110610cf857505060409293506000838284010152601f8019910116010190565b818101860151848201604001528501610cd6565b600435906001600160a01b0382168203610d2257565b600080fd5b602435906001600160a01b0382168203610d2257565b6005546001600160a01b03163303610d5157565b60405163118cdaa760e01b8152336004820152602490fd5b610d73828261110d565b9182610d7e57505090565b600091825260076020526040909120610da0916001600160a01b0316906112e0565b5090565b9160018060a01b038093169160009383855260016020526040938486209183169182875260205284862054926000198403610de3575b50505050505050565b848410610e4757508015610e2f578115610e1757855260016020528385209085526020520391205538808080808080610dda565b8451634a1406b160e11b815260048101879052602490fd5b845163e602df0560e01b815260048101879052602490fd5b8551637dc7a0d960e11b81526001600160a01b039190911660048201526024810184905260448101859052606490fd5b916001600160a01b03808416928315610f445716928315610f2b57610e9a611291565b60009083825281602052604082205490838210610ef9575091604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b60405163ec442f0560e01b815260006004820152602490fd5b604051634b637e8f60e11b815260006004820152602490fd5b3360009081527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8602052604081205460ff1615610f975750565b6044906040519063e2517d3f60e01b82523360048301526024820152fd5b80600052600660205260406000203360005260205260ff6040600020541615610f975750565b906001600160a01b038216908115610f4457610ff5611291565b600092828452836020526040842054908282106110505750817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef926020928587528684520360408620558060025403600255604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101829052606490fd5b6001600160a01b031660008181527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8602052604081205490919060ff1615610da0578180526006602052604082208183526020526040822060ff19815416905533917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b8180a4600190565b906000918083526006602052604083209160018060a01b03169182845260205260ff604084205416600014611184578083526006602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b505090565b6001600160a01b031660008181527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8602052604081205490919060ff16610da05781805260066020526040822081835260205260408220600160ff1982541617905533917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b906000918083526006602052604083209160018060a01b03169182845260205260ff604084205416156000146111845780835260066020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b60ff60055460a01c166112a057565b60405163d93c066560e01b8152600490fd5b80548210156112ca5760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b906001820190600092818452826020526040842054908115156000146113e057600019918083018181116113cc578254908482019182116113b85781810361136c575b505050805480156113585782019161133b83836112b2565b909182549160031b1b191690555582526020526040812055600190565b634e487b7160e01b86526031600452602486fd5b6113a361137c61138c93866112b2565b90549060031b1c928392866112b2565b819391549060031b91821b91600019901b19161790565b90558652846020526040862055388080611323565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b5050505090565b919060018301600090828252806020526040822054156000146114545784549468010000000000000000861015611440578361143061138c886001604098999a018555846112b2565b9055549382526020522055600190565b634e487b7160e01b83526041600452602483fd5b5092505056fea2646970667358221220a7a1b3c97cb32ce1ea9a2f62adb729dab8a11b626697c8756afc0876fcc0aca864736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a51304555ebc9c8d498723166ccc669734203a8f000000000000000000000000db8a701f2eee438ed8f790ddc4d640dee5a93511
-----Decoded View---------------
Arg [0] : initialOwner (address): 0xa51304555Ebc9c8d498723166cCC669734203a8f
Arg [1] : initialAdmin (address): 0xdb8a701F2eeE438ed8f790ddC4D640dEe5a93511
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000a51304555ebc9c8d498723166ccc669734203a8f
Arg [1] : 000000000000000000000000db8a701f2eee438ed8f790ddc4d640dee5a93511
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.