Pré-compilado ERC-20 do Token Nativo¶
Introdução¶
O contrato pré-compilado ERC-20 do token nativo em redes EVM powered by Tanssi permite que desenvolvedores interajam com o token nativo do protocolo por meio de uma interface ERC-20. Embora o token nativo da sua rede não seja um ERC-20, agora você pode interagir com ele como se fosse um ERC-20 padrão.
Um dos principais benefícios desse precompile é eliminar a necessidade de ter uma representação embrulhada do token do protocolo como um smart contract ERC-20, como o WETH no Ethereum. Além disso, minimiza a necessidade de múltiplas representações embrulhadas do mesmo token do protocolo. Consequentemente, dApps que precisam interagir com o token do protocolo via uma interface ERC-20 podem fazê-lo sem precisar de um contrato separado.
Por baixo dos panos, a precompilada ERC-20 executa ações específicas do Substrate relacionadas ao módulo de saldos, escrito em Rust. O módulo de saldos fornece funcionalidades para lidar com diversos tipos de saldos.
Este guia mostrará como interagir com tokens UNIT, o token nativo do protocolo para redes de teste rápido no Dancelight, por meio da precompilada ERC-20. Você pode seguir e adaptar este guia para interagir com sua própria rede.
A precompilada está localizada no seguinte endereço:
0x0000000000000000000000000000000000000800
Note
O uso de precompiladas pode trazer consequências inesperadas. As precompiladas do Tanssi são derivadas das do Moonbeam; portanto, familiarize-se com as considerações de segurança das precompiladas do Moonbeam.
Interface Solidity do ERC-20¶
A interface ERC20.sol nas redes EVM da Tanssi segue o Padrão de Token EIP-20, que é a interface padrão de API para tokens em smart contracts. O padrão define as funções e eventos exigidos para que um contrato de token seja interoperável com diferentes aplicações.
ERC20.sol
/ SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.3;
/// @dev The IERC20 contract's address.
address constant IERC20_ADDRESS = 0x0000000000000000000000000000000000000800;
/// @dev The IERC20 contract's instance.
IERC20 constant IERC20_CONTRACT = IERC20(IERC20_ADDRESS);
/// @title ERC20 interface
/// @dev see https://github.com/ethereum/EIPs/issues/20
/// @dev copied from https://github.com/OpenZeppelin/openzeppelin-contracts
/// @custom:address 0x0000000000000000000000000000000000000800
interface IERC20 {
/// @dev Returns the name of the token.
/// @custom:selector 06fdde03
function name() external view returns (string memory);
/// @dev Returns the symbol of the token.
/// @custom:selector 95d89b41
function symbol() external view returns (string memory);
/// @dev Returns the decimals places of the token.
/// @custom:selector 313ce567
function decimals() external view returns (uint8);
/// @dev Total number of tokens in existence
/// @custom:selector 18160ddd
function totalSupply() external view returns (uint256);
/// @dev Gets the balance of the specified address.
/// @custom:selector 70a08231
/// @param owner The address to query the balance of.
/// @return An uint256 representing the amount owned by the passed address.
function balanceOf(address owner) external view returns (uint256);
/// @dev Function to check the amount of tokens that an owner allowed to a spender.
/// @custom:selector dd62ed3e
/// @param owner address The address which owns the funds.
/// @param spender address The address which will spend the funds.
/// @return A uint256 specifying the amount of tokens still available for the spender.
function allowance(address owner, address spender)
external
view
returns (uint256);
/// @dev Transfer token for a specified address
/// @custom:selector a9059cbb
/// @param to The address to transfer to.
/// @param value The amount to be transferred.
/// @return true if the transfer was succesful, revert otherwise.
function transfer(address to, uint256 value) external returns (bool);
/// @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
/// 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
/// @custom:selector 095ea7b3
/// @param spender The address which will spend the funds.
/// @param value The amount of tokens to be spent.
/// @return true, this cannot fail
function approve(address spender, uint256 value) external returns (bool);
/// @dev Transfer tokens from one address to another
/// @custom:selector 23b872dd
/// @param from address The address which you want to send tokens from
/// @param to address The address which you want to transfer to
/// @param value uint256 the amount of tokens to be transferred
/// @return true if the transfer was succesful, revert otherwise.
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);
/// @dev Event emited when a transfer has been performed.
/// @custom:selector ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
/// @param from address The address sending the tokens
/// @param to address The address receiving the tokens.
/// @param value uint256 The amount of tokens transfered.
event Transfer(address indexed from, address indexed to, uint256 value);
/// @dev Event emited when an approval has been registered.
/// @custom:selector 8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
/// @param owner address Owner of the tokens.
/// @param spender address Allowed spender.
/// @param value uint256 Amount of tokens approved.
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
/// @title Native currency wrapper interface.
/// @dev Allow compatibility with dApps expecting this precompile to be
/// a WETH-like contract.
interface WrappedNativeCurrency {
/// @dev Provide compatibility for contracts that expect wETH design.
/// Returns funds to sender as this precompile tokens and the native tokens are the same.
/// @custom:selector d0e30db0
function deposit() external payable;
/// @dev Provide compatibility for contracts that expect wETH design.
/// Does nothing.
/// @custom:selector 2e1a7d4d
/// @param value uint256 The amount to withdraw/unwrap.
function withdraw(uint256 value) external;
/// @dev Event emited when deposit() has been called.
/// @custom:selector e1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c
/// @param owner address Owner of the tokens
/// @param value uint256 The amount of tokens "wrapped".
event Deposit(address indexed owner, uint256 value);
/// @dev Event emited when withdraw(uint256) has been called.
/// @custom:selector 7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65
/// @param owner address Owner of the tokens
/// @param value uint256 The amount of tokens "unwrapped".
event Withdrawal(address indexed owner, uint256 value);
}
Note
A precompilada ERC-20 não inclui as funções deposit e withdraw nem os eventos associados esperados de um token embrulhado, como o WETH.
Interagir com a Interface Solidity¶
Verificando Pré-requisitos¶
Para acompanhar este tutorial, você precisará ter sua carteira configurada para funcionar com sua rede EVM com Tanssi e uma conta com tokens nativos. Você pode adicionar sua rede EVM ao MetaMask com um clique no Tanssi dApp. Ou, se preferir, configure o MetaMask para Tanssi com a rede EVM de demonstração.
Adicionar token a uma carteira EVM¶
Se quiser interagir com o token nativo da rede como faria com um ERC-20, adicione um token personalizado à sua carteira compatível com EVM usando o endereço da precompilada. Esta seção mostra como adicionar um ativo externo ao MetaMask.
Para começar, abra o MetaMask, conecte-se à sua rede e:
- Acesse a aba Assets
- Clique em Import tokens
Agora, crie o token personalizado:
- Informe o endereço da precompilada para o endereço do contrato do token:
0x0000000000000000000000000000000000000800. Ao inserir o endereço, os campos Token Symbol e Token Decimal devem preencher automaticamente. Caso não aconteça, useUNITcomo símbolo e18como casas decimais. Lembre que o padrão de casas decimais das redes EVM da Tanssi é18, o mesmo do Ethereum - Clique em Next
O MetaMask solicitará a confirmação da importação. Revise os detalhes e clique em Import Tokens para importar os tokens UNIT na carteira.
Pronto! Você adicionou o token UNIT como um ERC-20 personalizado na sua rede EVM da Tanssi.
Configuração do Remix¶
Você pode interagir com a precompilada ERC-20 usando o Remix. Para adicioná-la ao Remix, você precisará:
- Obter uma cópia de
ERC20.sol - Colar o conteúdo em um arquivo do Remix chamado
IERC20.sol
Compilar o Contrato¶
Em seguida, compile a interface no Remix:
- Clique na aba Compile (segunda de cima)
- Compile a interface clicando em Compile IERC20.sol
Quando a compilação for concluída, um check verde aparecerá ao lado da aba Compile.
Acessar o Contrato¶
Em vez de implantar a precompilada ERC-20, você acessará a interface informando o endereço do contrato pré-compilado:
- Clique na aba Deploy and Run logo abaixo da aba Compile no Remix. Observe que contratos pré-compilados já estão acessíveis em seus respectivos endereços, portanto não há etapa de implantação
- Certifique-se de que Injected Web3 está selecionado em ENVIRONMENT. Ao selecionar Injected Web3, o MetaMask pode solicitar conexão ao Remix caso ainda não esteja
- Verifique se a conta correta aparece em ACCOUNT
- Garanta que IERC20 - IERC20.sol esteja selecionado em CONTRACT. Por ser um contrato pré-compilado, não há implantação; em vez disso, informe o endereço da precompilada no campo At Address
- Informe o endereço da precompilada ERC-20:
0x0000000000000000000000000000000000000800e clique em At Address
A precompilada IERC20 aparecerá na lista de Deployed Contracts.
Obter Informações Básicas do Token¶
A interface ERC-20 permite obter rapidamente informações como oferta total, nome, símbolo e casas decimais. Para recuperar essas informações:
- Expanda o contrato IERC20 em Deployed Contracts
- Clique em decimals para obter as casas decimais do token nativo
- Clique em name para obter o nome do token
- Clique em symbol para obter o símbolo do token
- Clique em totalSupply para obter a oferta total de tokens nativos na rede
Os resultados de cada chamada são exibidos abaixo das respectivas funções.
Consultar Saldo de uma Conta¶
Você pode verificar o saldo de qualquer endereço na rede chamando balanceOf e fornecendo um endereço:
- Expanda a função balanceOf
- Informe o endereço que deseja consultar no campo owner
- Clique em call
O saldo será exibido abaixo da função balanceOf.
Aprovar um Gasto¶
Para aprovar uma permissão de gasto, forneça um endereço para o spender e o número de tokens que ele pode gastar. O spender pode ser uma conta externa (EOA) ou um smart contract. Neste exemplo, você aprovará uma allowance de 1 token UNIT. Siga:
- Expanda a função approve
- Informe o endereço do spender. Você deve ter criado duas contas antes de começar; use a segunda conta como spender
- Informe o valor de tokens que o spender pode gastar em value. Para este exemplo, permita 1 token UNIT em Wei (
1000000000000000000) - Clique em transact
- A MetaMask aparecerá; revise os detalhes e clique em Confirm para enviar
Após a confirmação, o saldo da sua conta permanece o mesmo: você apenas aprovou a permissão e o spender ainda não gastou os fundos. Na próxima seção, você usará allowance para verificar que o spender pode gastar 1 token UNIT em seu nome.
Obter Allowance do Spender¶
Para conferir se o spender recebeu a allowance aprovada em Aprovar um Gasto:
- Expanda a função allowance
- Informe seu endereço em owner
- Informe o endereço do spender usado na seção anterior
- Clique em call
Quando a chamada finalizar, a allowance do spender será exibida e deve ser equivalente a 1 token UNIT (1000000000000000000).
Enviar Transferência¶
Para enviar tokens diretamente da sua conta para outra, chame transfer:
- Expanda a função transfer
- Informe o endereço para o qual deseja enviar tokens UNIT
- Informe a quantidade de tokens UNIT a enviar. Neste exemplo, envie 1 UNIT (
1000000000000000000) - Clique em transact
- A MetaMask aparecerá; revise os detalhes e clique em Confirm para enviar
Após a transação, você pode checar seu saldo usando balanceOf ou pelo MetaMask. Verá que seu saldo diminuiu em 1 UNIT. Use balanceOf também para confirmar que o saldo do destinatário aumentou em 1 UNIT conforme esperado.
Enviar Transferência de uma Conta Específica¶
Até agora, você aprovou uma allowance de 1 UNIT para o spender e enviou 1 UNIT via transfer. A função transferFrom difere da transfer padrão porque permite definir de qual endereço os tokens serão enviados. Você pode informar um endereço com allowance ou seu próprio endereço (se houver saldo). Neste exemplo, use a conta do spender para iniciar a transferência dos fundos permitidos do owner para o próprio spender. O spender poderia enviar para qualquer conta, mas aqui enviaremos do owner para o spender.
Primeiro, mude para a conta do spender no MetaMask. Ao trocar, o endereço selecionado no Remix em Accounts passará a ser o do spender.
Agora, inicie e envie a transferência:
- Expanda a função transferFrom
- Informe seu endereço (do owner) no campo from
- Informe o endereço do destinatário, que deve ser o endereço do spender, no campo to
- Informe a quantidade de tokens UNIT a enviar. O spender só pode enviar 1 UNIT, então insira
1000000000000000000 - Clique em transact
Após a transação, verifique o saldo do owner e do spender usando balanceOf. O saldo do spender deve ter aumentado em 1 UNIT, e a allowance deve ter sido consumida. Para confirmar que o spender não tem mais allowance, chame allowance informando os endereços de owner e spender; o resultado deve ser 0.
E é isso! Você interagiu com a precompilada ERC-20 usando MetaMask e Remix!
| Criada: 27 de novembro de 2025












