ERC-20
Overview
Max Total Supply
27,915,401.738738451908998809 Speed
Holders
75
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Balance
3,465,941.340042523339344706 SpeedValue
$0.00Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Minimal Proxy Contract for 0x7f9f70da4af54671a6abac58e705b5634cac8819
Contract Name:
InterchainToken
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 1000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { AddressBytes } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/AddressBytes.sol'; import { IInterchainToken } from '../interfaces/IInterchainToken.sol'; import { InterchainTokenStandard } from './InterchainTokenStandard.sol'; import { ERC20 } from './ERC20.sol'; import { ERC20Permit } from './ERC20Permit.sol'; import { Minter } from '../utils/Minter.sol'; /** * @title InterchainToken * @notice This contract implements an interchain token which extends InterchainToken functionality. * @dev This contract also inherits Minter and Implementation logic. */ contract InterchainToken is InterchainTokenStandard, ERC20, ERC20Permit, Minter, IInterchainToken { using AddressBytes for bytes; string public name; string public symbol; uint8 public decimals; bytes32 internal tokenId; address internal immutable interchainTokenService_; // bytes32(uint256(keccak256('interchain-token-initialized')) - 1); bytes32 internal constant INITIALIZED_SLOT = 0xc778385ecb3e8cecb82223fa1f343ec6865b2d64c65b0c15c7e8aef225d9e214; /** * @notice Constructs the InterchainToken contract. * @dev Makes the implementation act as if it has been setup already to disallow calls to init() (even though that would not achieve anything really). */ constructor(address interchainTokenServiceAddress) { _initialize(); if (interchainTokenServiceAddress == address(0)) revert InterchainTokenServiceAddressZero(); interchainTokenService_ = interchainTokenServiceAddress; } /** * @notice Returns true if the contract has been setup. * @return initialized True if the contract has been setup, false otherwise. */ function _isInitialized() internal view returns (bool initialized) { assembly { initialized := sload(INITIALIZED_SLOT) } } /** * @notice Sets initialized to true, to allow only a single init. */ function _initialize() internal { assembly { sstore(INITIALIZED_SLOT, true) } } /** * @notice Returns the interchain token service * @return address The interchain token service contract */ function interchainTokenService() public view override(InterchainTokenStandard, IInterchainToken) returns (address) { return interchainTokenService_; } /** * @notice Returns the tokenId for this token. * @return bytes32 The token manager contract. */ function interchainTokenId() public view override(InterchainTokenStandard, IInterchainToken) returns (bytes32) { return tokenId; } /** * @notice Setup function to initialize contract parameters. * @param tokenId_ The tokenId of the token. * @param minter The address of the token minter. * @param tokenName The name of the token. * @param tokenSymbol The symbopl of the token. * @param tokenDecimals The decimals of the token. */ function init(bytes32 tokenId_, address minter, string calldata tokenName, string calldata tokenSymbol, uint8 tokenDecimals) external { if (_isInitialized()) revert AlreadyInitialized(); _initialize(); if (tokenId_ == bytes32(0)) revert TokenIdZero(); if (bytes(tokenName).length == 0) revert TokenNameEmpty(); if (bytes(tokenSymbol).length == 0) revert TokenSymbolEmpty(); name = tokenName; symbol = tokenSymbol; decimals = tokenDecimals; tokenId = tokenId_; /** * @dev Set the token service as a minter to allow it to mint and burn tokens. * Also add the provided address as a minter. If `address(0)` was provided, * add it as a minter to allow anyone to easily check that no custom minter was set. */ _addMinter(interchainTokenService_); _addMinter(minter); _setNameHash(tokenName); } /** * @notice Function to mint new tokens. * @dev Can only be called by the minter address. * @param account The address that will receive the minted tokens. * @param amount The amount of tokens to mint. */ function mint(address account, uint256 amount) external onlyRole(uint8(Roles.MINTER)) { _mint(account, amount); } /** * @notice Function to burn tokens. * @dev Can only be called by the minter address. * @param account The address that will have its tokens burnt. * @param amount The amount of tokens to burn. */ function burn(address account, uint256 amount) external onlyRole(uint8(Roles.MINTER)) { _burn(account, amount); } /** * @notice A method to be overwritten that will decrease the allowance of the `spender` from `sender` by `amount`. * @dev Needs to be overwritten. This provides flexibility for the choice of ERC20 implementation used. Must revert if allowance is not sufficient. */ function _spendAllowance(address sender, address spender, uint256 amount) internal override { uint256 _allowance = allowance[sender][spender]; if (_allowance != UINT256_MAX) { _approve(sender, spender, _allowance - amount); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; interface IERC20Permit { function DOMAIN_SEPARATOR() external view returns (bytes32); function nonces(address account) external view returns (uint256); function permit( address issuer, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { error InvalidAccount(); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IRolesBase Interface * @notice IRolesBase is an interface that abstracts the implementation of a * contract with role control internal functions. */ interface IRolesBase { error MissingRole(address account, uint8 role); error MissingAllRoles(address account, uint256 accountRoles); error MissingAnyOfRoles(address account, uint256 accountRoles); error InvalidProposedRoles(address fromAccount, address toAccount, uint256 accountRoles); event RolesProposed(address indexed fromAccount, address indexed toAccount, uint256 accountRoles); event RolesAdded(address indexed account, uint256 accountRoles); event RolesRemoved(address indexed account, uint256 accountRoles); /** * @notice Checks if an account has a role. * @param account The address to check * @param role The role to check * @return True if the account has the role, false otherwise */ function hasRole(address account, uint8 role) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title AddressBytesUtils * @dev This library provides utility functions to convert between `address` and `bytes`. */ library AddressBytes { error InvalidBytesLength(bytes bytesAddress); /** * @dev Converts a bytes address to an address type. * @param bytesAddress The bytes representation of an address * @return addr The converted address */ function toAddress(bytes memory bytesAddress) internal pure returns (address addr) { if (bytesAddress.length != 20) revert InvalidBytesLength(bytesAddress); assembly { addr := mload(add(bytesAddress, 20)) } } /** * @dev Converts an address to bytes. * @param addr The address to be converted * @return bytesAddress The bytes representation of the address */ function toBytes(address addr) internal pure returns (bytes memory bytesAddress) { bytesAddress = new bytes(20); // we can test if using a single 32 byte variable that is the address with the length together and using one mstore would be slightly cheaper. assembly { mstore(add(bytesAddress, 20), addr) mstore(bytesAddress, 20) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IRolesBase } from '../interfaces/IRolesBase.sol'; /** * @title RolesBase * @notice A contract module which provides a set if internal functions * for implementing role control features. */ contract RolesBase is IRolesBase { bytes32 internal constant ROLES_PREFIX = keccak256('roles'); bytes32 internal constant PROPOSE_ROLES_PREFIX = keccak256('propose-roles'); /** * @notice Modifier that throws an error if called by any account missing the role. */ modifier onlyRole(uint8 role) { if (!_hasRole(_getRoles(msg.sender), role)) revert MissingRole(msg.sender, role); _; } /** * @notice Modifier that throws an error if called by an account without all the roles. */ modifier withEveryRole(uint8[] memory roles) { uint256 accountRoles = _toAccountRoles(roles); if (!_hasAllTheRoles(_getRoles(msg.sender), accountRoles)) revert MissingAllRoles(msg.sender, accountRoles); _; } /** * @notice Modifier that throws an error if called by an account without any of the roles. */ modifier withAnyRole(uint8[] memory roles) { uint256 accountRoles = _toAccountRoles(roles); if (!_hasAnyOfRoles(_getRoles(msg.sender), accountRoles)) revert MissingAnyOfRoles(msg.sender, accountRoles); _; } /** * @notice Checks if an account has a role. * @param account The address to check * @param role The role to check * @return True if the account has the role, false otherwise */ function hasRole(address account, uint8 role) public view returns (bool) { return _hasRole(_getRoles(account), role); } /** * @notice Internal function to convert an array of roles to a uint256. * @param roles The roles to convert * @return accountRoles The roles in uint256 format */ function _toAccountRoles(uint8[] memory roles) internal pure returns (uint256) { uint256 length = roles.length; uint256 accountRoles; for (uint256 i = 0; i < length; ++i) { accountRoles |= (1 << roles[i]); } return accountRoles; } /** * @notice Internal function to get the key of the roles mapping. * @param account The address to get the key for * @return key The key of the roles mapping */ function _rolesKey(address account) internal view virtual returns (bytes32 key) { return keccak256(abi.encodePacked(ROLES_PREFIX, account)); } /** * @notice Internal function to get the roles of an account. * @param account The address to get the roles for * @return accountRoles The roles of the account in uint256 format */ function _getRoles(address account) internal view returns (uint256 accountRoles) { bytes32 key = _rolesKey(account); assembly { accountRoles := sload(key) } } /** * @notice Internal function to set the roles of an account. * @param account The address to set the roles for * @param accountRoles The roles to set */ function _setRoles(address account, uint256 accountRoles) private { bytes32 key = _rolesKey(account); assembly { sstore(key, accountRoles) } } /** * @notice Internal function to get the key of the proposed roles mapping. * @param fromAccount The address of the current role * @param toAccount The address of the pending role * @return key The key of the proposed roles mapping */ function _proposalKey(address fromAccount, address toAccount) internal view virtual returns (bytes32 key) { return keccak256(abi.encodePacked(PROPOSE_ROLES_PREFIX, fromAccount, toAccount)); } /** * @notice Internal function to get the proposed roles of an account. * @param fromAccount The address of the current role * @param toAccount The address of the pending role * @return proposedRoles_ The proposed roles of the account in uint256 format */ function _getProposedRoles(address fromAccount, address toAccount) internal view returns (uint256 proposedRoles_) { bytes32 key = _proposalKey(fromAccount, toAccount); assembly { proposedRoles_ := sload(key) } } /** * @notice Internal function to set the proposed roles of an account. * @param fromAccount The address of the current role * @param toAccount The address of the pending role * @param proposedRoles_ The proposed roles to set in uint256 format */ function _setProposedRoles( address fromAccount, address toAccount, uint256 proposedRoles_ ) private { bytes32 key = _proposalKey(fromAccount, toAccount); assembly { sstore(key, proposedRoles_) } } /** * @notice Internal function to add a role to an account. * @dev emits a RolesAdded event. * @param account The address to add the role to * @param role The role to add */ function _addRole(address account, uint8 role) internal { _addAccountRoles(account, 1 << role); } /** * @notice Internal function to add roles to an account. * @dev emits a RolesAdded event. * @dev Called in the constructor to set the initial roles. * @param account The address to add roles to * @param roles The roles to add */ function _addRoles(address account, uint8[] memory roles) internal { _addAccountRoles(account, _toAccountRoles(roles)); } /** * @notice Internal function to add roles to an account. * @dev emits a RolesAdded event. * @dev Called in the constructor to set the initial roles. * @param account The address to add roles to * @param accountRoles The roles to add */ function _addAccountRoles(address account, uint256 accountRoles) internal { uint256 newAccountRoles = _getRoles(account) | accountRoles; _setRoles(account, newAccountRoles); emit RolesAdded(account, accountRoles); } /** * @notice Internal function to remove a role from an account. * @dev emits a RolesRemoved event. * @param account The address to remove the role from * @param role The role to remove */ function _removeRole(address account, uint8 role) internal { _removeAccountRoles(account, 1 << role); } /** * @notice Internal function to remove roles from an account. * @dev emits a RolesRemoved event. * @param account The address to remove roles from * @param roles The roles to remove */ function _removeRoles(address account, uint8[] memory roles) internal { _removeAccountRoles(account, _toAccountRoles(roles)); } /** * @notice Internal function to remove roles from an account. * @dev emits a RolesRemoved event. * @param account The address to remove roles from * @param accountRoles The roles to remove */ function _removeAccountRoles(address account, uint256 accountRoles) internal { uint256 newAccountRoles = _getRoles(account) & ~accountRoles; _setRoles(account, newAccountRoles); emit RolesRemoved(account, accountRoles); } /** * @notice Internal function to check if an account has a role. * @param accountRoles The roles of the account in uint256 format * @param role The role to check * @return True if the account has the role, false otherwise */ function _hasRole(uint256 accountRoles, uint8 role) internal pure returns (bool) { return accountRoles & (1 << role) != 0; } /** * @notice Internal function to check if an account has all the roles. * @param hasAccountRoles The roles of the account in uint256 format * @param mustHaveAccountRoles The roles the account must have * @return True if the account has all the roles, false otherwise */ function _hasAllTheRoles(uint256 hasAccountRoles, uint256 mustHaveAccountRoles) internal pure returns (bool) { return (hasAccountRoles & mustHaveAccountRoles) == mustHaveAccountRoles; } /** * @notice Internal function to check if an account has any of the roles. * @param hasAccountRoles The roles of the account in uint256 format * @param mustHaveAnyAccountRoles The roles to check in uint256 format * @return True if the account has any of the roles, false otherwise */ function _hasAnyOfRoles(uint256 hasAccountRoles, uint256 mustHaveAnyAccountRoles) internal pure returns (bool) { return (hasAccountRoles & mustHaveAnyAccountRoles) != 0; } /** * @notice Internal function to propose to transfer roles of message sender to a new account. * @dev Original account must have all the proposed roles. * @dev Emits a RolesProposed event. * @dev Roles are not transferred until the new role accepts the role transfer. * @param fromAccount The address of the current roles * @param toAccount The address to transfer roles to * @param role The role to transfer */ function _proposeRole( address fromAccount, address toAccount, uint8 role ) internal { _proposeAccountRoles(fromAccount, toAccount, 1 << role); } /** * @notice Internal function to propose to transfer roles of message sender to a new account. * @dev Original account must have all the proposed roles. * @dev Emits a RolesProposed event. * @dev Roles are not transferred until the new role accepts the role transfer. * @param fromAccount The address of the current roles * @param toAccount The address to transfer roles to * @param roles The roles to transfer */ function _proposeRoles( address fromAccount, address toAccount, uint8[] memory roles ) internal { _proposeAccountRoles(fromAccount, toAccount, _toAccountRoles(roles)); } /** * @notice Internal function to propose to transfer roles of message sender to a new account. * @dev Original account must have all the proposed roles. * @dev Emits a RolesProposed event. * @dev Roles are not transferred until the new role accepts the role transfer. * @param fromAccount The address of the current roles * @param toAccount The address to transfer roles to * @param accountRoles The account roles to transfer */ function _proposeAccountRoles( address fromAccount, address toAccount, uint256 accountRoles ) internal { if (!_hasAllTheRoles(_getRoles(fromAccount), accountRoles)) revert MissingAllRoles(fromAccount, accountRoles); _setProposedRoles(fromAccount, toAccount, accountRoles); emit RolesProposed(fromAccount, toAccount, accountRoles); } /** * @notice Internal function to accept roles transferred from another account. * @dev Pending account needs to pass all the proposed roles. * @dev Emits RolesRemoved and RolesAdded events. * @param fromAccount The address of the current role * @param role The role to accept */ function _acceptRole( address fromAccount, address toAccount, uint8 role ) internal virtual { _acceptAccountRoles(fromAccount, toAccount, 1 << role); } /** * @notice Internal function to accept roles transferred from another account. * @dev Pending account needs to pass all the proposed roles. * @dev Emits RolesRemoved and RolesAdded events. * @param fromAccount The address of the current role * @param roles The roles to accept */ function _acceptRoles( address fromAccount, address toAccount, uint8[] memory roles ) internal virtual { _acceptAccountRoles(fromAccount, toAccount, _toAccountRoles(roles)); } /** * @notice Internal function to accept roles transferred from another account. * @dev Pending account needs to pass all the proposed roles. * @dev Emits RolesRemoved and RolesAdded events. * @param fromAccount The address of the current role * @param accountRoles The account roles to accept */ function _acceptAccountRoles( address fromAccount, address toAccount, uint256 accountRoles ) internal virtual { if (_getProposedRoles(fromAccount, toAccount) != accountRoles) { revert InvalidProposedRoles(fromAccount, toAccount, accountRoles); } _setProposedRoles(fromAccount, toAccount, 0); _transferAccountRoles(fromAccount, toAccount, accountRoles); } /** * @notice Internal function to transfer roles from one account to another. * @dev Original account must have all the proposed roles. * @param fromAccount The address of the current role * @param toAccount The address to transfer role to * @param role The role to transfer */ function _transferRole( address fromAccount, address toAccount, uint8 role ) internal { _transferAccountRoles(fromAccount, toAccount, 1 << role); } /** * @notice Internal function to transfer roles from one account to another. * @dev Original account must have all the proposed roles. * @param fromAccount The address of the current role * @param toAccount The address to transfer role to * @param roles The roles to transfer */ function _transferRoles( address fromAccount, address toAccount, uint8[] memory roles ) internal { _transferAccountRoles(fromAccount, toAccount, _toAccountRoles(roles)); } /** * @notice Internal function to transfer roles from one account to another. * @dev Original account must have all the proposed roles. * @param fromAccount The address of the current role * @param toAccount The address to transfer role to * @param accountRoles The account roles to transfer */ function _transferAccountRoles( address fromAccount, address toAccount, uint256 accountRoles ) internal { if (!_hasAllTheRoles(_getRoles(fromAccount), accountRoles)) revert MissingAllRoles(fromAccount, accountRoles); _removeAccountRoles(fromAccount, accountRoles); _addAccountRoles(toAccount, accountRoles); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is IERC20 { mapping(address => uint256) public override balanceOf; mapping(address => mapping(address => uint256)) public override allowance; uint256 public override totalSupply; uint256 internal constant UINT256_MAX = type(uint256).max; /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) external virtual override returns (bool) { _transfer(msg.sender, recipient, amount); return true; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) external virtual override returns (bool) { _approve(msg.sender, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) external virtual override returns (bool) { uint256 _allowance = allowance[sender][msg.sender]; if (_allowance != UINT256_MAX) { _approve(sender, msg.sender, _allowance - amount); } _transfer(sender, recipient, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool) { _approve(msg.sender, spender, allowance[msg.sender][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool) { _approve(msg.sender, spender, allowance[msg.sender][spender] - subtractedValue); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { if (sender == address(0) || recipient == address(0)) revert InvalidAccount(); balanceOf[sender] -= amount; balanceOf[recipient] += amount; emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { if (account == address(0)) revert InvalidAccount(); totalSupply += amount; balanceOf[account] += amount; emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { if (account == address(0)) revert InvalidAccount(); balanceOf[account] -= amount; totalSupply -= amount; emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { if (owner == address(0) || spender == address(0)) revert InvalidAccount(); allowance[owner][spender] = amount; emit Approval(owner, spender, amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; import { IERC20Permit } from '@axelar-network/axelar-cgp-solidity/contracts/interfaces/IERC20Permit.sol'; import { ERC20 } from './ERC20.sol'; /** * @title ERC20Permit Contract * @dev Extension of ERC20 to include permit functionality (EIP-2612). * Allows for approval of ERC20 tokens by signature rather than transaction. */ abstract contract ERC20Permit is IERC20, IERC20Permit, ERC20 { error PermitExpired(); error InvalidS(); error InvalidV(); error InvalidSignature(); /** * @dev Represents hash of the EIP-712 Domain Separator. */ bytes32 public nameHash; string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = '\x19\x01'; // keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)') bytes32 private constant DOMAIN_TYPE_SIGNATURE_HASH = bytes32(0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f); // keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)') bytes32 private constant PERMIT_SIGNATURE_HASH = bytes32(0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9); /** * @dev Mapping of nonces for each address. */ mapping(address => uint256) public nonces; /** * @notice Internal function to set the token name hash * @param name The token name */ function _setNameHash(string memory name) internal { nameHash = keccak256(bytes(name)); } /** * @notice Calculates the domain separator. * @dev This is not cached because chainid can change on chain forks. */ // solhint-disable func-name-mixedcase // slither-disable-next-line naming-convention function DOMAIN_SEPARATOR() public view returns (bytes32) { return keccak256(abi.encode(DOMAIN_TYPE_SIGNATURE_HASH, nameHash, keccak256(bytes('1')), block.chainid, address(this))); } // solhint-enable func-name-mixedcase /** * @notice Permit the designated spender to spend the holder's tokens * @dev The permit function is used to allow a holder to designate a spender * to spend tokens on their behalf via a signed message. * @param issuer The address of the token holder * @param spender The address of the designated spender * @param value The number of tokens to be spent * @param deadline The time at which the permission to spend expires * @param v The recovery id of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function permit(address issuer, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external { if (block.timestamp > deadline) revert PermitExpired(); if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS(); if (v != 27 && v != 28) revert InvalidV(); bytes32 digest = keccak256( abi.encodePacked( EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA, DOMAIN_SEPARATOR(), keccak256(abi.encode(PERMIT_SIGNATURE_HASH, issuer, spender, value, nonces[issuer]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); if (recoveredAddress != issuer) revert InvalidSignature(); // _approve will revert if issuer is address(0x0) _approve(issuer, spender, value); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IInterchainTokenStandard } from '../interfaces/IInterchainTokenStandard.sol'; import { ITransmitInterchainToken } from '../interfaces/ITransmitInterchainToken.sol'; /** * @title An example implementation of the IInterchainTokenStandard. * @notice The is an abstract contract that needs to be extended with an ERC20 implementation. See `InterchainToken` for an example implementation. */ abstract contract InterchainTokenStandard is IInterchainTokenStandard { /** * @notice Getter for the tokenId used for this token. * @dev Needs to be overwritten. * @return tokenId_ The tokenId that this token is registerred under. */ function interchainTokenId() public view virtual returns (bytes32 tokenId_); /** * @notice Getter for the interchain token service. * @dev Needs to be overwritten. * @return service The address of the interchain token service. */ function interchainTokenService() public view virtual returns (address service); /** * @notice Implementation of the interchainTransfer method * @dev We chose to either pass `metadata` as raw data on a remote contract call, or if no data is passed, just do a transfer. * A different implementation could use metadata to specify a function to invoke, or for other purposes as well. * @param destinationChain The destination chain identifier. * @param recipient The bytes representation of the address of the recipient. * @param amount The amount of token to be transferred. * @param metadata Either empty, just to facilitate an interchain transfer, or the data to be passed for an interchain contract call with transfer * as per semantics defined by the token service. */ function interchainTransfer( string calldata destinationChain, bytes calldata recipient, uint256 amount, bytes calldata metadata ) external payable { address sender = msg.sender; _beforeInterchainTransfer(msg.sender, destinationChain, recipient, amount, metadata); ITransmitInterchainToken(interchainTokenService()).transmitInterchainTransfer{ value: msg.value }( interchainTokenId(), sender, destinationChain, recipient, amount, metadata ); } /** * @notice Implementation of the interchainTransferFrom method * @dev We chose to either pass `metadata` as raw data on a remote contract call, or, if no data is passed, just do a transfer. * A different implementation could use metadata to specify a function to invoke, or for other purposes as well. * @param sender The sender of the tokens. They need to have approved `msg.sender` before this is called. * @param destinationChain The string representation of the destination chain. * @param recipient The bytes representation of the address of the recipient. * @param amount The amount of token to be transferred. * @param metadata Either empty, just to facilitate an interchain transfer, or the data to be passed to an interchain contract call and transfer. */ function interchainTransferFrom( address sender, string calldata destinationChain, bytes calldata recipient, uint256 amount, bytes calldata metadata ) external payable { _spendAllowance(sender, msg.sender, amount); _beforeInterchainTransfer(sender, destinationChain, recipient, amount, metadata); ITransmitInterchainToken(interchainTokenService()).transmitInterchainTransfer{ value: msg.value }( interchainTokenId(), sender, destinationChain, recipient, amount, metadata ); } /** * @notice A method to be overwritten that will be called before an interchain transfer. One can approve the tokenManager here if needed, * to allow users for a 1-call transfer in case of a lock-unlock token manager. * @param from The sender of the tokens. They need to have approved `msg.sender` before this is called. * @param destinationChain The string representation of the destination chain. * @param destinationAddress The bytes representation of the address of the recipient. * @param amount The amount of token to be transferred. * @param metadata Either empty, just to facilitate an interchain transfer, or the data to be passed to an interchain contract call and transfer. */ function _beforeInterchainTransfer( address from, string calldata destinationChain, bytes calldata destinationAddress, uint256 amount, bytes calldata metadata ) internal virtual {} /** * @notice A method to be overwritten that will decrease the allowance of the `spender` from `sender` by `amount`. * @dev Needs to be overwritten. This provides flexibility for the choice of ERC20 implementation used. Must revert if allowance is not sufficient. */ function _spendAllowance(address sender, address spender, uint256 amount) internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IERC20MintableBurnable Interface * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20MintableBurnable { /** * @notice Function to mint new tokens. * @dev Can only be called by the minter address. * @param to The address that will receive the minted tokens. * @param amount The amount of tokens to mint. */ function mint(address to, uint256 amount) external; /** * @notice Function to burn tokens. * @dev Can only be called by the minter address. * @param from The address that will have its tokens burnt. * @param amount The amount of tokens to burn. */ function burn(address from, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol'; /** * @title IERC20Named Interface * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Named is IERC20 { /** * @notice Getter for the name of the token. * @return string Name of the token. */ function name() external view returns (string memory); /** * @notice Getter for the symbol of the token. * @return string The symbol of the token. */ function symbol() external view returns (string memory); /** * @notice Getter for the decimals of the token. * @return uint8 The decimals of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IInterchainTokenStandard } from './IInterchainTokenStandard.sol'; import { IMinter } from './IMinter.sol'; import { IERC20MintableBurnable } from './IERC20MintableBurnable.sol'; import { IERC20Named } from './IERC20Named.sol'; /** * @title IInterchainToken interface * @dev Extends IInterchainTokenStandard and IMinter. */ interface IInterchainToken is IInterchainTokenStandard, IMinter, IERC20MintableBurnable, IERC20Named { error InterchainTokenServiceAddressZero(); error TokenIdZero(); error TokenNameEmpty(); error TokenSymbolEmpty(); error AlreadyInitialized(); /** * @notice Getter for the interchain token service contract. * @dev Needs to be overwitten. * @return interchainTokenServiceAddress The interchain token service address. */ function interchainTokenService() external view returns (address interchainTokenServiceAddress); /** * @notice Getter for the tokenId used for this token. * @dev Needs to be overwitten. * @return tokenId_ The tokenId for this token. */ function interchainTokenId() external view returns (bytes32 tokenId_); /** * @notice Setup function to initialize contract parameters. * @param tokenId_ The tokenId of the token. * @param minter The address of the token minter. * @param tokenName The name of the token. * @param tokenSymbol The symbopl of the token. * @param tokenDecimals The decimals of the token. */ function init(bytes32 tokenId_, address minter, string calldata tokenName, string calldata tokenSymbol, uint8 tokenDecimals) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IInterchainTokenStandard interface * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IInterchainTokenStandard { /** * @notice Implementation of the interchainTransfer method. * @dev We chose to either pass `metadata` as raw data on a remote contract call, or if no data is passed, just do a transfer. * A different implementation could use metadata to specify a function to invoke, or for other purposes as well. * @param destinationChain The destination chain identifier. * @param recipient The bytes representation of the address of the recipient. * @param amount The amount of token to be transferred. * @param metadata Optional metadata for the call for additional effects (such as calling a destination contract). */ function interchainTransfer( string calldata destinationChain, bytes calldata recipient, uint256 amount, bytes calldata metadata ) external payable; /** * @notice Implementation of the interchainTransferFrom method * @dev We chose to either pass `metadata` as raw data on a remote contract call, or, if no data is passed, just do a transfer. * A different implementation could use metadata to specify a function to invoke, or for other purposes as well. * @param sender The sender of the tokens. They need to have approved `msg.sender` before this is called. * @param destinationChain The string representation of the destination chain. * @param recipient The bytes representation of the address of the recipient. * @param amount The amount of token to be transferred. * @param metadata Optional metadata for the call for additional effects (such as calling a destination contract.) */ function interchainTransferFrom( address sender, string calldata destinationChain, bytes calldata recipient, uint256 amount, bytes calldata metadata ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IRolesBase } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IRolesBase.sol'; /** * @title IMinter Interface * @notice An interface for a contract module which provides a basic access control mechanism, where * there is an account (a minter) that can be granted exclusive access to specific functions. */ interface IMinter is IRolesBase { /** * @notice Change the minter of the contract. * @dev Can only be called by the current minter. * @param minter_ The address of the new minter. */ function transferMintership(address minter_) external; /** * @notice Proposed a change of the minter of the contract. * @dev Can only be called by the current minter. * @param minter_ The address of the new minter. */ function proposeMintership(address minter_) external; /** * @notice Accept a change of the minter of the contract. * @dev Can only be called by the proposed minter. * @param fromMinter The previous minter. */ function acceptMintership(address fromMinter) external; /** * @notice Query if an address is a minter * @param addr the address to query for * @return bool Boolean value representing whether or not the address is a minter. */ function isMinter(address addr) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title ITransmitInterchainToken Interface * @notice Interface for transmiting interchain tokens via the interchain token service */ interface ITransmitInterchainToken { /** * @notice Transmit an interchain transfer for the given tokenId. * @dev Only callable by a token registered under a tokenId. * @param tokenId The tokenId of the token (which must be the msg.sender). * @param sourceAddress The address where the token is coming from. * @param destinationChain The name of the chain to send tokens to. * @param destinationAddress The destinationAddress for the interchainTransfer. * @param amount The amount of token to give. * @param metadata Optional metadata for the call for additional effects (such as calling a destination contract). */ function transmitInterchainTransfer( bytes32 tokenId, address sourceAddress, string calldata destinationChain, bytes memory destinationAddress, uint256 amount, bytes calldata metadata ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IMinter } from '../interfaces/IMinter.sol'; import { RolesBase } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/RolesBase.sol'; import { RolesConstants } from './RolesConstants.sol'; /** * @title Minter Contract * @notice A contract module which provides a basic access control mechanism, where * there is an account (a minter) that can be granted exclusive access to * specific functions. * @dev This module is used through inheritance. */ contract Minter is IMinter, RolesBase, RolesConstants { /** * @notice Internal function that stores the new minter address in the correct storage slot. * @param minter_ The address of the new minter. */ function _addMinter(address minter_) internal { _addRole(minter_, uint8(Roles.MINTER)); } /** * @notice Changes the minter of the contract. * @dev Can only be called by the current minter. * @param minter_ The address of the new minter. */ function transferMintership(address minter_) external onlyRole(uint8(Roles.MINTER)) { _transferRole(msg.sender, minter_, uint8(Roles.MINTER)); } /** * @notice Proposes a change of the minter of the contract. * @dev Can only be called by the current minter. * @param minter_ The address of the new minter. */ function proposeMintership(address minter_) external onlyRole(uint8(Roles.MINTER)) { _proposeRole(msg.sender, minter_, uint8(Roles.MINTER)); } /** * @notice Accept a change of the minter of the contract. * @dev Can only be called by the proposed minter. * @param fromMinter The previous minter. */ function acceptMintership(address fromMinter) external { _acceptRole(fromMinter, msg.sender, uint8(Roles.MINTER)); } /** * @notice Query if an address is a minter * @param addr the address to query for * @return bool Boolean value representing whether or not the address is a minter. */ function isMinter(address addr) external view returns (bool) { return hasRole(addr, uint8(Roles.MINTER)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title RolesConstants * @notice This contract contains enum values representing different contract roles. */ contract RolesConstants { enum Roles { MINTER, OPERATOR, FLOW_LIMITER } }
{ "evmVersion": "london", "optimizer": { "enabled": true, "runs": 1000, "details": { "peephole": true, "inliner": true, "jumpdestRemover": true, "orderLiterals": true, "deduplicate": true, "cse": true, "constantOptimizer": true, "yul": true, "yulDetails": { "stackAllocation": true } } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"interchainTokenServiceAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InterchainTokenServiceAddressZero","type":"error"},{"inputs":[],"name":"InvalidAccount","type":"error"},{"inputs":[{"internalType":"address","name":"fromAccount","type":"address"},{"internalType":"address","name":"toAccount","type":"address"},{"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"InvalidProposedRoles","type":"error"},{"inputs":[],"name":"InvalidS","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidV","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"MissingAllRoles","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"MissingAnyOfRoles","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint8","name":"role","type":"uint8"}],"name":"MissingRole","type":"error"},{"inputs":[],"name":"PermitExpired","type":"error"},{"inputs":[],"name":"TokenIdZero","type":"error"},{"inputs":[],"name":"TokenNameEmpty","type":"error"},{"inputs":[],"name":"TokenSymbolEmpty","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":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"RolesAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromAccount","type":"address"},{"indexed":true,"internalType":"address","name":"toAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"RolesProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"accountRoles","type":"uint256"}],"name":"RolesRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromMinter","type":"address"}],"name":"acceptMintership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","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":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint8","name":"role","type":"uint8"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"tokenId_","type":"bytes32"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interchainTokenId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interchainTokenService","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"interchainTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"interchainTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nameHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"issuer","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":[{"internalType":"address","name":"minter_","type":"address"}],"name":"proposeMintership","outputs":[],"stateMutability":"nonpayable","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":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"transferMintership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.