// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import { IAuthorized } from "./interfaces/IAuthorized.sol";
abstract contract Authorized is IAuthorized {
constructor() {
/// @notice Add the deployer as an authorized admin
owner = msg.sender;
}
/// @notice the owner of the contract
address private owner;
/// @notice A mapping storing authorized admins
/// @dev admin address => authorized status
mapping (address => bool) private authorizedAdmins;
/// @notice A mapping of the authorized delegate operators
/// @dev operator address => authorized status
mapping (address => bool) private authorizedOperators;
/// @notice Modifier to ensure caller is owner
modifier onlyOwner() {
if (msg.sender != owner) {
revert Unauthorized();
}
_;
}
/// @dev Modifier to ensure caller is authorized admin
modifier onlyAuthorizedAdmin() {
if (msg.sender != owner && !authorizedAdmins[msg.sender]) {
revert Unauthorized();
}
_;
}
/// @dev Modifier to ensure caller is authorized operator
modifier onlyAuthorizedOperator() {
if (msg.sender != owner && !authorizedAdmins[msg.sender] && !authorizedOperators[msg.sender]) {
revert Unauthorized();
}
_;
}
/// @inheritdoc IAuthorized
function transferOwnership(address newOwner) external onlyOwner {
/// check if address is not null
require(newOwner != address(0), "Authorized System: New owner cannot be null");
/// check if address is not the same as owner
require(newOwner != owner, "Authorized System: New owner cannot be the same as old owner");
/// check if address is not the same as operator
require(!authorizedOperators[owner], "Authorized System: Owner cannot be an operator");
/// update the owner
owner = newOwner;
}
/// @inheritdoc IAuthorized
function setAuthorizedAdmin(address _admin, bool status) public virtual onlyAuthorizedAdmin {
/// check if address is not null
require(_admin != address(0), "Authorized System: Admin address cannot be null");
/// check if address is not the same as operator
require(!authorizedOperators[_admin], "Authorized System: Admin cannot be an operator");
/// update the admin status
authorizedAdmins[_admin] = status;
emit SetAdmin(_admin);
}
/// @inheritdoc IAuthorized
function setAuthorizedOperator(address _operator, bool status) public virtual onlyAuthorizedAdmin {
/// check if address is not null
require(_operator != address(0), "Authorized System: Operator address cannot be null");
/// check if address is not the same as admin
require(!authorizedAdmins[_operator], "Authorized System: Operator cannot be an admin");
/// update the operator status
authorizedOperators[_operator] = status;
emit SetOperator(_operator);
}
/// @inheritdoc IAuthorized
function getAuthorizedAdmin(address _admin) public view virtual returns (bool) {
return authorizedAdmins[_admin];
}
/// @inheritdoc IAuthorized
function getAuthorizedOperator(address _operator) public view virtual returns (bool) {
return authorizedOperators[_operator];
}
/// @inheritdoc IAuthorized
function getOwner() public view virtual override returns (address) {
return owner;
}
}
// 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/Create2.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev Not enough balance for performing a CREATE2 deploy.
*/
error Create2InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev There's no code to deploy.
*/
error Create2EmptyBytecode();
/**
* @dev The deployment failed.
*/
error Create2FailedDeployment();
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
if (address(this).balance < amount) {
revert Create2InsufficientBalance(address(this).balance, amount);
}
if (bytecode.length == 0) {
revert Create2EmptyBytecode();
}
/// @solidity memory-safe-assembly
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
if (addr == address(0)) {
revert Create2FailedDeployment();
}
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40) // Get free memory pointer
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := keccak256(start, 85)
}
}
}
// 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: UNLICENSED
pragma solidity ^0.8.24;
/*
&&&&&& &&&&& &%
&&&&&&&&&&&&&&& && &&&&&&&&&&%
&&&&&&& &&&&& #&&&&&&&&&&&&&
&&&&& &&&&&&& && &&&& &% &&&&&&&
&&. &&&&&&&&&& & %&&&&&&& &&&&
&&&& *&&&&&&&&& &&&&&&&&& &&&&
.&&& &&&&&&&& &&&&&&&& &&&
.&&&&&&& &&&&&&& &&&%
&&&&&& &&&&&&
&&&&& /&&&&.
&&&& %&&& #&&&,
&&&&( &&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&
&&&% &&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&& &&&* &&&&&&&&&&&&&&&&&&&&& &&*
&&& .&&&&&& &&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& #&&&&&& &&&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& &&&& &&&&&&&&&&&&&&&&&&&&&& #&& &&&
&&& &&&&&&&&&&&&&&&&&&&&&&&&, *&&&
(&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&%
&&&&&&&&&&&&&&&&& &&&&&
&&&&&&&&&&&&&&&&&& %&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
*/
/*
* ERC20AntiBot contract
* This contract is used to control bad actors using bots on trades
*/
/// @title ERC20AntiBot
/// @author Smithii
import {IERC20AntiBot} from "./interfaces/services/IERC20AntiBot.sol";
import {Indexable} from "./utils/Indexable.sol";
import {Payable} from "./utils/Payable.sol";
contract ERC20AntiBot is IERC20AntiBot, Payable, Indexable {
constructor(
address _indexer,
address _payments,
string memory _serviceId
) Indexable(_indexer) Payable(_payments, _serviceId) {}
/// mappings
mapping(address => mapping(address => uint256)) private buyBlock;
mapping(address => Options) private canUseAntiBot;
mapping(address => mapping(address => bool)) public exempts;
/// @inheritdoc IERC20AntiBot
function isBotDetected(address _from) public view returns (bool) {
if (isExempt(msg.sender, _from)) return false;
if (isActive(msg.sender)) {
return (buyBlock[msg.sender][_from] == block.number);
}
return false;
}
/// @inheritdoc IERC20AntiBot
function registerBlock(address _to) external {
if (isActive(msg.sender)) {
buyBlock[msg.sender][_to] = block.number;
}
}
/// set a token address to be registered in the AntiBot
/// @param _tokenAddress the address to check
/// @param _options the options for anti bot
function _setCanUseAntiBot(
address _tokenAddress,
Options memory _options
) internal {
canUseAntiBot[_tokenAddress] = _options;
}
/// @inheritdoc IERC20AntiBot
function setCanUseAntiBot(
bytes32 projectId,
address _tokenAddress
) external payable onlyProjectOwner(_tokenAddress) {
if (canUseAntiBot[_tokenAddress].active)
revert TokenAlreadyActiveOnAntiBot();
Options memory _options = Options(true, true);
_setCanUseAntiBot(_tokenAddress, _options);
payService(projectId, _tokenAddress, 1);
}
/// @inheritdoc IERC20AntiBot
function setActive(
address _tokenAddress,
bool _active
) external onlyProjectOwner(_tokenAddress) {
if (!canUseAntiBot[_tokenAddress].active)
revert TokenNotActiveOnAntiBot();
canUseAntiBot[_tokenAddress].applied = _active;
}
/// @inheritdoc IERC20AntiBot
function setExempt(
address _tokenAddress,
address _traderAddress,
bool _exempt
) external onlyProjectOwner(_tokenAddress) {
if (!canUseAntiBot[_tokenAddress].active)
revert TokenNotActiveOnAntiBot();
exempts[_tokenAddress][_traderAddress] = _exempt;
}
/// @inheritdoc IERC20AntiBot
function isExempt(
address _tokenAddress,
address _traderAddress
) public view returns (bool) {
return exempts[_tokenAddress][_traderAddress];
}
/// @inheritdoc IERC20AntiBot
function isActive(address _tokenAddress) public view returns (bool) {
if (!canUseAntiBot[_tokenAddress].active) return false;
return canUseAntiBot[_tokenAddress].applied;
}
/// @inheritdoc IERC20AntiBot
function canUse(address _tokenAddress) public view returns (bool) {
return canUseAntiBot[_tokenAddress].active;
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/*
&&&&&& &&&&& &%
&&&&&&&&&&&&&&& && &&&&&&&&&&%
&&&&&&& &&&&& #&&&&&&&&&&&&&
&&&&& &&&&&&& && &&&& &% &&&&&&&
&&. &&&&&&&&&& & %&&&&&&& &&&&
&&&& *&&&&&&&&& &&&&&&&&& &&&&
.&&& &&&&&&&& &&&&&&&& &&&
.&&&&&&& &&&&&&& &&&%
&&&&&& &&&&&&
&&&&& /&&&&.
&&&& %&&& #&&&,
&&&&( &&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&
&&&% &&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&& &&&* &&&&&&&&&&&&&&&&&&&&& &&*
&&& .&&&&&& &&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& #&&&&&& &&&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& &&&& &&&&&&&&&&&&&&&&&&&&&& #&& &&&
&&& &&&&&&&&&&&&&&&&&&&&&&&&, *&&&
(&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&%
&&&&&&&&&&&&&&&&& &&&&&
&&&&&&&&&&&&&&&&&& %&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
*/
/*
* ERC20AntiWhale contract
* This contract is used to control bad actors controlling large amounts of tokens
*/
/// @title ERC20AntiWhale
/// @author Smithii
import {IERC20AntiWhale} from "./interfaces/services/IERC20AntiWhale.sol";
import {Indexable} from "./utils/Indexable.sol";
import {Payable} from "./utils/Payable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract ERC20AntiWhale is IERC20AntiWhale, Indexable, Payable {
/// mappings
mapping(address => mapping(address => uint256)) private buyBlock;
mapping(address => Options) private canUseAntiWhale;
mapping(address => mapping(address => bool)) public exempts;
constructor(
address _indexer,
address _payments,
string memory _serviceId
) Indexable(_indexer) Payable(_payments, _serviceId) {}
/// @inheritdoc IERC20AntiWhale
function isWhaleDetected(
address _to,
uint256 _amount
) public view returns (bool) {
if (isExempt(msg.sender, _to)) return false;
bool isWhale = false;
if (isActive(msg.sender)) {
if (_amount > canUseAntiWhale[msg.sender].maxAmountPerTrade)
isWhale = true;
if (
_amount + IERC20(msg.sender).balanceOf(_to) >
canUseAntiWhale[msg.sender].maxAmountTotal
) isWhale = true;
if (
block.timestamp <
buyBlock[msg.sender][_to] +
canUseAntiWhale[msg.sender].timeLimitPerTrade
) isWhale = true;
}
return isWhale;
}
/// @inheritdoc IERC20AntiWhale
function registerBlockTimeStamp(address _to) external {
if (isActive(msg.sender)) {
buyBlock[msg.sender][_to] = block.timestamp;
}
}
/// set a token address to be registered in the AntiWhale
/// @param _address the address to check
/// @param _options the options for anti whale
function _setCanUseAntiWhale(
address _address,
Options memory _options
) internal {
canUseAntiWhale[_address] = _options;
}
/// @inheritdoc IERC20AntiWhale
function setCanUseAntiWhale(
bytes32 projectId,
address _tokenAddress,
Options memory _options
) external payable onlyProjectOwner(_tokenAddress) {
if (canUseAntiWhale[_tokenAddress].active)
revert TokenAlreadyActiveOnAntiWhale();
_options.active = true;
_options.activePeriodStarted = block.timestamp;
_setCanUseAntiWhale(_tokenAddress, _options);
payService(projectId, _tokenAddress, 1);
}
/// @inheritdoc IERC20AntiWhale
function setMaxAmountPerTrade(
address _tokenAddress,
uint256 _maxAmountPerTrade
) external onlyProjectOwner(_tokenAddress) {
if (!canUseAntiWhale[_tokenAddress].active)
revert TokenNotActiveOnAntiWhale();
canUseAntiWhale[_tokenAddress].maxAmountPerTrade = _maxAmountPerTrade;
}
/// @inheritdoc IERC20AntiWhale
function setMaxAmountTotal(
address _tokenAddress,
uint256 _maxAmountTotal
) external onlyProjectOwner(_tokenAddress) {
if (!canUseAntiWhale[_tokenAddress].active)
revert TokenNotActiveOnAntiWhale();
canUseAntiWhale[_tokenAddress].maxAmountTotal = _maxAmountTotal;
}
/// @inheritdoc IERC20AntiWhale
function setTimeLimitPerTrade(
address _tokenAddress,
uint256 _timeLimitPerTrade
) external onlyProjectOwner(_tokenAddress) {
if (!canUseAntiWhale[_tokenAddress].active)
revert TokenNotActiveOnAntiWhale();
canUseAntiWhale[_tokenAddress].timeLimitPerTrade = _timeLimitPerTrade;
}
/// @inheritdoc IERC20AntiWhale
function setActivePeriod(
address _tokenAddress,
uint256 _activePeriod
) external onlyProjectOwner(_tokenAddress) {
if (!canUseAntiWhale[_tokenAddress].active)
revert TokenNotActiveOnAntiWhale();
canUseAntiWhale[_tokenAddress].activePeriod = _activePeriod;
canUseAntiWhale[_tokenAddress].activePeriodStarted = block.timestamp;
}
/// @inheritdoc IERC20AntiWhale
function setExempt(
address _tokenAddress,
address _traderAddress,
bool _exempt
) external onlyProjectOwner(_tokenAddress) {
if (!canUseAntiWhale[_tokenAddress].active)
revert TokenNotActiveOnAntiWhale();
exempts[_tokenAddress][_traderAddress] = _exempt;
}
/// @inheritdoc IERC20AntiWhale
function isExempt(
address _tokenAddress,
address _traderAddress
) public view returns (bool) {
return exempts[_tokenAddress][_traderAddress];
}
/// @inheritdoc IERC20AntiWhale
function isActive(address _tokenAddress) public view returns (bool) {
if (!canUseAntiWhale[_tokenAddress].active) return false;
return
block.timestamp <
canUseAntiWhale[_tokenAddress].activePeriodStarted +
canUseAntiWhale[_tokenAddress].activePeriod;
}
/// @inheritdoc IERC20AntiWhale
function canUse(address _tokenAddress) public view returns (bool) {
return canUseAntiWhale[_tokenAddress].active;
}
}
// 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: UNLICENSED
pragma solidity ^0.8.24;
pragma abicoder v2;
/*
&&&&&& &&&&& &%
&&&&&&&&&&&&&&& && &&&&&&&&&&%
&&&&&&& &&&&& #&&&&&&&&&&&&&
&&&&& &&&&&&& && &&&& &% &&&&&&&
&&. &&&&&&&&&& & %&&&&&&& &&&&
&&&& *&&&&&&&&& &&&&&&&&& &&&&
.&&& &&&&&&&& &&&&&&&& &&&
.&&&&&&& &&&&&&& &&&%
&&&&&& &&&&&&
&&&&& /&&&&.
&&&& %&&& #&&&,
&&&&( &&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&
&&&% &&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&& &&&* &&&&&&&&&&&&&&&&&&&&& &&*
&&& .&&&&&& &&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& #&&&&&& &&&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& &&&& &&&&&&&&&&&&&&&&&&&&&& #&& &&&
&&& &&&&&&&&&&&&&&&&&&&&&&&&, *&&&
(&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&%
&&&&&&&&&&&&&&&&& &&&&&
&&&&&&&&&&&&&&&&&& %&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
*/
/*
* Pool Factory contract
* This contract is used to create a liquidity pool on Uniswap V3
*/
/// @title PoolFactory
/// @author Smithii
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import {INonfungiblePositionManager} from "./interfaces/INonfungiblePositionManager.sol";
import {Payable} from "./utils/Payable.sol";
contract ERC20PoolFactory is IERC721Receiver, Payable {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
struct Deposit {
address owner;
uint128 liquidity;
address token0;
address token1;
}
INonfungiblePositionManager public immutable nonfungiblePositionManager;
/// events
event PositionMinted(
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
event FeesCollected(uint256 amount0, uint256 amount1);
event LiquidityIncreased(
uint256 liquidity,
uint256 amount0,
uint256 amount1
);
event LiquidityDecreased(uint256 amount0, uint256 amount1);
/// mappings
mapping(uint256 => Deposit) public deposits;
constructor(
address _nonfungiblePositionManager,
address _payments,
string memory _serviceId
) Payable(_payments, _serviceId) {
nonfungiblePositionManager = INonfungiblePositionManager(
_nonfungiblePositionManager
);
}
/// @inheritdoc IERC721Receiver
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external override returns (bytes4) {
// get position information
_createDeposit(operator, tokenId);
return this.onERC721Received.selector;
}
/// Create Depoisit function
/// @param owner the owner of the deposit
/// @param tokenId the id of the deposit
function _createDeposit(address owner, uint256 tokenId) internal {
(
,
,
address token0,
address token1,
,
,
,
uint128 liquidity,
,
,
,
) = nonfungiblePositionManager.positions(tokenId);
// set the owner and data for position
// operator is msg.sender
deposits[tokenId] = Deposit({
owner: owner,
liquidity: liquidity,
token0: token0,
token1: token1
});
}
/// @notice Mint a new position, creates the pool and mints a token
/// @param _token0 the address of the token0
/// @param _token1 the address of the token1
/// @param _amount0ToMint the amount of token0 to mint
/// @param _amount1ToMint the amount of token1 to mint
/// @param poolFee the pool fee
/// @return tokenId the id of the erc721
/// @return liquidity the amount of liquidity
/// @return amount0 the amount of token0
/// @return amount1 the amount of token1
function mintNewPosition(
address _token0,
address _token1,
uint256 _amount0ToMint,
uint256 _amount1ToMint,
uint24 poolFee,
bytes32 _projectId
)
external
payable
returns (
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
)
{
// Approve the position manager
TransferHelper.safeApprove(
_token0,
address(nonfungiblePositionManager),
_amount0ToMint
);
TransferHelper.safeApprove(
_token1,
address(nonfungiblePositionManager),
_amount1ToMint
);
INonfungiblePositionManager.MintParams
memory params = INonfungiblePositionManager.MintParams({
token0: _token0,
token1: _token1,
fee: poolFee,
tickLower: MIN_TICK,
tickUpper: MAX_TICK,
amount0Desired: _amount0ToMint,
amount1Desired: _amount1ToMint,
amount0Min: 0,
amount1Min: 0,
recipient: address(this),
deadline: block.timestamp
});
///@dev Note that the pool defined by DAI/USDC and fee tier 0.01%
///@dev must already be created and initialized in order to mint
(tokenId, liquidity, amount0, amount1) = nonfungiblePositionManager
.mint(params);
// Create a deposit
_createDeposit(msg.sender, tokenId);
// Remove allowance and refund in both assets.
if (amount0 < _amount0ToMint) {
TransferHelper.safeApprove(
_token0,
address(nonfungiblePositionManager),
0
);
uint256 refund0 = _amount0ToMint - amount0;
TransferHelper.safeTransfer(_token0, msg.sender, refund0);
}
if (amount1 < _amount1ToMint) {
TransferHelper.safeApprove(
_token0,
address(nonfungiblePositionManager),
0
);
uint256 refund1 = _amount1ToMint - amount1;
TransferHelper.safeTransfer(_token1, msg.sender, refund1);
}
payService(_projectId, _token0, 1);
emit PositionMinted(tokenId, liquidity, amount0, amount1);
return (tokenId, liquidity, amount0, amount1);
}
/// Collect all fees from a position
/// @param tokenId The id of the erc721
/// @return amount0 the amount of token0
/// @return amount1 the amount of token1
function collectAllFees(
uint256 tokenId
) external returns (uint256 amount0, uint256 amount1) {
// Caller must own the ERC721 position
// Call to safeTransfer will trigger `onERC721Received` which must return the selector else transfer will fail
nonfungiblePositionManager.safeTransferFrom(
msg.sender,
address(this),
tokenId
);
// set amount0Max and amount1Max to uint256.max to collect all fees
// alternatively can set recipient to msg.sender and avoid another transaction in `sendToOwner`
INonfungiblePositionManager.CollectParams
memory params = INonfungiblePositionManager.CollectParams({
tokenId: tokenId,
recipient: address(this),
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
});
(amount0, amount1) = nonfungiblePositionManager.collect(params);
// send collected feed back to owner
_sendToOwner(tokenId, amount0, amount1);
emit FeesCollected(amount0, amount1);
return (amount0, amount1);
}
/// @notice Transfers funds to owner of NFT
/// @param tokenId The id of the erc721
/// @param amount0 The amount of token0
/// @param amount1 The amount of token1
function _sendToOwner(
uint256 tokenId,
uint256 amount0,
uint256 amount1
) internal {
// get owner of contract
address owner = deposits[tokenId].owner;
address token0 = deposits[tokenId].token0;
address token1 = deposits[tokenId].token1;
// send collected fees to owner
TransferHelper.safeTransfer(token0, owner, amount0);
TransferHelper.safeTransfer(token1, owner, amount1);
}
///
/// @param tokenId The id of the erc721
/// @param amountAdd0 the amount to add of token0
/// @param amountAdd1 the amount to add of token1
/// @return liquidity the amount of liquidity
/// @return amount0 the amount of token0
/// @return amount1 the amount of token1
function increaseLiquidityCurrentRange(
uint256 tokenId,
uint256 amountAdd0,
uint256 amountAdd1
) external returns (uint128 liquidity, uint256 amount0, uint256 amount1) {
TransferHelper.safeTransferFrom(
deposits[tokenId].token0,
msg.sender,
address(this),
amountAdd0
);
TransferHelper.safeTransferFrom(
deposits[tokenId].token1,
msg.sender,
address(this),
amountAdd1
);
TransferHelper.safeApprove(
deposits[tokenId].token0,
address(nonfungiblePositionManager),
amountAdd0
);
TransferHelper.safeApprove(
deposits[tokenId].token1,
address(nonfungiblePositionManager),
amountAdd1
);
INonfungiblePositionManager.IncreaseLiquidityParams
memory params = INonfungiblePositionManager
.IncreaseLiquidityParams({
tokenId: tokenId,
amount0Desired: amountAdd0,
amount1Desired: amountAdd1,
amount0Min: 0,
amount1Min: 0,
deadline: block.timestamp
});
(liquidity, amount0, amount1) = nonfungiblePositionManager
.increaseLiquidity(params);
emit LiquidityIncreased(liquidity, amount0, amount1);
}
///
/// @param tokenId The id of the erc721
/// @param newLiquidity the new liquidity
/// @return amount0 the amount of token0
/// @return amount1 the amount of token1
function decreaseLiquidity(
uint256 tokenId,
uint128 newLiquidity
) external returns (uint256 amount0, uint256 amount1) {
// caller must be the owner of the NFT
require(msg.sender == deposits[tokenId].owner, "Not the owner");
// get liquidity data for tokenId
uint128 liquidity = deposits[tokenId].liquidity;
//uint128 halfLiquidity = liquidity / 2;
require(
newLiquidity < liquidity,
"New liquidity must be lesser than current liquidity"
);
// amount0Min and amount1Min are price slippage checks
// if the amount received after burning is not greater than these minimums, transaction will fail
INonfungiblePositionManager.DecreaseLiquidityParams
memory params = INonfungiblePositionManager
.DecreaseLiquidityParams({
tokenId: tokenId,
liquidity: newLiquidity,
amount0Min: 0,
amount1Min: 0,
deadline: block.timestamp
});
(amount0, amount1) = nonfungiblePositionManager.decreaseLiquidity(
params
);
/// @notice send liquidity back to owner
_sendToOwner(tokenId, amount0, amount1);
emit LiquidityDecreased(amount0, amount1);
return (amount0, amount1);
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/*
&&&&&& &&&&& &%
&&&&&&&&&&&&&&& && &&&&&&&&&&%
&&&&&&& &&&&& #&&&&&&&&&&&&&
&&&&& &&&&&&& && &&&& &% &&&&&&&
&&. &&&&&&&&&& & %&&&&&&& &&&&
&&&& *&&&&&&&&& &&&&&&&&& &&&&
.&&& &&&&&&&& &&&&&&&& &&&
.&&&&&&& &&&&&&& &&&%
&&&&&& &&&&&&
&&&&& /&&&&.
&&&& %&&& #&&&,
&&&&( &&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&
&&&% &&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&& &&&* &&&&&&&&&&&&&&&&&&&&& &&*
&&& .&&&&&& &&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& #&&&&&& &&&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& &&&& &&&&&&&&&&&&&&&&&&&&&& #&& &&&
&&& &&&&&&&&&&&&&&&&&&&&&&&&, *&&&
(&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&%
&&&&&&&&&&&&&&&&& &&&&&
&&&&&&&&&&&&&&&&&& %&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
*/
/**
* ERC20Template contract
*/
/// @author Smithii
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Secured} from "../../utils/Secured.sol";
import {Shallowed} from "../../utils/Shallowed.sol";
contract ERC20Template is
ERC20,
ERC20Burnable,
Pausable,
Ownable,
Secured,
Shallowed
{
uint256 public constant DECIMALS = 1 * 10 ** 18;
uint256 public initialSupply = 0;
uint256 public taxFee = 0; // 0 - 100 % tax fee
address public taxAddress = address(0);
bool public isAirdrop = false;
mapping(address => bool) public blackList;
mapping(address => bool) public noTaxable;
/// Errors
error InvalidInitialSupply();
error InvalidTaxFee();
error BlacklistedAddress(address _address);
constructor(
string memory name,
string memory symbol,
address _owner,
address _taxAddress,
address _antiBot,
address _antiWhale,
uint256 _initialSupply,
uint256 _taxFee,
bool _isAirdrop
)
ERC20(name, symbol)
Ownable(_owner)
Secured(_antiBot)
Shallowed(_antiWhale)
{
if (_initialSupply <= 0) revert InvalidInitialSupply();
if (_taxFee > 20) revert InvalidTaxFee();
initialSupply = _initialSupply * DECIMALS;
taxFee = _taxFee;
taxAddress = _taxAddress;
noTaxable[_owner] = true;
noTaxable[address(0)] = true;
if (_isAirdrop) isAirdrop = true;
_mint(_owner, initialSupply);
}
/// Exclude the address from the tax
/// @param _address the target address
/// @param _taxable is the address not taxable
function setNotTaxable(address _address, bool _taxable) external onlyOwner {
noTaxable[_address] = _taxable;
}
/// BLacklist the address
/// @param _address the target address
/// @param _blackList is in the black list
function setBlackList(
address _address,
bool _blackList
) external onlyOwner {
blackList[_address] = _blackList;
}
/// Address to receive the tax
/// @param _taxAddress the address to receive the tax
function setTaxAddress(address _taxAddress) external onlyOwner {
taxAddress = _taxAddress;
noTaxable[_taxAddress] = true;
}
/// relesae the airdrop mode
/// @dev set the airdrop mode to false only once
function releaseAirdropMode() external onlyOwner {
isAirdrop = false;
}
/// @inheritdoc ERC20
function _update(
address sender,
address recipient,
uint256 amount
)
internal
virtual
override
whenNotPaused
noBots(sender)
noWhales(recipient, amount)
{
registerBlock(recipient);
registerBlockTimeStamp(sender);
if (isAirdrop) {
if (!noTaxable[sender]) revert("Airdrop mode is enabled");
}
/// @dev the tx is charged based on the sender
if (blackList[sender]) revert BlacklistedAddress(sender);
if (blackList[recipient]) revert BlacklistedAddress(recipient);
uint tax = 0;
if (!noTaxable[sender]) {
tax = (amount / 100) * taxFee; // % tax
super._update(sender, taxAddress, tax);
}
super._update(sender, recipient, amount - tax);
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/*
&&&&&& &&&&& &%
&&&&&&&&&&&&&&& && &&&&&&&&&&%
&&&&&&& &&&&& #&&&&&&&&&&&&&
&&&&& &&&&&&& && &&&& &% &&&&&&&
&&. &&&&&&&&&& & %&&&&&&& &&&&
&&&& *&&&&&&&&& &&&&&&&&& &&&&
.&&& &&&&&&&& &&&&&&&& &&&
.&&&&&&& &&&&&&& &&&%
&&&&&& &&&&&&
&&&&& /&&&&.
&&&& %&&& #&&&,
&&&&( &&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&
&&&% &&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&& &&&* &&&&&&&&&&&&&&&&&&&&& &&*
&&& .&&&&&& &&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& #&&&&&& &&&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& &&&& &&&&&&&&&&&&&&&&&&&&&& #&& &&&
&&& &&&&&&&&&&&&&&&&&&&&&&&&, *&&&
(&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&%
&&&&&&&&&&&&&&&&& &&&&&
&&&&&&&&&&&&&&&&&& %&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
*/
/*
* Factory contract
* This contract is used to deploy smart contracts and register them in the Indexer contract
*/
/// @title ERC20TokenFactory
/// @author Smithii
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {Indexable} from "./utils/Indexable.sol";
import {Payable} from "./utils/Payable.sol";
contract ERC20TokenFactory is Payable, Indexable {
constructor(
address _indexer,
address _payments,
string memory _serviceId
) Payable(_payments, _serviceId) Indexable(_indexer) {}
/// Deploys a contract and pays the service creating fee
/// @param _projectId bytes32 projectId
/// @param _byteCode the contract bytecode
/// @param _type the contract type
function deployContract(
bytes32 _projectId,
bytes calldata _byteCode,
string memory _type
) external payable {
address resultedAddress = Create2.computeAddress(
_projectId,
keccak256(_byteCode)
);
registerProject(_projectId, msg.sender, resultedAddress, _type);
address _contract = Create2.deploy(0, _projectId, _byteCode);
require(_contract == resultedAddress, "Contract address mismatch");
// Pay the total of 1 token creation fee
payService(_projectId, _contract, 1);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IAuthorized {
/// @notice Generic error when a user attempts to access a feature/function without proper access
error Unauthorized();
/// @notice Event emitted when a new admin is added
event SetAdmin(address indexed admin);
/// @notice Event emitted when a new operator is added
event SetOperator(address indexed operator);
/// @notice Event emmited when a new authOperator is added
event SetAuthOperator(address indexed authOperator);
/// @notice Transfer ownership of the contract to a new account (`newOwner`).
/// @param newOwner The address to transfer ownership to.
function transferOwnership(address newOwner) external;
/// @notice Add an authorized admin
/// @param _admin address of the admin
/// @param status status of the admin
function setAuthorizedAdmin(address _admin, bool status) external;
/// @notice Add an authorized Operator
/// @param _operator address of the operator
/// @param status status of the operator
function setAuthorizedOperator(address _operator, bool status) external;
/// @notice Get the status of an admin
/// @param _admin address of the admin
/// @return status of the admin
function getAuthorizedAdmin(address _admin) external view returns (bool);
/// @notice Get the status of an operator
/// @param _operator address of the operator
/// @return status of the operator
function getAuthorizedOperator(address _operator) external view returns (bool);
/// @notice Get the owner
function getOwner() external view returns (address);
}
// 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) (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: UNLICENSED
pragma solidity ^0.8.24;
/*
* IERC20AntiBot interface
*/
/// @title ERC20AntiBot
/// @author Smithii
interface IERC20AntiBot {
struct Options {
bool applied;
bool active;
}
/// errors
error TokenNotActiveOnAntiBot();
error TokenAlreadyActiveOnAntiBot();
///
/// @param _from the address to check
function isBotDetected(address _from) external returns (bool);
/// Registers the block number of the receiver
/// @param _to the address to register
function registerBlock(address _to) external;
/// Registers and pay for a token address to use the Antibot
/// @param projectId the project id
/// @param _tokenAddress the address to register
function setCanUseAntiBot(
bytes32 projectId,
address _tokenAddress
) external payable;
/// Set the exempt status of a trader
/// @param _tokenAddress the token address
/// @param _traderAddress the trader address
/// @param _exempt the exempt status
function setExempt(
address _tokenAddress,
address _traderAddress,
bool _exempt
) external;
/// helper function to check if the trader is exempt
/// @param _tokenAddress the token address
/// @param _traderAddress the trader address
function isExempt(
address _tokenAddress,
address _traderAddress
) external returns (bool);
///
/// @param _tokenAddress the token address
/// @param _active the active oft he options to be applied
function setActive(address _tokenAddress, bool _active) external;
/// Check if the token address is active to use the Antibot
/// @param _tokenAddress the address to check
function isActive(address _tokenAddress) external returns (bool);
/// Get if the token address can use the Antibot
/// @param _tokenAddress the address to check
function canUse(address _tokenAddress) external returns (bool);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/*
* IERC20AntiWhale interface
*/
/// @title IERC20AntiWhale
/// @author Smithii
interface IERC20AntiWhale {
struct Options {
uint256 maxAmountPerTrade;
uint256 maxAmountTotal; /// require to get the traders balance
uint256 timeLimitPerTrade;
uint256 activePeriod;
uint256 activePeriodStarted;
bool active;
}
/// errors
error TokenNotActiveOnAntiWhale();
error TokenAlreadyActiveOnAntiWhale();
///
/// @param _to the address to check
/// @param _amount the amount to check
function isWhaleDetected(
address _to,
uint256 _amount
) external returns (bool);
///
/// @param _to the address to register
function registerBlockTimeStamp(address _to) external;
///
/// @param projectId the project id
/// @param _address the token address to register
/// @param _options the options as Options struct
function setCanUseAntiWhale(
bytes32 projectId,
address _address,
Options memory _options
) external payable;
///
/// @param _address the token address
/// @param _maxAmountPerTrade the maximum amount per trade
function setMaxAmountPerTrade(
address _address,
uint256 _maxAmountPerTrade
) external;
///
/// @param _address the token address
/// @param _maxAmountTotal the maximum amount total accumulated by the trader
function setMaxAmountTotal(
address _address,
uint256 _maxAmountTotal
) external;
///
/// @param _address the token address
/// @param _timeLimitPerTrade the time limit per trade
function setTimeLimitPerTrade(
address _address,
uint256 _timeLimitPerTrade
) external;
///
/// @param _tokenAddress the token address
/// @param _activePeriod the active period of the options to be applied
function setActivePeriod(
address _tokenAddress,
uint256 _activePeriod
) external;
/// Set the exempt status of a trader
/// @param _tokenAddress the token address
/// @param _traderAddress the trader address
/// @param _exempt the exempt status
function setExempt(
address _tokenAddress,
address _traderAddress,
bool _exempt
) external;
/// helper function to check if the trader is exempt
/// @param _tokenAddress the token address
/// @param _traderAddress the trader address
function isExempt(
address _tokenAddress,
address _traderAddress
) external returns (bool);
///
/// @param _tokenAddress the token address
function isActive(address _tokenAddress) external returns (bool);
/// Get if the token address can use the AntiWhale
/// @param _tokenAddress the address to check
function canUse(address _tokenAddress) external returns (bool);
}
// 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/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
/// @title ERC721 with permit
/// @notice Extension to ERC721 that includes a permit function for signature based approvals
interface IERC721Permit is IERC721 {
/// @notice The permit typehash used in the permit signature
/// @return The typehash for the permit
function PERMIT_TYPEHASH() external pure returns (bytes32);
/// @notice The domain separator used in the permit signature
/// @return The domain seperator used in encoding of permit signature
function DOMAIN_SEPARATOR() external view returns (bytes32);
/// @notice Approve of a specific token ID for spending by spender via signature
/// @param spender The account that is being approved
/// @param tokenId The ID of the token that is being approved for spending
/// @param deadline The deadline timestamp by which the call must be mined for the approve to work
/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`
/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`
/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`
function permit(
address spender,
uint256 tokenId,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external payable;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/*
* IIndexer Inteface
*/
/// @title IIndexer
/// @author Smithii
interface IIndexer {
/// Structs
struct Contract {
address contractAddress;
string contracType;
}
struct Project {
address owner;
Contract[] contracts;
}
/// Errors
error ProjectContractAlreadyRegistered();
error ProjectIndexAlreadyRegistered();
/// Events
event ProjectRegistered(
bytes32 projectId,
address owner,
address contractAddress,
string contractType
);
/// Register a project in the Indexer
/// @param _projectId bytes32 projectId
/// @param _owner the owner of the project
/// @param _contract the contract address
function registerProject(
bytes32 _projectId,
address _owner,
address _contract,
string memory _contractType
) external;
/// Check if the ProjectIndex is registered
/// @param _projectId bytes32 projectId
/// @return bool if the proyect is aleady registered
function isProjectIndexRegistered(
bytes32 _projectId
) external returns (bool);
/// Check if a contract is registered in the project
/// @param _contract the contract address
/// @return bool if the proyect is aleady registered`
function isContractRegistered(address _contract) external returns (bool);
/// @param _projectId the project Index
function getProjectOwner(bytes32 _projectId) external returns (address);
///
/// @param _projectAddress address of the project
function getProjectAddressOwner(
address _projectAddress
) external returns (address);
///
/// @param _projectAddress address of the project
/// @return address the owner of the project
/// @return address[] the contracts of the project
function getProjectInfoByProjectAddress(
address _projectAddress
) external returns (address, Contract[] memory);
///
/// @param _projectId bytes32 projectId
/// @return address the owner of the project
/// @return address[] the contracts of the project
function getProjectInfoByIndex(
bytes32 _projectId
) external returns (address, Contract[] memory);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IPoolInitializer.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IERC721Permit.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryPayments.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol";
/// @title Non-fungible token for positions
/// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred
/// and authorized.
interface INonfungiblePositionManager is
IPoolInitializer,
IPeripheryPayments,
IPeripheryImmutableState,
IERC721Metadata,
IERC721Enumerable,
IERC721Permit
{
/// @notice Emitted when liquidity is increased for a position NFT
/// @dev Also emitted when a token is minted
/// @param tokenId The ID of the token for which liquidity was increased
/// @param liquidity The amount by which liquidity for the NFT position was increased
/// @param amount0 The amount of token0 that was paid for the increase in liquidity
/// @param amount1 The amount of token1 that was paid for the increase in liquidity
event IncreaseLiquidity(
uint256 indexed tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
/// @notice Emitted when liquidity is decreased for a position NFT
/// @param tokenId The ID of the token for which liquidity was decreased
/// @param liquidity The amount by which liquidity for the NFT position was decreased
/// @param amount0 The amount of token0 that was accounted for the decrease in liquidity
/// @param amount1 The amount of token1 that was accounted for the decrease in liquidity
event DecreaseLiquidity(
uint256 indexed tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
/// @notice Emitted when tokens are collected for a position NFT
/// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior
/// @param tokenId The ID of the token for which underlying tokens were collected
/// @param recipient The address of the account that received the collected tokens
/// @param amount0 The amount of token0 owed to the position that was collected
/// @param amount1 The amount of token1 owed to the position that was collected
event Collect(
uint256 indexed tokenId,
address recipient,
uint256 amount0,
uint256 amount1
);
/// @notice Returns the position information associated with a given token ID.
/// @dev Throws if the token ID is not valid.
/// @param tokenId The ID of the token that represents the position
/// @return nonce The nonce for permits
/// @return operator The address that is approved for spending
/// @return token0 The address of the token0 for a specific pool
/// @return token1 The address of the token1 for a specific pool
/// @return fee The fee associated with the pool
/// @return tickLower The lower end of the tick range for the position
/// @return tickUpper The higher end of the tick range for the position
/// @return liquidity The liquidity of the position
/// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position
/// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position
/// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation
/// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation
function positions(
uint256 tokenId
)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
/// @notice Creates a new position wrapped in a NFT
/// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized
/// a method does not exist, i.e. the pool is assumed to be initialized.
/// @param params The params necessary to mint a position, encoded as `MintParams` in calldata
/// @return tokenId The ID of the token that represents the minted position
/// @return liquidity The amount of liquidity for this position
/// @return amount0 The amount of token0
/// @return amount1 The amount of token1
function mint(
MintParams calldata params
)
external
payable
returns (
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
/// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`
/// @param params tokenId The ID of the token for which liquidity is being increased,
/// amount0Desired The desired amount of token0 to be spent,
/// amount1Desired The desired amount of token1 to be spent,
/// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,
/// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,
/// deadline The time by which the transaction must be included to effect the change
/// @return liquidity The new liquidity amount as a result of the increase
/// @return amount0 The amount of token0 to acheive resulting liquidity
/// @return amount1 The amount of token1 to acheive resulting liquidity
function increaseLiquidity(
IncreaseLiquidityParams calldata params
)
external
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1);
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
/// @notice Decreases the amount of liquidity in a position and accounts it to the position
/// @param params tokenId The ID of the token for which liquidity is being decreased,
/// amount The amount by which liquidity will be decreased,
/// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,
/// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,
/// deadline The time by which the transaction must be included to effect the change
/// @return amount0 The amount of token0 accounted to the position's tokens owed
/// @return amount1 The amount of token1 accounted to the position's tokens owed
function decreaseLiquidity(
DecreaseLiquidityParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
/// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient
/// @param params tokenId The ID of the NFT for which tokens are being collected,
/// recipient The account that should receive the tokens,
/// amount0Max The maximum amount of token0 to collect,
/// amount1Max The maximum amount of token1 to collect
/// @return amount0 The amount of fees collected in token0
/// @return amount1 The amount of fees collected in token1
function collect(
CollectParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
/// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens
/// must be collected first.
/// @param tokenId The ID of the token that is being burned
function burn(uint256 tokenId) external payable;
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/*
* IPayments interface
*/
/// @title Payments
/// @author Smithii
interface IPayments {
struct Service {
bytes32 serviceId;
uint256 pricePerItem;
bool active;
}
struct Invoice {
address user;
Service service;
uint256 qty;
uint256 total;
uint256 timestamp;
}
/// Events
event ServiceAdded(bytes32 serviceId, string name, uint256 price);
event ServiceSet(bytes32 serviceId, bool active);
event ServicePaid(
bytes32 projectId,
address contractAddress,
bytes32 serviceId,
address user,
uint256 amount,
uint256 timestamp
);
event ServiceWithdraw(
bytes32 projectId,
address contractAddress,
bytes32 serviceId,
uint256 amount
);
/// Errors
error ServiceNotActive(bytes32 serviceId);
error InvalidTotalAmount();
error ServiceAlreadyPaid(
bytes32 projectId,
address contractAddress,
bytes32 serviceId
);
/// Add a service to the payment program
/// @param _serviceId the service id
/// @param _pricePerItem the price per item
function addService(bytes32 _serviceId, uint256 _pricePerItem) external;
/// Set the service active status
/// @param _serviceId the service id
/// @param _active the active status
function setService(bytes32 _serviceId, bool _active) external;
/// function payService by projectId and contract address
/// @param _projectId bytes32 projectId
/// @param _contract the contract address
/// @param _serviceId the service id
/// @param _qty the qty of items to pay
function payService(
bytes32 _projectId,
address _contract,
bytes32 _serviceId,
uint256 _qty
) external payable;
/// Withdraw per invoice
/// @param _projectId the project id
/// @param _contract the contract address
/// @param _serviceId the service id
/// @param _to the address to withdraw the balance
function withdraw(
bytes32 _projectId,
address _contract,
bytes32 _serviceId,
address payable _to
) external;
/// Withdraw the contract balance
/// @param _to the address to withdraw the balance
function withdrawAll(address payable _to) external;
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Immutable state
/// @notice Functions that return immutable state of the router
interface IPeripheryImmutableState {
/// @return Returns the address of the Uniswap V3 factory
function factory() external view returns (address);
/// @return Returns the address of WETH9
function WETH9() external view returns (address);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
/// @title Periphery Payments
/// @notice Functions to ease deposits and withdrawals of ETH
interface IPeripheryPayments {
/// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH.
/// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users.
/// @param amountMinimum The minimum amount of WETH9 to unwrap
/// @param recipient The address receiving ETH
function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;
/// @notice Refunds any ETH balance held by this contract to the `msg.sender`
/// @dev Useful for bundling with mint or increase liquidity that uses ether, or exact output swaps
/// that use ether for the input amount
function refundETH() external payable;
/// @notice Transfers the full amount of a token held by this contract to recipient
/// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users
/// @param token The contract address of the token which will be transferred to `recipient`
/// @param amountMinimum The minimum amount of token required for a transfer
/// @param recipient The destination address of the token
function sweepToken(
address token,
uint256 amountMinimum,
address recipient
) external payable;
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
/// @title Creates and initializes V3 Pools
/// @notice Provides a method for creating and initializing a pool, if necessary, for bundling with other methods that
/// require the pool to exist.
interface IPoolInitializer {
/// @notice Creates a new pool if it does not exist, then initializes if not initialized
/// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) performed against a pool
/// @param token0 The contract address of token0 of the pool
/// @param token1 The contract address of token1 of the pool
/// @param fee The fee amount of the v3 pool for the specified token pair
/// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value
/// @return pool Returns the pool address based on the pair of tokens and fee, will return the newly created pool address if necessary
function createAndInitializePoolIfNecessary(
address token0,
address token1,
uint24 fee,
uint160 sqrtPriceX96
) external payable returns (address pool);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/// @title Indexable
/// @author Smithii
import {IIndexer} from "../interfaces/marketplace/IIndexer.sol";
abstract contract Indexable {
address public indexer = address(0);
bytes32 public projectId;
/// errors
error NotPtojectOwner();
constructor(address _indexer) {
indexer = _indexer;
}
modifier onlyProjectOwner(address _address) {
if (getProjectAddressOwner(_address) != msg.sender)
revert NotPtojectOwner();
_;
}
/// Registers the project in the Indexer
/// @param _projectId the project id
/// @param _owner the owner of the project
/// @param _contract the contract address
/// @param _contractType the contract type eg. ERC20, ERC721
function registerProject(
bytes32 _projectId,
address _owner,
address _contract,
string memory _contractType
) public {
IIndexer(indexer).registerProject(
_projectId,
_owner,
_contract,
_contractType
);
}
///
/// @param _projectAddress the project address
function isContractRegistered(
address _projectAddress
) public returns (bool) {
return IIndexer(indexer).isContractRegistered(_projectAddress);
}
///
/// @param _projectId the project id
function getProjectOwner(bytes32 _projectId) public returns (address) {
return IIndexer(indexer).getProjectOwner(_projectId);
}
function getProjectAddressOwner(
address _projectAddress
) public returns (address) {
return IIndexer(indexer).getProjectAddressOwner(_projectAddress);
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/*
&&&&&& &&&&& &%
&&&&&&&&&&&&&&& && &&&&&&&&&&%
&&&&&&& &&&&& #&&&&&&&&&&&&&
&&&&& &&&&&&& && &&&& &% &&&&&&&
&&. &&&&&&&&&& & %&&&&&&& &&&&
&&&& *&&&&&&&&& &&&&&&&&& &&&&
.&&& &&&&&&&& &&&&&&&& &&&
.&&&&&&& &&&&&&& &&&%
&&&&&& &&&&&&
&&&&& /&&&&.
&&&& %&&& #&&&,
&&&&( &&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&
&&&% &&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&& &&&* &&&&&&&&&&&&&&&&&&&&& &&*
&&& .&&&&&& &&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& #&&&&&& &&&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& &&&& &&&&&&&&&&&&&&&&&&&&&& #&& &&&
&&& &&&&&&&&&&&&&&&&&&&&&&&&, *&&&
(&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&%
&&&&&&&&&&&&&&&&& &&&&&
&&&&&&&&&&&&&&&&&& %&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
*/
/*
* Indexer contract
* This contract is used to index the projects and contracts deployed by the Factory contract
*/
/// @title Indexer
/// @author Smithii
import {IIndexer} from "../interfaces/marketplace/IIndexer.sol";
import {Authorized} from "@privylabs/authorized/contracts/Authorized.sol";
contract Indexer is IIndexer, Authorized {
/// Mappings
mapping(bytes32 => Project) public projects;
mapping(address => bytes32) public projectIndex; /// hepler to get registered projects
constructor() {}
/// @inheritdoc IIndexer
function registerProject(
bytes32 _projectId,
address _owner,
address _contract,
string memory _contractType
) public onlyAuthorizedOperator {
if (isContractRegistered(_contract))
revert ProjectContractAlreadyRegistered();
if (
isProjectIndexRegistered(_projectId) &&
projects[_projectId].owner != _owner
) revert ProjectIndexAlreadyRegistered();
Contract memory _contractInfo = Contract(_contract, _contractType);
projects[_projectId].contracts.push(_contractInfo);
projects[_projectId].owner = _owner;
projectIndex[_contract] = _projectId;
emit ProjectRegistered(_projectId, _owner, _contract, _contractType);
}
/// @inheritdoc IIndexer
function isProjectIndexRegistered(
bytes32 _projectId
) public view returns (bool) {
return projects[_projectId].owner != address(0);
}
/// @inheritdoc IIndexer
function isContractRegistered(
address _contract
) public view returns (bool) {
return projects[projectIndex[_contract]].owner != address(0);
}
/// @inheritdoc IIndexer
function getProjectOwner(bytes32 _projectId) public view returns (address) {
return projects[_projectId].owner;
}
function getProjectAddressOwner(
address _projectAddress
) public view returns (address) {
return projects[projectIndex[_projectAddress]].owner;
}
/// @inheritdoc IIndexer
function getProjectInfoByProjectAddress(
address _projectAddress
) public view returns (address, Contract[] memory) {
Project memory project = projects[projectIndex[_projectAddress]];
return (project.owner, project.contracts);
}
/// @inheritdoc IIndexer
function getProjectInfoByIndex(
bytes32 _projectId
) public view returns (address, Contract[] memory) {
Project memory project = projects[_projectId];
return (project.owner, project.contracts);
}
}
// 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) (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: UNLICENSED
pragma solidity ^0.8.24;
/// @title Payable
/// @author Smithii
import {IPayments} from "../interfaces/marketplace/IPayments.sol";
abstract contract Payable {
address public payments = address(0);
bytes32 public serviceId;
constructor(address _payments, string memory _serviceId) {
payments = _payments;
serviceId = keccak256(abi.encodePacked(_serviceId));
}
///
/// @param _projectId the project id
/// @param _token the token address
/// @param qty the qty of items to pay
function payService(
bytes32 _projectId,
address _token,
uint256 qty
) public payable {
IPayments(payments).payService{value: msg.value}(
_projectId,
_token,
serviceId,
qty
);
}
receive() external payable {}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/*
&&&&&& &&&&& &%
&&&&&&&&&&&&&&& && &&&&&&&&&&%
&&&&&&& &&&&& #&&&&&&&&&&&&&
&&&&& &&&&&&& && &&&& &% &&&&&&&
&&. &&&&&&&&&& & %&&&&&&& &&&&
&&&& *&&&&&&&&& &&&&&&&&& &&&&
.&&& &&&&&&&& &&&&&&&& &&&
.&&&&&&& &&&&&&& &&&%
&&&&&& &&&&&&
&&&&& /&&&&.
&&&& %&&& #&&&,
&&&&( &&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&
&&&% &&&&&&&&&&&&&&&&&&&&&&&&& &&&
&&& &&&* &&&&&&&&&&&&&&&&&&&&& &&*
&&& .&&&&&& &&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& #&&&&&& &&&&&&&&&&&&&&&&&&&&& &&&&& &&
&&& &&&& &&&&&&&&&&&&&&&&&&&&&& #&& &&&
&&& &&&&&&&&&&&&&&&&&&&&&&&&, *&&&
(&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&%
&&&&&&&&&&&&&&&&& &&&&&
&&&&&&&&&&&&&&&&&& %&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&#
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
*/
/*
* Payments contract
* This contract is used to pay the bills based on servicesId and projectId from the Indexer.
*/
/// @title Payments
/// @author Smithii
import {IPayments} from "../interfaces/marketplace/IPayments.sol";
import {Authorized} from "@privylabs/authorized/contracts/Authorized.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract Payments is IPayments, Authorized, ReentrancyGuard {
mapping(bytes32 => Service) public services;
/// projectId from indexer => contract address => serviceId => Invoice
mapping(bytes32 => mapping(address => mapping(bytes32 => Invoice[])))
public invoices;
constructor() {}
/// @inheritdoc IPayments
function addService(
bytes32 _serviceId,
uint256 _pricePerItem
) public onlyAuthorizedOperator {
services[_serviceId] = Service(_serviceId, _pricePerItem, false);
}
/// @inheritdoc IPayments
function setService(
bytes32 _serviceId,
bool _active
) public onlyAuthorizedOperator {
services[_serviceId].active = _active;
}
/// @inheritdoc IPayments
function payService(
bytes32 _projectId,
address _contract,
bytes32 _serviceId,
uint256 _qty
) public payable nonReentrant {
if (!services[_serviceId].active) revert ServiceNotActive(_serviceId);
uint256 total = services[_serviceId].pricePerItem * _qty;
if (msg.value != total) revert InvalidTotalAmount();
Invoice memory invoice = Invoice(
msg.sender,
services[_serviceId],
_qty,
total,
block.timestamp
);
invoices[_projectId][_contract][_serviceId].push(invoice);
emit ServicePaid(
_projectId,
_contract,
_serviceId,
msg.sender,
total,
block.timestamp
);
}
/// @inheritdoc IPayments
function withdraw(
bytes32 _projectId,
address _contract,
bytes32 _serviceId,
address payable _to
) public onlyAuthorizedAdmin {
Invoice[] memory _invoices = invoices[_projectId][_contract][
_serviceId
];
uint256 total = 0;
for (uint256 i = 0; i < _invoices.length; i++) {
total += _invoices[i].total;
}
_to.transfer(total);
emit ServiceWithdraw(_projectId, _contract, _serviceId, total);
}
/// @inheritdoc IPayments
function withdrawAll(address payable _to) public onlyOwner {
_to.transfer(address(this).balance);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/// @title Secured
/// @author Smithii
import {IERC20AntiBot} from "../interfaces/services/IERC20AntiBot.sol";
/// errors
error BotDetected();
abstract contract Secured {
address public antiBot = address(0);
constructor(address _antiBot) {
antiBot = _antiBot;
}
modifier noBots(address _from) {
if (IERC20AntiBot(antiBot).isBotDetected(_from)) revert BotDetected();
_;
}
/// Registers the block number of the receiver
/// @param _to the address to register
function registerBlock(address _to) internal {
IERC20AntiBot(antiBot).registerBlock(_to);
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
/// @title Whale Detector
/// @author Smithii
import {IERC20AntiWhale} from "../interfaces/services/IERC20AntiWhale.sol";
/// errors
error WhaleDetected();
abstract contract Shallowed {
address public antiWhale = address(0);
constructor(address _antiWhale) {
antiWhale = _antiWhale;
}
modifier noWhales(address _to, uint256 _amount) {
if (IERC20AntiWhale(antiWhale).isWhaleDetected(_to, _amount))
revert WhaleDetected();
_;
}
/// Registers the block number of the receiver
/// @param _to the address to register
function registerBlockTimeStamp(address _to) internal {
IERC20AntiWhale(antiWhale).registerBlockTimeStamp(_to);
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
library TransferHelper {
/// @notice Transfers tokens from the targeted address to the given destination
/// @notice Errors with 'STF' if transfer fails
/// @param token The contract address of the token to be transferred
/// @param from The originating address from which the tokens will be transferred
/// @param to The destination address of the transfer
/// @param value The amount to be transferred
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) =
token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
}
/// @notice Transfers tokens from msg.sender to a recipient
/// @dev Errors with ST if transfer fails
/// @param token The contract address of the token which will be transferred
/// @param to The recipient of the transfer
/// @param value The value of the transfer
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
}
/// @notice Approves the stipulated contract to spend the given allowance in the given token
/// @dev Errors with 'SA' if transfer fails
/// @param token The contract address of the token to be approved
/// @param to The target of the approval
/// @param value The amount of the given token the target will be allowed to spend
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
}
/// @notice Transfers ETH to the recipient address
/// @dev Fails with `STE`
/// @param to The destination of the transfer
/// @param value The value to be transferred
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'STE');
}
}
// SPDX-License-Identifier: MIT
// 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);
}
{
"compilationTarget": {
"contracts/tokens/ERC20/ERC20Template.sol": "ERC20Template"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_taxAddress","type":"address"},{"internalType":"address","name":"_antiBot","type":"address"},{"internalType":"address","name":"_antiWhale","type":"address"},{"internalType":"uint256","name":"_initialSupply","type":"uint256"},{"internalType":"uint256","name":"_taxFee","type":"uint256"},{"internalType":"bool","name":"_isAirdrop","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"BlacklistedAddress","type":"error"},{"inputs":[],"name":"BotDetected","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":[],"name":"InvalidInitialSupply","type":"error"},{"inputs":[],"name":"InvalidTaxFee","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"WhaleDetected","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":"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":"DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"antiBot","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"antiWhale","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"address","name":"","type":"address"}],"name":"blackList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[],"name":"initialSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isAirdrop","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"noTaxable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"releaseAirdropMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_blackList","type":"bool"}],"name":"setBlackList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_taxable","type":"bool"}],"name":"setNotTaxable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_taxAddress","type":"address"}],"name":"setTaxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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"}]