はじめに
こちらの続きで、コントラクトへの委任をして、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残高を超える送金を抑止しています。
↑実行結果です。引き出せていることを確認できました。