はじめに
こちらの続きで、コントラクトへの委任をして、ICOのようにユーザがコントラクトアドレスへETHを送金したら、rateに応じてERC20トークンが送られる簡易的な仕組みを体験してみましょう。
※ 本記事はICOを推奨するものではありません。ICOは日本国内や海外においても規制上実施するのは困難です。ICOを行うと違法の可能性があります。本記事で扱うコントラクトは簡易的なものであり、mainnetで使用された場合に事故が発生しても責任は負いません。
コントラクトへの委任
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TokenVendingContract {
ERC20 public ERC20Token;
address public TokenOwner;
uint256 private weiAmount;
uint256 private weiBalance;
function TokenVending(address _ERC20Token, address payable _TokenOwner) public {
ERC20Token = ERC20(_ERC20Token);
TokenOwner = _TokenOwner;
}
function withdrawal(uint withdraw_amount) private {
ERC20Token.transferFrom(TokenOwner, msg.sender, withdraw_amount);
}
receive() external payable {
weiAmount = msg.value;
withdrawal(weiAmount * 1000);
}
function withdrawEth(address payable _to, uint _value) public {
require(msg.sender == TokenOwner, "Token owner only can withdrawal eth!");
weiBalance = address(this).balance;
require(_value <= weiBalance, "Withdrawal amount exceeds balance!");
_to.transfer(_value);
}
}
Remixで新しい.solファイルを用意し、上記リンク先のコードをコピーします。
適当なアカウント(以下、エレンとします)をMetamaskでセットし、デプロイします。
デプロイできました。
デビットの残高を取得。
Metamaskのアカウントをデビットに切り替え。
デプロイしたコントラクトのアカウントをコピーし、トークンコントラクトapprove欄のspenderに入力。
amountはデビットの残高の範囲内に設定します。
↑ApproveしたTXです。
allowance関数にownerをデビットのアカウント、spenderを自動販売機コントラクトのアカウントを設定して、callすると委任された額が表示されています。
トークン自動販売機のコントラクトの方に移り、、ERC20Token、TokenOwner関数を実行してもまだ設定していないので、0x00000...となります。
TokenVending関数の_ERC20Tokenにトークンコントラクトアカウントを、_TokenOwnerにトークンを委任してapproveしたアカウント(ここではデビット)を入れて実行します。
↑実行結果です。
ERC20Token、TokenOwnerにアカウントがセットされていることがわかります。
コントラクトへの送金
トークン自動販売機コントラクトアカウントへRopstenでETHを送金してみましょう。
↑送金結果がこちら
contract TokenVendingContract {
ERC20 public ERC20Token;
address public TokenOwner;
uint256 private weiAmount;
uint256 private weiBalance;
function TokenVending(address _ERC20Token, address payable _TokenOwner) public {
ERC20Token = ERC20(_ERC20Token);
TokenOwner = _TokenOwner;
}
function withdrawal(uint withdraw_amount) private {
ERC20Token.transferFrom(TokenOwner, msg.sender, withdraw_amount);
}
receive() external payable {
weiAmount = msg.value;
withdrawal(weiAmount * 1000);
}
}
上記抜粋したコードの中に、下記1行があるように、ETHの額の1000倍のERC20トークンを返すRateをベタ書きで設定しています。
withdrawal(weiAmount * 1000);
貯まったETHの引き出し
貯まったETHを引き出す関数も用意しています。
function withdrawEth(address payable _to, uint _value) public {
require(msg.sender == TokenOwner, "Token owner only can withdrawal eth!");
weiBalance = address(this).balance;
require(_value <= weiBalance, "Withdrawal amount exceeds balance!");
_to.transfer(_value);
}
↓実行できるのはコントラクトに登録されたトークンオーナーに限定しています。
↓また、コントラクト内のETH残高を超える送金を抑止しています。
↑実行結果です。引き出せていることを確認できました。












