// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/* ===== Library: ECDSA (versión mínima) ===== */
library ECDSA {
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
if (signature.length != 65) revert("ECDSA: longitud invalida");
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 32))
s := mload(add(signature, 64))
v := byte(0, mload(add(signature, 96)))
}
require(uint256(s) <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "ECDSA: valor s invalido");
require(v == 27 || v == 28, "ECDSA: valor v invalido");
address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "ECDSA: firma invalida");
return signer;
}
}
/* ===== Contract: Context ===== */
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
/* ===== Contract: Ownable ===== */
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
/* ===== Contract: ERC20 (versión mínima) ===== */
contract ERC20 is Context {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public pure returns (uint8) {
return 18;
}
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
_transfer(_msgSender(), to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
uint256 currentAllowance = _allowances[from][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
_transfer(from, to, amount);
_approve(from, _msgSender(), currentAllowance - amount);
return true;
}
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from zero address");
require(to != address(0), "ERC20: transfer to zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from zero address");
require(spender != address(0), "ERC20: approve to zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
// Hook que se llama antes de cualquier transferencia, mint o burn.
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
/* ===== Contract: EIP712 ===== */
abstract contract EIP712 {
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
constructor(string memory name, string memory version) {
_HASHED_NAME = keccak256(bytes(name));
_HASHED_VERSION = keccak256(bytes(version));
_TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
function _domainSeparatorV4() internal view returns (bytes32) {
return block.chainid == _CACHED_CHAIN_ID ? _CACHED_DOMAIN_SEPARATOR : _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
}
}
/* ===== Contract: ERC20Permit ===== */
abstract contract ERC20Permit is ERC20, EIP712 {
mapping(address => uint256) public nonces;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
bytes32 public constant PERMIT_TYPEHASH = 0x6a761202d1a982bec02486d3d0f4394af28b31a1a1f7dfaa680c15c02d7c5f8c;
constructor(string memory name) EIP712(name, "1") { }
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(block.timestamp <= deadline, "ERC20Permit: deadline expirada");
bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, abi.encodePacked(r, s, v));
require(signer == owner, "ERC20Permit: firma invalida");
_approve(owner, spender, value);
}
}
/* ===== Contract: ERC20Snapshot (versión básica) ===== */
abstract contract ERC20Snapshot is ERC20 {
struct Snapshot {
uint256 id;
uint256 value;
}
mapping(address => Snapshot[]) private _accountSnapshots;
Snapshot[] private _totalSupplySnapshots;
uint256 internal _currentSnapshotId;
event SnapshotCreated(uint256 id);
// Cambiado a "public" para permitir llamadas internas con super.snapshot()
function snapshot() public virtual returns (uint256) {
_currentSnapshotId++;
_updateTotalSupplySnapshot();
emit SnapshotCreated(_currentSnapshotId);
return _currentSnapshotId;
}
function balanceOfAt(address account, uint256 snapshotId) external view returns (uint256) {
return _valueAt(snapshotId, _accountSnapshots[account]);
}
function totalSupplyAt(uint256 snapshotId) external view returns (uint256) {
return _valueAt(snapshotId, _totalSupplySnapshots);
}
function _valueAt(uint256 snapshotId, Snapshot[] storage snapshots) private view returns (uint256) {
uint256 len = snapshots.length;
if (len == 0) return 0;
uint256 lower = 0;
uint256 upper = len;
while (lower < upper) {
uint256 mid = (lower + upper) / 2;
if (snapshots[mid].id <= snapshotId) {
lower = mid + 1;
} else {
upper = mid;
}
}
if (lower == 0) return 0;
else return snapshots[lower - 1].value;
}
function _updateAccountSnapshot(address account, uint256 newBalance) internal {
Snapshot[] storage snapshots = _accountSnapshots[account];
uint256 len = snapshots.length;
if (len == 0 || snapshots[len - 1].id < _currentSnapshotId) {
snapshots.push(Snapshot(_currentSnapshotId, newBalance));
} else {
snapshots[len - 1].value = newBalance;
}
}
function _updateTotalSupplySnapshot() internal {
uint256 newTotalSupply = totalSupply();
uint256 len = _totalSupplySnapshots.length;
if (len == 0 || _totalSupplySnapshots[len - 1].id < _currentSnapshotId) {
_totalSupplySnapshots.push(Snapshot(_currentSnapshotId, newTotalSupply));
} else {
_totalSupplySnapshots[len - 1].value = newTotalSupply;
}
}
// Hook llamado en cada transferencia, mint o burn.
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
super._beforeTokenTransfer(from, to, amount);
if (from == address(0)) {
// mint
_updateTotalSupplySnapshot();
if (to != address(0)) {
_updateAccountSnapshot(to, balanceOf(to) + amount);
}
} else if (to == address(0)) {
// burn
_updateAccountSnapshot(from, balanceOf(from) - amount);
_updateTotalSupplySnapshot();
} else {
if (from != address(0)) {
_updateAccountSnapshot(from, balanceOf(from) - amount);
}
if (to != address(0)) {
_updateAccountSnapshot(to, balanceOf(to) + amount);
}
}
}
}
/* ===== Contract: ADRIANToken ===== */
contract ADRIANToken is ERC20Snapshot, ERC20Permit, Ownable {
// Constant para basis points (10,000 = 100%)
uint256 public constant BASIS_POINTS = 10000;
// Fees en basis points
uint256 public taxFee; // Ej: 50 equivale a 0.5%
uint256 public creatorFee; // Ej: 50 equivale a 0.5%
uint256 public burnFee; // Ej: 50 equivale a 0.5%
// Direcciones para recibir fees
address public taxAddress;
address public creatorAddress;
// Mapping para exención de fees
mapping(address => bool) public isFeeExempt;
// Variables para staking
mapping(address => uint256) public stakedBalance;
mapping(address => uint256) public stakingStart;
uint256 public rewardRate; // tasa de recompensa por segundo (escala 1e18)
event TaxFeeUpdated(uint256 newTaxFee);
event CreatorFeeUpdated(uint256 newCreatorFee);
event BurnFeeUpdated(uint256 newBurnFee);
event TaxAddressUpdated(address newTaxAddress);
event CreatorAddressUpdated(address newCreatorAddress);
event FeeExemptionUpdated(address indexed account, bool isExempt);
event Staked(address indexed staker, uint256 amount);
event WithdrawnStake(address indexed staker, uint256 amount, uint256 reward);
event RewardRateUpdated(uint256 newRewardRate);
event GalleryAction(address indexed from, address indexed to, uint256 amount, string action);
constructor(
string memory name,
string memory symbol,
uint256 initialSupply,
uint256 _taxFee, // En basis points (ej. 50 para 0.5%)
uint256 _creatorFee, // En basis points
uint256 _burnFee, // En basis points
address _taxAddress,
address _creatorAddress,
uint256 _rewardRate // Ej: 1e16 equivale a 0.01 por segundo
)
ERC20(name, symbol)
ERC20Permit(name)
{
require(initialSupply > 0, "Initial supply > 0");
// La suma de fees no debe exceder BASIS_POINTS (100%)
require(_taxFee + _creatorFee + _burnFee <= BASIS_POINTS, "Suma de fees > 100%");
taxFee = _taxFee;
creatorFee = _creatorFee;
burnFee = _burnFee;
taxAddress = _taxAddress;
creatorAddress = _creatorAddress;
rewardRate = _rewardRate;
// Eximir de fees: owner, taxAddress, creatorAddress y el contrato (para staking interno)
isFeeExempt[_msgSender()] = true;
isFeeExempt[_taxAddress] = true;
isFeeExempt[_creatorAddress] = true;
isFeeExempt[address(this)] = true;
_mint(_msgSender(), initialSupply);
}
// Override de _transfer para aplicar fees: TAX, CREATOR y BURN
function _transfer(address sender, address recipient, uint256 amount) internal virtual override {
uint256 feeTotal = 0;
uint256 taxAmount = 0;
uint256 creatorAmount = 0;
uint256 burnAmount = 0;
if (!isFeeExempt[sender]) {
if (taxFee > 0) {
taxAmount = (amount * taxFee) / BASIS_POINTS;
super._transfer(sender, taxAddress, taxAmount);
feeTotal += taxAmount;
}
if (creatorFee > 0) {
creatorAmount = (amount * creatorFee) / BASIS_POINTS;
super._transfer(sender, creatorAddress, creatorAmount);
feeTotal += creatorAmount;
}
if (burnFee > 0) {
burnAmount = (amount * burnFee) / BASIS_POINTS;
_burn(sender, burnAmount);
feeTotal += burnAmount;
}
}
super._transfer(sender, recipient, amount - feeTotal);
}
// Funciones para actualizar fees y direcciones
function updateTaxFee(uint256 _newTaxFee) external onlyOwner {
require(_newTaxFee + creatorFee + burnFee <= BASIS_POINTS, "Suma de fees > 100%");
taxFee = _newTaxFee;
emit TaxFeeUpdated(_newTaxFee);
}
function updateCreatorFee(uint256 _newCreatorFee) external onlyOwner {
require(taxFee + _newCreatorFee + burnFee <= BASIS_POINTS, "Suma de fees > 100%");
creatorFee = _newCreatorFee;
emit CreatorFeeUpdated(_newCreatorFee);
}
function updateBurnFee(uint256 _newBurnFee) external onlyOwner {
require(taxFee + creatorFee + _newBurnFee <= BASIS_POINTS, "Suma de fees > 100%");
burnFee = _newBurnFee;
emit BurnFeeUpdated(_newBurnFee);
}
function updateTaxAddress(address _newTaxAddress) external onlyOwner {
taxAddress = _newTaxAddress;
isFeeExempt[_newTaxAddress] = true;
emit TaxAddressUpdated(_newTaxAddress);
}
function updateCreatorAddress(address _newCreatorAddress) external onlyOwner {
creatorAddress = _newCreatorAddress;
isFeeExempt[_newCreatorAddress] = true;
emit CreatorAddressUpdated(_newCreatorAddress);
}
function setFeeExemption(address account, bool exempt) external onlyOwner {
isFeeExempt[account] = exempt;
emit FeeExemptionUpdated(account, exempt);
}
// Función snapshot protegida por onlyOwner
function snapshot() public override onlyOwner returns (uint256) {
return super.snapshot();
}
// Funciones de staking
// Permite al usuario bloquear (stake) tokens. Se transfieren al contrato (sin fees por exención)
function stake(uint256 amount) external {
require(amount > 0, "Stake amount must be > 0");
super._transfer(_msgSender(), address(this), amount);
stakedBalance[_msgSender()] += amount;
if (stakingStart[_msgSender()] == 0) {
stakingStart[_msgSender()] = block.timestamp;
}
emit Staked(_msgSender(), amount);
}
// Calcula la recompensa acumulada para un staker en función del tiempo transcurrido
function calculateReward(address staker) public view returns (uint256) {
uint256 timeElapsed = block.timestamp - stakingStart[staker];
return (stakedBalance[staker] * rewardRate * timeElapsed) / 1e18;
}
// Permite retirar el stake y reclamar la recompensa acumulada
function withdrawStake() external {
uint256 staked = stakedBalance[_msgSender()];
require(staked > 0, "No staked tokens");
uint256 reward = calculateReward(_msgSender());
stakedBalance[_msgSender()] = 0;
stakingStart[_msgSender()] = 0;
super._transfer(address(this), _msgSender(), staked + reward);
emit WithdrawnStake(_msgSender(), staked, reward);
}
// Permite actualizar la tasa de recompensa
function updateRewardRate(uint256 _newRewardRate) external onlyOwner {
rewardRate = _newRewardRate;
emit RewardRateUpdated(_newRewardRate);
}
// Función extra para futuras integraciones (por ejemplo, ADRIAN GALLERY)
function galleryAction(string calldata actionDescription) external {
emit GalleryAction(_msgSender(), address(0), 0, actionDescription);
}
// Override de _beforeTokenTransfer para integrar la lógica de snapshot
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override(ERC20, ERC20Snapshot) {
ERC20Snapshot._beforeTokenTransfer(from, to, amount);
}
}
{
"compilationTarget": {
"ADRIANToken.sol": "ADRIANToken"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"_taxFee","type":"uint256"},{"internalType":"uint256","name":"_creatorFee","type":"uint256"},{"internalType":"uint256","name":"_burnFee","type":"uint256"},{"internalType":"address","name":"_taxAddress","type":"address"},{"internalType":"address","name":"_creatorAddress","type":"address"},{"internalType":"uint256","name":"_rewardRate","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newBurnFee","type":"uint256"}],"name":"BurnFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newCreatorAddress","type":"address"}],"name":"CreatorAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCreatorFee","type":"uint256"}],"name":"CreatorFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"isExempt","type":"bool"}],"name":"FeeExemptionUpdated","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":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"action","type":"string"}],"name":"GalleryAction","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":"uint256","name":"newRewardRate","type":"uint256"}],"name":"RewardRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"SnapshotCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTaxAddress","type":"address"}],"name":"TaxAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newTaxFee","type":"uint256"}],"name":"TaxFeeUpdated","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":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"WithdrawnStake","type":"event"},{"inputs":[],"name":"BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"snapshotId","type":"uint256"}],"name":"balanceOfAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"calculateReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creatorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creatorFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"actionDescription","type":"string"}],"name":"galleryAction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isFeeExempt","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":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"exempt","type":"bool"}],"name":"setFeeExemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"snapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakingStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"uint256","name":"snapshotId","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newBurnFee","type":"uint256"}],"name":"updateBurnFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newCreatorAddress","type":"address"}],"name":"updateCreatorAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCreatorFee","type":"uint256"}],"name":"updateCreatorFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newRewardRate","type":"uint256"}],"name":"updateRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newTaxAddress","type":"address"}],"name":"updateTaxAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newTaxFee","type":"uint256"}],"name":"updateTaxFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"}]