-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add 'build a dapp' docs * Feedback applied - Fontsize decreased - Small notes about preview, gas, etc. - Small edits * Some fixes after review * Add Node.js, yarn note to the contracts' articles
- Loading branch information
Showing
23 changed files
with
1,212 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
--- | ||
title: Simple Counter | ||
--- | ||
|
||
In this guide you will write one of the simplest smart contracts possible and learn how to deploy and interact with it. | ||
We will store just one integer value inside of it and increment it: | ||
|
||
```solidity title="contracts/Incrementer.sol" | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8; | ||
contract Incrementer { | ||
uint counter; | ||
constructor(uint startValue) { | ||
counter = startValue; | ||
} | ||
function increment() public { | ||
counter = counter + 1; | ||
} | ||
function getCounter() public view returns (uint) { | ||
return counter; | ||
} | ||
} | ||
``` | ||
|
||
To deploy it to the Aurora Testnet you need to follow the steps below. | ||
|
||
:::tip | ||
You can find the code of the whole project in [GitHub repository](https://github.com/aurora-is-near/aurora-examples/blob/main/hardhat/incrementer-example/). | ||
::: | ||
|
||
## Create project | ||
|
||
Open your favorite terminal application and clone the repo: | ||
|
||
```bash | ||
git clone git@github.com:aurora-is-near/aurora-examples.git | ||
cd hardhat/incrementer-example | ||
``` | ||
|
||
## Configure project | ||
|
||
Add your Aurora Private key (from MetaMask or other Web3 wallet) to `__.env__` file: | ||
|
||
```bash | ||
$ echo "AURORA_PRIVATE_KEY=YOUR_AURORA_PRIVATE_KEY_HERE" >> .env | ||
``` | ||
|
||
## Interact with contract | ||
|
||
:::note | ||
To use the commands below you will need Node.js and `yarn` to be installed. Please follow the [instructions here](https://nodejs.org/en/download/package-manager) to install Node.js. | ||
Then, install `yarn` with `npm install --global yarn` or read more [here](https://classic.yarnpkg.com/lang/en/docs/install/). | ||
::: | ||
|
||
To deploy the contract to Testnet run: | ||
|
||
```bash | ||
$ make deploy | ||
``` | ||
|
||
Take the address of the deployed Incrementer from the output to use it in the next steps. | ||
|
||
To get the current counter value run: | ||
|
||
```bash | ||
$ make get-counter INCREMENTER_ADDRESS=YOUR_INCREMENTER_ADDRESS_HERE | ||
``` | ||
|
||
To increment the current counter value run: | ||
|
||
```bash | ||
$ make increment-counter INCREMENTER_ADDRESS=YOUR_INCREMENTER_ADDRESS_HERE | ||
``` | ||
|
||
You can observe your transactions by using [Aurora Block Explorer](https://dev.aurora.dev/ecosystem/block-explorer). | ||
|
||
## Switch a network | ||
|
||
Optionally you can specify any of the following networks for any command: __testnet_aurora__, __mainnet_aurora__, __ropsten__ like this: | ||
|
||
```bash | ||
$ make deploy NETWORK=mainnet_aurora | ||
``` | ||
|
||
## More materials | ||
|
||
You can find a more detailed tutorial with a similar Incrementer example in the [Getting Started with Aurora article](https://dev.aurora.dev/posts/getting-started-with-aurora). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
--- | ||
title: ERC-20 Token | ||
--- | ||
|
||
In this article, we will consider a bit more complex, yet standard example of an ERC-20 token contract. | ||
|
||
:::note | ||
|
||
In case you are not familiar with a standard we advise you to read more about it on the OpenZeppelin website: | ||
[ERC-20 article](https://docs.openzeppelin.com/contracts/5.x/erc20) and [ERC-20 API](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20). | ||
::: | ||
|
||
Here is the full contract code below: | ||
|
||
```solidity title="contracts/WatermelonToken.sol" | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
contract WatermelonToken is ERC20 { | ||
constructor(uint256 initialSupply) ERC20("Watermelon", "WTM") { | ||
_mint(msg.sender, initialSupply); | ||
} | ||
function decimals() public pure override(ERC20) returns (uint8) { | ||
return 0; | ||
} | ||
} | ||
``` | ||
|
||
As you can see, the implementation is just as simple as inheriting from OpenZeppelin's ERC20 contract. | ||
Notice two modifications done to the standard implementation: | ||
|
||
- During the construction, all of the `initialSupply` is minted to the contract deployer. | ||
- Decimals are set to zero. | ||
|
||
:::note | ||
You can find [a GitHub repo here](https://github.com/aurora-is-near/aurora-examples/blob/main/hardhat/erc20/) | ||
and [another version of this tutorial](https://dev.aurora.dev/ecosystem/hardhat) on Aurora Developer Portal. | ||
::: | ||
|
||
## Create project | ||
|
||
To create a project, clone the examples repository and go to `erc-20` folder: | ||
|
||
```bash | ||
git clone https://github.com/aurora-is-near/aurora-examples.git | ||
cd aurora-examples/hardhat/erc20/ | ||
yarn install | ||
``` | ||
|
||
## Configure project | ||
|
||
Add your Aurora Private key (from MetaMask or other Web3 wallet) to `__.env__` file: | ||
|
||
```bash | ||
$ echo "AURORA_PRIVATE_KEY=YOUR_AURORA_PRIVATE_KEY_HERE" >> .env | ||
``` | ||
|
||
## Deploy contract | ||
|
||
This example is about a naive Watermelon token 🍉. The total supply is 1,000,000, the | ||
minter is the contract deployer address, and the decimals are 0, so one token is one non-divisible watermelon. | ||
|
||
:::note | ||
To use the commands below you will need Node.js and `yarn` to be installed. Please follow the [instructions here](https://nodejs.org/en/download/package-manager) to install Node.js. | ||
Then, install `yarn` with `npm install --global yarn` or read more [here](https://classic.yarnpkg.com/lang/en/docs/install/). | ||
::: | ||
|
||
To deploy the token contract, use the following command: | ||
|
||
```bash | ||
make deploy NETWORK=testnet_aurora | ||
``` | ||
|
||
You will see the next output with your Token Address on your screen: | ||
|
||
```bash | ||
yarn hardhat run scripts/deploy.js --network testnet_aurora | ||
yarn run v1.22.10 | ||
|
||
Deploying contracts with the account: 0x6A33382de9f73B846878a57500d055B981229ac4 | ||
Account balance: 2210010200000000000 | ||
WatermelonToken deployed to: 0xD7f2A76F5DA173043E6c61a0A18D835809A07766 | ||
✨ Done in 14.96s. | ||
``` | ||
|
||
You should also export your Token Address as an environment variable to re-use later during CLI interactions with the contract: | ||
|
||
```bash | ||
# export the token address | ||
export TOKEN_ADDRESS='YOUR OUTPUT FROM DEPLOY (e.g. 0xD7f2A76F5DA173043E6c61a0A18D835809A07766)' | ||
``` | ||
|
||
## Interact with contract | ||
|
||
We will use Hardhat tasks to take care of parsing the values provided for each parameter. | ||
It gets the values, performs the type validation and converts them into your desired type. | ||
|
||
In this example, we will go through a set of predefined Hardhat tasks that use the [Hardhat Runtime Environment](https://hardhat.org/advanced/hardhat-runtime-environment.html). | ||
|
||
:::note | ||
The Hardhat Runtime Environment is an object containing all the functionality that Hardhat exposes when running a task, test or script. In reality, Hardhat is the HRE. | ||
|
||
To communicate with contracts from UI you will need a web3-library like [viem](https://viem.sh/docs/introduction), [ethers.js](https://docs.ethers.org/) or [web3.js](https://web3js.readthedocs.io/en). | ||
Hardhat uses ethers.js by default. | ||
::: | ||
|
||
If you want to complete all steps of this tutorial, you should execute the tasks in the same order they are mentioned below. | ||
But if you want just take a look at how to interact with some particular method - you can just use the code snippet as is. | ||
|
||
### Get total supply | ||
|
||
The following task script gets the total supply of the Watermelon ERC-20 token. | ||
First, it gets the token contract, then gets the sender address and then retrieves the total supply | ||
by calling `totalSupply()` method in our ERC-20 contract: | ||
|
||
```javascript | ||
task("totalSupply", "Total supply of ERC-20 token") | ||
.addParam("token", "Token address") | ||
.setAction(async function ({ token }, { ethers: { getSigners } }, runSuper) { | ||
const watermelonToken = await ethers.getContractFactory("WatermelonToken") | ||
const watermelon = watermelonToken.attach(token) | ||
const [minter] = await ethers.getSigners(); | ||
const totalSupply = (await (await watermelon.connect(minter)).totalSupply()).toNumber() | ||
console.log(`Total Supply is ${totalSupply}`); | ||
}); | ||
``` | ||
|
||
To get the total supply, just use the following command: | ||
|
||
```bash | ||
npx hardhat totalSupply --token $TOKEN_ADDRESS --network testnet_aurora | ||
``` | ||
|
||
### Transfer tokens | ||
|
||
The `transfer` method allows anyone holding ERC-20 tokens to transfer | ||
them to any EVM address (user or contract one). | ||
|
||
In the following script, the minter address | ||
will mint (implicitly) and transfer 10 WTM tokens to the spender address: | ||
|
||
```javascript | ||
task("transfer", "ERC-20 transfer") | ||
.addParam("token", "Token address") | ||
.addParam("spender", "Spender address") | ||
.addParam("amount", "Token amount") | ||
.setAction(async function ({ token, spender, amount }, { ethers: { getSigners } }, runSuper) { | ||
const watermelonToken = await ethers.getContractFactory("WatermelonToken") | ||
const watermelon = watermelonToken.attach(token) | ||
const [minter] = await ethers.getSigners(); | ||
await (await watermelon.connect(minter).transfer(spender, amount)).wait() | ||
console.log(`${minter.address} has transferred ${amount} to ${spender}`); | ||
}); | ||
``` | ||
|
||
To call the task now, please use the following command: | ||
|
||
```bash | ||
export $SPENDER_ADDRESS=HERE_GOES_THE_ADDRESS_TO_TRANSFER_TO | ||
npx hardhat transfer --token $TOKEN_ADDRESS --amount 10 --spender $SPENDER_ADDRESS --network testnet_aurora | ||
``` | ||
|
||
### Get a balance | ||
|
||
We can prove that spender has received the exact amount of tokens by calling the `balanceOf` as shown below: | ||
|
||
```javascript | ||
task("balanceOf", "Balance of ERC-20 token for particular user") | ||
.addParam("token", "Token address") | ||
.addParam("account", "Account address") | ||
.setAction(async function ({ token, account }, { ethers: { getSigners } }, runSuper) { | ||
const watermelonToken = await ethers.getContractFactory("WatermelonToken") | ||
const watermelon = watermelonToken.attach(token) | ||
const [minter] = await ethers.getSigners(); | ||
const balance = (await (await watermelon.connect(minter)).balanceOf(account)).toNumber() | ||
console.log(`Account ${account} has a total token balance: ${balance} WTM`); | ||
}); | ||
``` | ||
|
||
To get a balance, use the following command: | ||
|
||
```bash | ||
npx hardhat balanceOf --token $TOKEN_ADDRESS --account $SPENDER_ADDRESS --network testnet_aurora | ||
``` | ||
|
||
### Approve and TransferFrom | ||
|
||
In some cases, instead of calling the `transfer` directly, a sender | ||
can approve a specific amount of tokens to be withdrawn from his account | ||
to the recipient's address later. This can be done by calling `approve` and then calling `transferFrom` method. | ||
|
||
```javascript | ||
task("approve", "ERC-20 approve") | ||
.addParam("token", "Token address") | ||
.addParam("spender", "Spender address") | ||
.addParam("amount", "Token amount") | ||
.setAction(async function ({ token, spender, amount }, { ethers: { getSigners } }, runSuper) { | ||
const watermelonToken = await ethers.getContractFactory("WatermelonToken") | ||
const watermelon = watermelonToken.attach(token) | ||
const [sender] = await ethers.getSigners(); | ||
await (await watermelon.connect(sender).approve(spender, amount)).wait() | ||
console.log(`${sender.address} has approved ${amount} tokens to ${spender}`); | ||
}); | ||
|
||
module.exports = {}; | ||
``` | ||
|
||
To call `approve`, use the following command: | ||
|
||
```bash | ||
npx hardhat approve --token $TOKEN_ADDRESS --spender $SPENDER_ADDRESS --amount 10 --network testnet_aurora | ||
``` | ||
|
||
Now, after approving tokens, a recipient can call `transferFrom` to move | ||
the `allowance` to his account. | ||
|
||
```javascript | ||
task("transferFrom", "ERC-20 transferFrom") | ||
.addParam("token", "Token address") | ||
.addParam("sender", "Sender address") | ||
.addParam("amount", "Token amount") | ||
.setAction(async function ({ token, sender, amount }, { ethers: { getSigners } }, runSuper) { | ||
const watermelonToken = await ethers.getContractFactory("WatermelonToken") | ||
const watermelon = watermelonToken.attach(token) | ||
const [recipient] = await ethers.getSigners() | ||
console.log(recipient.address); | ||
await (await watermelon.connect(recipient).transferFrom(sender, recipient.address, amount)).wait() | ||
console.log(`${recipient.address} has received ${amount} tokens from ${sender}`) | ||
}); | ||
``` | ||
|
||
To call `transferFrom`, use the following command: | ||
|
||
```bash | ||
# export the spender's private key | ||
export AURORA_PRIVATE_KEY="THE RECIPIENT PRIVATE KEY" | ||
npx hardhat transferFrom --token $TOKEN_ADDRESS --sender $MINTER_ADDRESS --amount 10 --network testnet_aurora | ||
``` | ||
|
||
After this, you can check the balance of a recipient's account to make sure he has the tokens now. | ||
|
||
## Switch a network | ||
|
||
Optionally you can specify any of the following networks for any command: __testnet_aurora__, __mainnet_aurora__, __ropsten__ like this: | ||
|
||
```bash | ||
$ make deploy NETWORK=mainnet_aurora | ||
``` | ||
|
||
## Conclusion | ||
|
||
In this tutorial, we have deployed an ERC-20 token using Hardhat on the Aurora | ||
Testnet, transferred, and approved ERC-20 tokens. Moreover, we have added other | ||
utility tasks such as getting the total supply, and the account balance. |
Oops, something went wrong.