Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Deploy an ERC20" with remix tutorial #344

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const interactWithStorageContract = async (
contractAddress,
mnemonic,
providerConfig,
numberToSet,
numberToSet
) => {
try {
console.log(`Setting new number in Storage contract: ${numberToSet}`);
Expand Down Expand Up @@ -79,5 +79,5 @@ interactWithStorageContract(
contractAddress,
mnemonic,
providerConfig,
newNumber,
newNumber
);
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const compileContract = async (solidityFilePath, outputDir) => {
const bytecodePath = join(outputDir, `${name}.polkavm`);
writeFileSync(
bytecodePath,
Buffer.from(contract.evm.bytecode.object, 'hex'),
Buffer.from(contract.evm.bytecode.object, 'hex')
);
console.log(`Bytecode saved to ${bytecodePath}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ const createProvider = (rpcUrl, chainId, chainName) => {
const getAbi = (contractName) => {
try {
return JSON.parse(
readFileSync(join(codegenDir, `${contractName}.json`), 'utf8'),
readFileSync(join(codegenDir, `${contractName}.json`), 'utf8')
);
} catch (error) {
console.error(
`Could not find ABI for contract ${contractName}:`,
error.message,
error.message
);
throw error;
}
Expand All @@ -31,11 +31,13 @@ const getAbi = (contractName) => {
// Reads the compiled bytecode for a given contract
const getByteCode = (contractName) => {
try {
return `0x${readFileSync(join(codegenDir, `${contractName}.polkavm`)).toString('hex')}`;
return `0x${readFileSync(
join(codegenDir, `${contractName}.polkavm`)
).toString('hex')}`;
} catch (error) {
console.error(
`Could not find bytecode for contract ${contractName}:`,
error.message,
error.message
);
throw error;
}
Expand All @@ -49,7 +51,7 @@ const deployContract = async (contractName, mnemonic, providerConfig) => {
const provider = createProvider(
providerConfig.rpc,
providerConfig.chainId,
providerConfig.name,
providerConfig.name
);
const walletMnemonic = ethers.Wallet.fromPhrase(mnemonic);
const wallet = walletMnemonic.connect(provider);
Expand All @@ -58,7 +60,7 @@ const deployContract = async (contractName, mnemonic, providerConfig) => {
const factory = new ethers.ContractFactory(
getAbi(contractName),
getByteCode(contractName),
wallet,
wallet
);
const contract = await factory.deploy();
await contract.waitForDeployment();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const main = async () => {
const provider = createProvider(
PROVIDER_RPC.rpc,
PROVIDER_RPC.chainId,
PROVIDER_RPC.name,
PROVIDER_RPC.name
);
const latestBlock = await provider.getBlockNumber();
console.log(`Latest block: ${latestBlock}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.22;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {
constructor(address initialOwner)
ERC20("MyToken", "MTK")
Ownable(initialOwner)
{}

function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions tutorials/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ nav:
- polkadot-sdk
- interoperability
- onchain-governance
- smart-contracts
4 changes: 4 additions & 0 deletions tutorials/smart-contracts/.pages
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
title: Smart Contracts
nav:
- index.md
- 'Deploy an ERC20': deploy-erc20.md
137 changes: 137 additions & 0 deletions tutorials/smart-contracts/deploy-erc20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
title: Deploy a ERC20 to Asset Hub
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved
description: Deploy an ERC20 token on Asset Hub using PolkaVM. This guide covers contract creation, compilation, deployment, and interaction via Polkadot Remix IDE.
---

# Deploy ERC20 to Asset Hub

## Introduction

[ERC20](https://eips.ethereum.org/EIPS/eip-20){target=\_blank} tokens are fungible tokens commonly used for creating cryptocurrencies, governance tokens, and staking mechanisms. Asset Hub enables easy token deployment with EVM-compatible smart contracts via PolkaVM. This tutorial covers deploying an ERC20 contract on the Westend TestNet using [Polkadot Remix IDE](https://remix.polkadot.io){target=\_blank}, a web-based development tool. [OpenZeppelin's ERC20 contracts](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.0.0/contracts/token/ERC20){target=\_blank} are used for security and compliance.
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved

## Prerequisites

Before starting, make sure you have:

- [MetaMask](https://metamask.io/){target=\_blank} installed and connected to [Westend Asset Hub](https://chainlist.org/chain/420420421){target=\_blank}
- A funded account with some WND tokens (you can get them from the [Westend Faucet](https://faucet.polkadot.io/westend?parachain=1000){target=\_blank})
- Basic understanding of Solidity and fungible tokens

## Creating the ERC20 Contract

To create the ERC20 contract, you can follow the steps below:

1. Navigate to the [Polkadot Remix IDE](https://remix.polkadot.io){target=\_blank}
2. Click in the **Create new file** button under the **contracts** folder, and name your contract as `MyToken.sol`

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-1.webp)

3. Now, paste the following ERC20 contract code into the editor

```solidity title="MyToken.sol"
--8<-- 'code/tutorials/smart-contracts/deploy-erc20/MyToken.sol'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this snippet formatted with prettier or something like that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we don't have a prettier set up for solidity files. This is exactly how the openzeppelin wizard displays the contract

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for raising this! I've got a ticket to make sure that we add formatting for Solidity files. But this looks good

```

The key components of the code above are:

- Contract Imports
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved

- [`ERC20.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.0/contracts/token/ERC20/ERC20.sol){target=\_blank} - the base contract for fungible tokens, implementing core functionality like transfers, approvals, and balance tracking
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved
- [`Ownable.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.0/contracts/access/Ownable.sol){target=\_blank} - provides basic authorization control, ensuring only the contract owner can mint new tokens

- Constructor Parameters

- `initialOwner` - sets the address that will have administrative rights over the contract
- `"MyToken"` - the full name of your token
- `"MTK"` - the symbol representing your token in wallets and exchanges

- Key Function
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved

- `mint(address to, uint256 amount)` - allows the contract owner to create new tokens for any address. The amount should include 18 decimals (e.g., 1 token = 1000000000000000000)
- Inherited [Standard ERC20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/){target=\_blank} functions:
- `transfer(address recipient, uint256 amount)` - sends a specified amount of tokens to another address
- `approve(address spender, uint256 amount)` - grants permission for another address to spend a specific number of tokens on behalf of the token owner
- `transferFrom(address sender, address recipient, uint256 amount)` - transfers tokens from one address to another, if previously approved
- `balanceOf(address account)` - returns the token balance of a specific address
- `allowance(address owner, address spender)` - checks how many tokens an address is allowed to spend on behalf of another address

!!! tip
Use the [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/){target=\_blank} to quickly generate customized smart contracts. Simply configure your contract, copy the generated code, and paste it into Polkadot Remix IDE for deployment.

## Compiling the Contract
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved

nhussein11 marked this conversation as resolved.
Show resolved Hide resolved
The compilation transforms your Solidity source code into bytecode that can be deployed on the blockchain. During this process, the compiler checks your contract for syntax errors, ensures type safety, and generates the machine-readable instructions needed for blockchain execution. To compile your contract, follow the instructions below:

1. Select the **Solidity Compiler** plugin from the left panel

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-2.webp)

2. Click in the **Compile MyToken.sol** button
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-3.webp)

3. If the compilation succeeded, you can see a green checkmark indicating success in the **Solidity Compiler** icon
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-4.webp)

## Deploying the Contract

nhussein11 marked this conversation as resolved.
Show resolved Hide resolved
Deployment is the process of publishing your compiled smart contract to the blockchain, making it permanently available for interaction. During deployment, you'll create a new instance of your contract on the blockchain, which involves:

1. Select the **Deploy & Run Transactions** plugin from the left panel

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-5.webp)

2. Configure the deployment settings
1. From the **ENVIRONMENT** dropdown, select **Westend Testnet - MetaMask**
2. From the **ACCOUNT** dropdown, select the account you want to use for the deploy

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-6.webp)

3. Configure the contract parameters
1. Enter the address that will own the deployed token contract
2. Click the **Deploy** button to initiate the deployment

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-7.webp)

4. MetaMask will pop up - review the transaction details. Click **Confirm** to deploy your contract

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-8.webp){: .browser-extension}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to center this image?

Copy link
Collaborator Author

@nhussein11 nhussein11 Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is centered, you should pull the latest polkadot-mkdocs version (which contains this PR).


If the deployment process succeeded, you will see the transaction details in the terminal, including the contract address and deployment transaction hash:

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-9.webp)

## Interacting with Your ERC20 Contract

Once deployed, you can interact with your contract through Remix:

1. Find your contract under **Deployed/Unpinned Contracts**, and click it to expand the available methods

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-10.webp)

2. To mint new tokens:
nhussein11 marked this conversation as resolved.
Show resolved Hide resolved
1. Click in the contract to expand its associated methods
2. Expand the **mint** function
3. Enter:
- The recipient address
- The amount (remember to add 18 zeros for 1 whole token)
4. Click **Transact**

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-11.webp)

3. Confirm the transaction in MetaMask

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-12.webp){: .browser-extension}

If the transaction succeeds, you will see the following output in the terminal:

![](/images/tutorials/smart-contracts/deploy-erc20/deploy-erc20-13.webp)

Other common functions you can use:

- `balanceOf(address)` - check token balance of any address
- `transfer(address to, uint256 amount)` - send tokens to another address
- `approve(address spender, uint256 amount)` - allow another address to spend your tokens

Feel free to explore and interact with the contract's other functions using the same approach - selecting the method, providing any required parameters, and confirming the transaction through MetaMask when needed.
7 changes: 7 additions & 0 deletions tutorials/smart-contracts/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Smart Contracts
description: TODO
template: index-page.html
---

# Smart Contracts