Introduction
In this tutorial, we'll walk through scaffold-eth's second challenge: the Token Vendor. This guide will help you create an ERC20 token and develop a vendor contract that allows users to buy and sell tokens.
Prerequisites
- Basic understanding of Ethereum and smart contracts
- Familiarity with JavaScript/TypeScript
- MetaMask installed
Step 1: Setting Up the Environment
Clone the Project
git clone https://github.com/scaffold-eth/scaffold-eth-typescript-challenges.git challenge-2-token-vendor
cd challenge-2-token-vendor
git checkout challenge-2-token-vendor
yarn installProject Structure
packages/
├── hardhat-ts # Smart contracts
├── services # Graph-node config
├── subgraph # The Graph mappings
└── vite-app-ts # FrontendStart the Application
- Run
yarn chainto launch a local blockchain. - Deploy contracts with
yarn deploy. - Start the frontend using
yarn start.
Access the app at http://localhost:3000.
Step 2: Creating an ERC20 Token
What is ERC20?
ERC20 is a standard for fungible tokens on Ethereum, defining functions like:
transfer()balanceOf()approve()transferFrom()
Using OpenZeppelin
We’ll leverage OpenZeppelin’s audited contracts for security and efficiency.
Token Contract Code (YourToken.sol)
pragma solidity >=0.8.0 <0.9.0;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
contract YourToken is ERC20 {
constructor() ERC20("Gold", "GLD") {
_mint(msg.sender, 1000 * 10 ** 18);
}
}Deploy Script
// Send tokens to the vendor address
await yourToken.transfer(vendor.address, ethers.utils.parseEther("1000"));Step 3: Vendor Contract – Buy Tokens
Key Features
- Exchange rate: 100 GLD per ETH
buyTokens(): Accepts ETH and sends GLD to the buyer.
Vendor Contract (Vendor.sol)
contract Vendor is Ownable {
uint256 public tokensPerEth = 100;
event BuyTokens(address buyer, uint256 amountOfEth, uint256 amountOfTokens);
function buyTokens() public payable {
require(msg.value > 0, "Send ETH to buy");
uint256 tokens = msg.value * tokensPerEth;
require(yourToken.balanceOf(address(this)) >= tokens, "Insufficient tokens");
yourToken.transfer(msg.sender, tokens);
emit BuyTokens(msg.sender, msg.value, tokens);
}
function withdraw() public onlyOwner {
payable(owner()).transfer(address(this).balance);
}
}Deployment
yarn deploy --reset👉 Check out the deployed contract on Etherscan
Step 4: Vendor Contract – Sell Tokens
How Selling Works
- User approves the vendor to spend their GLD.
- Vendor transfers GLD from the user and sends ETH back.
Code Addition
event SellTokens(address seller, uint256 amountOfTokens, uint256 amountOfETH);
function sellTokens(uint256 amountToSell) public {
uint256 ethToSend = amountToSell / tokensPerEth;
yourToken.transferFrom(msg.sender, address(this), amountToSell);
payable(msg.sender).transfer(ethToSend);
emit SellTokens(msg.sender, amountToSell, ethToSend);
}Testing Steps
- Approve the vendor to spend GLD.
- Call
sellTokens().
Step 5: Deploying to Rinkeby
- Update
hardhat.config.tsandprovidersConfig.tsto target Rinkeby. - Fund your account via Paradigm Faucet.
Run:
yarn deploy --network rinkeby
Step 6: Deploying the Frontend
Use Surge for free static hosting:
yarn build
yarn surge👉 Explore more about dApp deployment
Step 7: Verifying Contracts on Etherscan
- Get an API key from Etherscan.
Run:
yarn verify --network rinkeby
Step 8: Submitting Your Project
Submit your dApp on speedrunethereum.com with:
- Frontend URL
- Contract address
FAQ
Q1: Why use OpenZeppelin?
A: It provides secure, audited contracts, reducing development risks.
Q2: How do I test token transfers?
A: Use MetaMask and the Debug page to simulate transactions.
Q3: What if my deployment fails?
A: Reset with yarn deploy --reset and check Rinkeby ETH balance.
Q4: How do I update the exchange rate?
A: Modify tokensPerEth in the vendor contract and redeploy.
Conclusion
By building this dApp, you’ve learned:
✅ Creating ERC20 tokens
✅ Writing vendor contracts
✅ Deploying to testnets
✅ Frontend integration
🚀 Next Steps: Try adding liquidity pools or multi-token support!