Deploy an ERC20 Token
Create and deploy your own ERC20 token on RISE
Learn how to create and deploy your own ERC20 token on RISE using OpenZeppelin's battle-tested contracts.
What You'll Build
A standard ERC20 token with:
- Custom name and symbol
- Initial token supply
- Standard transfer, approve, and allowance functions
- Built on OpenZeppelin's secure implementation
The Contract
We'll use OpenZeppelin's ERC20 implementation:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
}This creates a token called "MyToken" with symbol "MTK" and mints the initial supply to the deployer.
Choose Your Tool
Deploy with Remix
The easiest way - no installation required!
Prerequisites
- A Web3 wallet (MetaMask or Rabby) with RISE Testnet configured
- Testnet ETH from the RISE Faucet
Open Remix IDE
Go to remix.ethereum.org in your browser.
Create the Contract
- In the File Explorer, create a new file:
MyToken.sol - Copy and paste this code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
}Customize the token name ("MyToken") and symbol ("MTK") to your preference.
Compile
- Click the Solidity Compiler tab
- Select compiler version
0.8.20or higher - Click Compile MyToken.sol
Remix will automatically fetch the OpenZeppelin contracts from GitHub.
Deploy to RISE
- Click the Deploy & Run Transactions tab
- Select Injected Provider - MetaMask in Environment
- Connect your wallet when prompted
- Verify you're on RISE Testnet (Chain ID: 11155931)
- In the Contract dropdown, select
MyToken - Enter initial supply (e.g.,
1000000for 1 million tokens) - Click Deploy
- Confirm the transaction in your wallet
Interact with Your Token
Under Deployed Contracts, you can:
- Click
name→ Returns "MyToken" - Click
symbol→ Returns "MTK" - Click
decimals→ Returns 18 - Click
totalSupply→ Returns total supply in wei (1000000 * 10^18) - Click
balanceOfwith your address → Shows your token balance
To transfer tokens:
- Expand the
transferfunction - Enter recipient address and amount
- Click transact and confirm
View on Explorer
Visit RISE Testnet Explorer and search for your contract address to see all token transfers and holders.
Deploy with Foundry
Fast, Rust-based toolkit with OpenZeppelin integration.
Prerequisites
- Foundry installed (installation guide)
- Testnet ETH from the RISE Faucet
Install OpenZeppelin Contracts
Install the OpenZeppelin contracts library:
forge install OpenZeppelin/openzeppelin-contractsConfigure remappings to make imports work:
forge remappings > remappings.txtThis creates a remappings.txt file that tells Foundry where to find OpenZeppelin contracts.
Create the Token Contract
Create src/MyToken.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
}Configure RISE Network
Update foundry.toml:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc = "0.8.30"
[rpc_endpoints]
rise = "https://testnet.riselabs.xyz"Deploy
Deploy to RISE Testnet with 1 million token initial supply using your private key:
forge create \
--rpc-url rise \
--private-key 0xYOUR_PRIVATE_KEY_HERE \
src/MyToken.sol:MyToken \
--constructor-args 1000000Alternatively, use a keystore for better security:
forge create \
--rpc-url rise \
--account <keystore-name> \
src/MyToken.sol:MyToken \
--constructor-args 1000000Learn how to create a keystore: Foundry Keystore Guide
Save the contract address from the output!
Interact with Your Token
Check token name:
cast call <CONTRACT_ADDRESS> "name()" --rpc-url riseCheck your balance:
cast call <CONTRACT_ADDRESS> "balanceOf(address)(uint256)" <YOUR_ADDRESS> --rpc-url riseTransfer tokens to another address:
cast send <CONTRACT_ADDRESS> \
"transfer(address,uint256)" \
<RECIPIENT_ADDRESS> \
1000000000000000000 \
--rpc-url rise \
--private-key 0xYOUR_PRIVATE_KEY_HERENote: The amount is in wei (18 decimals), so 1000000000000000000 = 1 token.
View on Explorer
Visit RISE Testnet Explorer and search for your contract address.
Deploy with Hardhat
Flexible development environment with OpenZeppelin support.
Prerequisites
- Node.js v22 or later
- Testnet ETH from the RISE Faucet
Create Project
Initialize a new Hardhat project:
mkdir erc20-token
cd erc20-token
npm init -y
npm install --save-dev hardhat
npx hardhat --initSelect:
- "Hardhat 3 Beta"
- Current directory
- "A minimal Hardhat project"
- Install dependencies: yes
Install OpenZeppelin Contracts
Install the OpenZeppelin contracts package:
npm install @openzeppelin/contractsCreate the Token Contract
Create contracts/MyToken.sol:
mkdir contracts// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
}Configure RISE Network
Update hardhat.config.ts:
import hardhatToolboxViemPlugin from "@nomicfoundation/hardhat-toolbox-viem";
import { configVariable, defineConfig } from "hardhat/config";
export default defineConfig({
plugins: [hardhatToolboxViemPlugin],
solidity: {
version: "0.8.30",
},
networks: {
riseTestnet: {
type: "http",
url: "https://testnet.riselabs.xyz",
accounts: [configVariable("RISE_PRIVATE_KEY")],
chainId: 11155931
}
}
});Set Your Private Key
Store your private key securely:
npx hardhat keystore set RISE_PRIVATE_KEYEnter your private key when prompted.
Create Deployment Module
Create the deployment script:
mkdir -p ignition/modulesimport { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
export default buildModule("MyTokenModule", (m) => {
const initialSupply = m.getParameter("initialSupply", 1000000n);
const myToken = m.contract("MyToken", [initialSupply]);
return { myToken };
});Deploy
Deploy to RISE Testnet:
npx hardhat ignition deploy ignition/modules/MyToken.ts --network riseTestnetTo deploy with a custom initial supply:
npx hardhat ignition deploy ignition/modules/MyToken.ts --network riseTestnet --parameters '{"MyTokenModule":{"initialSupply":"5000000"}}'Save the contract address from the output!
Interact with Your Token
Use Hardhat console:
npx hardhat console --network riseTestnetThen in the console:
const MyToken = await ethers.getContractFactory("MyToken");
const token = await MyToken.attach("YOUR_CONTRACT_ADDRESS");
// Check name and symbol
await token.name(); // "MyToken"
await token.symbol(); // "MTK"
// Check total supply
await token.totalSupply();
// Check your balance
await token.balanceOf("YOUR_ADDRESS");
// Transfer tokens
await token.transfer("RECIPIENT_ADDRESS", ethers.parseUnits("100", 18));View on Explorer
Visit RISE Testnet Explorer and search for your contract address.
Customizing Your Token
Change Token Details
Modify the constructor in your contract:
constructor(uint256 initialSupply) ERC20("YourTokenName", "YTN") {
_mint(msg.sender, initialSupply * 10 ** decimals());
}Add Minting Capability
Want to mint more tokens later? Add Ownable:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Ownable {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") Ownable(msg.sender) {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}Add Burning Capability
Allow token holders to burn their tokens:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
contract MyToken is ERC20, ERC20Burnable {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
}