lesson-2_独自トークン発行、swap機能の実装をしよう
🪙 独自トークンを発行するコントラクトを作成しよう
ではいよいよスマートコントラクトの実装に移ります。まずはこの送金アプリで使うトークンを発行するためのコントラクトを作成しましょう。
今回はOpenZepplinが公開しているライブラリを使用するのでとても簡略化できます。このライブラリを使用することによってトークンの授受や指定したアドレスの残高照会のための関数を簡単かつ安全に使用することができます。
1つ前のレッスンで作成したERC20Tokens.sol
ファイルに以下の内容を追記しましょう。
[ERC20Tokens.sol
]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract DaiToken is ERC20 {
constructor(address contractAddress) ERC20('Dai Token', "DAI") {
_mint(contractAddress, 1000000 ether);
}
}
contract EthToken is ERC20 {
constructor(address contractAddress) ERC20('Ethereum Token', "ETH") {
_mint(contractAddress, 100000 ether);
}
}
contract AuroraToken is ERC20 {
constructor(address contractAddress) ERC20('Aurora Token', "AOA") {
_mint(contractAddress, 1000000 ether);
}
}
contract ShibainuToken is ERC20 {
constructor(address contractAddress) ERC20('Shibainu Token', "SHIB") {
_mint(contractAddress, 1000000 ether);
}
}
contract SolanaToken is ERC20 {
constructor(address contractAddress) ERC20('Solana Token', "SOL") {
_mint(contractAddress, 1000000 ether);
}
}
contract TetherToken is ERC20 {
constructor(address contractAddress) ERC20('Tether Token', "USDT") {
_mint(contractAddress, 1000000 ether);
}
}
contract UniswapToken is ERC20 {
constructor(address contractAddress) ERC20('Uniswap Token', "UNI") {
_mint(contractAddress, 1000000 ether);
}
}
contract PolygonToken is ERC20 {
constructor(address contractAddress) ERC20('Polygon Token', "Matic") {
_mint(contractAddress, 1000000 ether);
}
}
まずは下の一行によってOpenZepplinが発行しているERC20
のライブラリが使用できるようにします。
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
全て同じように書いているので、その中の1つを見ていきましょう。一番最初に書いてあるDaiToken
というコントラクトの内容は以下のようになっています。
contract DaiToken is ERC20 {
constructor(address contractAddress) ERC20('Dai Token', "DAI") {
_mint(contractAddress, 1000000 ether);
}
}
ERC20
という規格を継承しており、引数としてcontractAddress
を持っていることがわかります。
その次に名前、symbolを記述しています。constructorはコントラクトがdeployされた時に一度だけ最初に呼ばれる関数で、その中に_mint
関数が呼ばれています。
ここでは引数として受け取るcontractAddress
と発行数として1000000 ether
を指定しています。このether
というのは10の18乗
を示しており、100万ether分発行することを表しています。
etherの最小単位wei
は10の-18乗
であり、発行数の単位はweiなので気をつけるようにしましょう。
このように
- トークンの名前
- トークンのsymbol(ETH等)
- トークンの初期オーナー
- 発行枚数
を指定したものをそれぞれコントラクトとして記述しています。
_mint
関数の中で引数として取っている数字はトークンの発行数です。この値によって次に実装するswap機能を備えた送金機能が動きます。
例えば1ETHに対して10AOAが同等な価値を持っているとすれば、10ETHをスマートコントラクトに送ると100AOAが送金先に届くということです。
このswap機能がうまく働いていることを理解するために、発行数は上記で書いた通り、つまりETHだけ10万x10の18乗で他のトークンは100万x10の18乗にしておくのがいいと思います。
アプリが完成してから発行数を変えてもう一度デプロイしてもいいですね!
💥 swap 機能を備えた送金コントラクトを実装しよう
次はメインである swap 機能
を含んだトークンの送金機能を作成していきます。
実装に入る前に今回のプロジェクトの概要を把握しておきましょう。まず送金者は
(1)送金したいトークン
(2)送金したい量
を決めることができます。
また、受け取り手のトークンの種類を指定することができます。
ここで必要となってくる機能がswap機能です。スマートコントラクトが仲介役となって送金者からトークンを受け取り、それと同等の価値を持った量のトークンを受信者に送るというものです。
これがこのコントラクトの概要となります。では早速実装に移っていきましょう。Swap.sol
の中身を以下のようにしましょう。
[Swap.sol
]
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
// Import this file to use console.log
import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract SwapContract{
address public deployerAddress;
constructor() payable{
deployerAddress = msg.sender;
}
// calculate value between two tokens
function calculateValue(address tokenSendAddress, address tokenReceiveMesureAddress) public view returns (uint256 value){
value = (1 ether) * IERC20(tokenSendAddress).balanceOf(address(this)) / ERC20(tokenReceiveMesureAddress).balanceOf(address(this));
}
// distribute token to users
function distributeToken(address tokenAddress, uint256 amount, address recipientAddress) public {
require(msg.sender == deployerAddress, "Anyone but deployer can distribute token!");
IERC20 token = IERC20(tokenAddress);
token.transfer(recipientAddress, amount);
}
// swap tokens between two users
function swap(address sendTokenAddress, address measureTokenAddress, address receiveTokenAddress, uint256 amount, address recipientAddress) public payable{
IERC20 sendToken = IERC20(sendTokenAddress);
IERC20 receiveToken = IERC20(receiveTokenAddress);
uint256 sendTokenValue = calculateValue(sendTokenAddress, measureTokenAddress);
uint256 receiveTokenValue = calculateValue(receiveTokenAddress, measureTokenAddress);
uint256 sendAmount = amount * sendTokenValue / (1 ether);
uint256 receiveAmount = amount * receiveTokenValue / (1 ether);
require(sendToken.balanceOf(msg.sender) >= sendAmount, "Your asset is smaller than amount you want to send");
require(receiveToken.balanceOf(address(this)) >= receiveAmount, "Contract asset of the currency recipient want is smaller than amount you want to send");
sendToken.transferFrom(msg.sender, address(this), sendAmount);
receiveToken.transfer(recipientAddress, receiveAmount);
}
}