// 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: UNLICENSED
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
interface TokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes calldata _extraData) external;
}
contract ESXAToken is IERC20, Ownable, Pausable {
struct LockupInfo {
uint256 releaseTime;
uint256 termOfRound;
uint256 unlockAmountPerRound;
uint256 lockupBalance;
}
string public name;
string public symbol;
uint8 constant public decimals =18;
uint256 internal initialSupply;
uint256 internal totalSupply_;
mapping(address => uint256) internal balances;
mapping(address => bool) internal locks;
mapping(address => bool) public frozen;
mapping(address => mapping(address => uint256)) internal allowed;
mapping(address => LockupInfo[]) internal lockupInfo;
event Lock(address indexed holder, uint256 value);
event Unlock(address indexed holder, uint256 value);
event Burn(address indexed owner, uint256 value);
modifier notFrozen(address _holder) {
require(!frozen[_holder], "Account is frozen");
_;
}
constructor() Ownable(msg.sender) {
name = "EstaliaX";
symbol = "ESXA";
initialSupply = 1*(10**9);
totalSupply_ = initialSupply * 10 ** uint(decimals);
balances[msg.sender] = totalSupply_;
emit Transfer(address(0), msg.sender, totalSupply_);
}
// Fallback
receive() external payable {
revert("Direct ETH transfer not allowed");
}
fallback() external payable {
revert("Direct ETH transfer not allowed");
}
function totalSupply() public view override returns (uint256) {
return totalSupply_;
}
function transfer(address _to, uint256 _value) public override whenNotPaused notFrozen(msg.sender) returns (bool) {
if (locks[msg.sender]) {
autoUnlock(msg.sender);
}
require(_to != address(0), "Cannot transfer to zero address");
require(_value <= balances[msg.sender], "Insufficient balance");
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender] - _value;
balances[_to] = balances[_to] + _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function balanceOf(address _holder) public view override returns (uint256 balance) {
uint256 lockedBalance = 0;
if(locks[_holder]) {
for(uint256 idx = 0; idx < lockupInfo[_holder].length ; idx++ ) {
lockedBalance = lockedBalance + lockupInfo[_holder][idx].lockupBalance;
}
}
return balances[_holder] + lockedBalance;
}
function transferFrom(address _from, address _to, uint256 _value) public override whenNotPaused notFrozen(_from) returns (bool) {
if (locks[_from]) {
autoUnlock(_from);
}
require(_to != address(0), "Cannot transfer to zero address");
require(_value <= balances[_from], "Insufficient balance");
require(_value <= allowed[_from][msg.sender], "Insufficient allowance");
balances[_from] = balances[_from] - _value;
balances[_to] = balances[_to] + _value;
allowed[_from][msg.sender] = allowed[_from][msg.sender] - _value;
emit Transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public override whenNotPaused returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function approveAndCall(address _spender, uint256 _value, bytes memory _extraData) public returns (bool success) {
require(isContract(_spender), "Spender must be a contract");
TokenRecipient spender = TokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, address(this), _extraData);
return true;
}
return false;
}
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
require(spender != address(0), "Cannot approve zero address");
allowed[msg.sender][spender] = (allowed[msg.sender][spender] + addedValue);
emit Approval(msg.sender, spender, allowed[msg.sender][spender]);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
require(spender != address(0), "Cannot approve zero address");
allowed[msg.sender][spender] = (allowed[msg.sender][spender] - subtractedValue);
emit Approval(msg.sender, spender, allowed[msg.sender][spender]);
return true;
}
function allowance(address _holder, address _spender) public view override returns (uint256) {
return allowed[_holder][_spender];
}
function lock(address _holder, uint256 _amount, uint256 _releaseStart, uint256 _termOfRound, uint256 _releaseRate) public onlyOwner returns (bool) {
require(balances[_holder] >= _amount, "Insufficient balance for lock");
if(_termOfRound==0 ) {
_termOfRound = 1;
}
balances[_holder] = balances[_holder] - _amount;
lockupInfo[_holder].push(
LockupInfo(_releaseStart, _termOfRound, _amount * _releaseRate / 100, _amount)
);
locks[_holder] = true;
emit Lock(_holder, _amount);
return true;
}
function unlock(address _holder, uint256 _idx) public onlyOwner returns (bool) {
require(locks[_holder], "Account not locked");
require(_idx < lockupInfo[_holder].length, "Invalid lockup index");
LockupInfo storage lockupinfo = lockupInfo[_holder][_idx];
uint256 releaseAmount = lockupinfo.lockupBalance;
delete lockupInfo[_holder][_idx];
lockupInfo[_holder][_idx] = lockupInfo[_holder][lockupInfo[_holder].length - 1];
lockupInfo[_holder].pop();
if(lockupInfo[_holder].length == 0) {
locks[_holder] = false;
}
emit Unlock(_holder, releaseAmount);
balances[_holder] = balances[_holder] + releaseAmount;
return true;
}
function getNowTime() public view returns(uint256) {
return block.timestamp;
}
function showLockState(address _holder, uint256 _idx) public view returns (bool, uint256, uint256, uint256, uint256, uint256) {
if(locks[_holder]) {
return (
locks[_holder],
lockupInfo[_holder].length,
lockupInfo[_holder][_idx].lockupBalance,
lockupInfo[_holder][_idx].releaseTime,
lockupInfo[_holder][_idx].termOfRound,
lockupInfo[_holder][_idx].unlockAmountPerRound
);
} else {
return (
locks[_holder],
lockupInfo[_holder].length,
0,0,0,0
);
}
}
function distribute(address _to, uint256 _value) public onlyOwner returns (bool) {
require(_to != address(0), "Cannot distribute to zero address");
require(_value <= balances[owner()], "Insufficient balance");
balances[owner()] = balances[owner()] - _value;
balances[_to] = balances[_to] + _value;
emit Transfer(owner(), _to, _value);
return true;
}
function distributeWithLockup(address _to, uint256 _value, uint256 _releaseStart, uint256 _termOfRound, uint256 _releaseRate) public onlyOwner returns (bool) {
distribute(_to, _value);
lock(_to, _value, _releaseStart, _termOfRound, _releaseRate);
return true;
}
function claimToken(IERC20 token, address _to, uint256 _value) public onlyOwner returns (bool) {
token.transfer(_to, _value);
return true;
}
function burn(uint256 _value) public onlyOwner returns (bool success) {
require(_value <= balances[msg.sender], "Insufficient balance");
address burner = msg.sender;
balances[burner] = balances[burner] - _value;
totalSupply_ = totalSupply_ - _value;
emit Burn(burner, _value);
emit Transfer(burner, address(0), _value);
return true;
}
function isContract(address addr) internal view returns (bool) {
uint size;
assembly {size := extcodesize(addr)}
return size > 0;
}
function autoUnlock(address _holder) internal returns (bool) {
for(uint256 idx = 0; idx < lockupInfo[_holder].length;) {
if(locks[_holder] == false) {
return true;
}
if (lockupInfo[_holder][idx].releaseTime <= block.timestamp) {
if(releaseTimeLock(_holder, idx)) {
} else {
idx++;
}
} else {
idx++;
}
}
return true;
}
function releaseTimeLock(address _holder, uint256 _idx) internal returns(bool) {
require(locks[_holder], "Account not locked");
require(_idx < lockupInfo[_holder].length, "Invalid lockup index");
LockupInfo storage info = lockupInfo[_holder][_idx];
uint256 releaseAmount = info.unlockAmountPerRound;
uint256 sinceFrom;
if (block.timestamp > info.releaseTime) {
sinceFrom = block.timestamp - info.releaseTime;
} else {
sinceFrom = 0;
}
uint256 sinceRound;
if (info.termOfRound > 0) {
sinceRound = sinceFrom / info.termOfRound;
} else {
sinceRound = 0;
}
releaseAmount = releaseAmount + (sinceRound * info.unlockAmountPerRound);
if(releaseAmount >= info.lockupBalance) {
releaseAmount = info.lockupBalance;
if(_idx < lockupInfo[_holder].length - 1) {
lockupInfo[_holder][_idx] = lockupInfo[_holder][lockupInfo[_holder].length - 1];
}
lockupInfo[_holder].pop();
if(lockupInfo[_holder].length == 0) {
locks[_holder] = false;
}
emit Unlock(_holder, releaseAmount);
balances[_holder] = balances[_holder] + releaseAmount;
return true;
} else {
if (info.termOfRound > 0 && sinceRound > 0) {
info.releaseTime = info.releaseTime + ((sinceRound + 1) * info.termOfRound);
}
info.lockupBalance = info.lockupBalance - releaseAmount;
emit Unlock(_holder, releaseAmount);
balances[_holder] = balances[_holder] + releaseAmount;
return false;
}
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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());
}
}
{
"compilationTarget": {
"contracts/ESXAToken.sol": "ESXAToken"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Lock","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":true,"internalType":"address","name":"holder","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Unlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"claimToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"distribute","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_releaseStart","type":"uint256"},{"internalType":"uint256","name":"_termOfRound","type":"uint256"},{"internalType":"uint256","name":"_releaseRate","type":"uint256"}],"name":"distributeWithLockup","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNowTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_releaseStart","type":"uint256"},{"internalType":"uint256","name":"_termOfRound","type":"uint256"},{"internalType":"uint256","name":"_releaseRate","type":"uint256"}],"name":"lock","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"showLockState","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"},{"internalType":"uint256","name":"_idx","type":"uint256"}],"name":"unlock","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]