Developing an Ethereum Web Wallet with ethers.js - Part 4: Sending Tokens

·

Introduction to Token Transactions

Ethereum's decentralized web wallet development series combines theory and实战,focusing on creating a functional wallet from scratch. This fourth installment covers发送Token functionality—a critical feature since tokens (代币) are a hallmark of Ethereum's ecosystem.

Key Concepts:


Contract ABI Essentials

To transfer tokens, you'll need the contract's Application Binary Interface (ABI)—a JSON description of its functions.

ERC20 Interface Example:

contract ERC20Interface {
    string public constant name;
    string public constant symbol;
    function transfer(address to, uint tokens) public returns (bool success);
    // ... (other standard functions)
}

ABI Structure:

[
    {
        "constant": true,
        "inputs": [{"name": "tokenOwner", "type": "address"}],
        "name": "balanceOf",
        "outputs": [{"name": "balance", "type": "uint256"}],
        "type": "function"
    }
    // ... (other function descriptors)
]

Key Fields:

👉 Explore ethers.js Contract ABI docs


Constructing the Contract Object

With ethers.js, instantiate a contract using:

  1. ABI: The interface JSON.
  2. Address: Deployed contract address.
  3. Provider: Network connection (e.g., ethers.providers.Web3Provider).
const contract = new ethers.Contract(address, abi, provider);

Token Operations

1. Fetching Token Balances

UI Integration:

<input id="wallet-token-balance" readonly value="0.0" />

JavaScript Logic:

contract.balanceOf(walletAddress).then(balance => {
    document.getElementById('wallet-token-balance').value = balance;
});

2. Transferring Tokens

UI Components:

<input id="wallet-token-send-target-address" placeholder="Recipient" />
<input id="wallet-token-send-amount" placeholder="Amount" />
<button id="wallet-token-submit-send">Send</button>

Transaction Execution:

document.getElementById('wallet-token-submit-send').addEventListener('click', async () => {
    const targetAddress = ethers.utils.getAddress(document.getElementById('wallet-token-send-target-address').value);
    const amount = document.getElementById('wallet-token-send-amount').value;
    
    // Estimate gas
    const gasEstimate = await contract.estimateGas.transfer(targetAddress, amount);
    
    // Connect signer (required for transactions)
    const contractWithSigner = contract.connect(wallet);
    
    // Execute transfer
    const tx = await contractWithSigner.transfer(targetAddress, amount, {
        gasLimit: gasEstimate,
        gasPrice: ethers.utils.parseUnits("2", "gwei")
    });
    console.log("Transaction hash:", tx.hash);
});

Key Notes:

👉 Best practices for gas optimization


FAQ Section

1. Why do I need an ABI to interact with a token contract?

The ABI defines how to encode/decode data for contract functions, ensuring compatibility between your calls and the contract's expectations.

2. How can I get the ABI for a popular token like USDC?

Use block explorers like Etherscan, which display verified contract ABIs under the "Contract" tab.

3. What’s the difference between call and send in token operations?

4. How do I handle transaction errors (e.g., insufficient funds)?

Wrap transfers in try-catch blocks and check error.code for specific failures (e.g., INSUFFICIENT_FUNDS).

5. Can I send tokens without specifying gas price?

Yes—ethers.js defaults to the current network gas price, but manual settings prevent delays during congestion.


Conclusion

This guide covered发送ERC20 tokens using ethers.js—from ABI setup to executing transfers. Implement these steps to enhance your wallet's functionality.

Further Reading: