2
Help us understand the problem. What are the problem?

posted at

updated at

ERC20開発ハンズオン3(コントラクトへの委任編)

はじめに

こちらの続きで、コントラクトへの委任をして、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ファイルを用意し、上記リンク先のコードをコピーします。

スクリーンショット 2022-04-03 14.44.36.png

適当なアカウント(以下、エレンとします)をMetamaskでセットし、デプロイします。

デプロイできました。

デビットの残高を取得。

スクリーンショット 2022-04-03 14.50.07.png

Metamaskのアカウントをデビットに切り替え。

スクリーンショット 2022-04-03 14.46.05.png

デプロイしたコントラクトのアカウントをコピーし、トークンコントラクトapprove欄のspenderに入力。

amountはデビットの残高の範囲内に設定します。

スクリーンショット 2022-04-03 14.47.00.png

↑ApproveしたTXです。

スクリーンショット 2022-04-03 14.59.13.png

allowance関数にownerをデビットのアカウント、spenderを自動販売機コントラクトのアカウントを設定して、callすると委任された額が表示さてます。

トークン自動販売機のコントラクトの方に移り、、ERC20TokenTokenOwner関数を実行してもまだ設定していないので、0x00000...となります。

スクリーンショット 2022-04-03 14.55.22.png

スクリーンショット 2022-04-03 14.57.34.png

TokenVending関数の_ERC20Tokenにトークンコントラクトアカウントを、_TokenOwnerにトークンを委任してapproveしたアカウント(ここではデビット)を入れて実行します。

↑実行結果です。

スクリーンショット 2022-04-03 15.03.35.png

ERC20TokenTokenOwnerにアカウントがセットされていることがわかります。

コントラクトへの送金

スクリーンショット 2022-04-03 15.06.10.png

トークン自動販売機コントラクトアカウントへRopstenでETHを送金してみましょう。

スクリーンショット 2022-04-03 15.11.24.png

↑送金結果がこちら

TokenVendingMachine.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);
    }
}

上記抜粋したコードの中に、下記1行があるように、ETHの額の1000倍のERC20トークンを返すRateをベタ書きで設定しています。

withdrawal(weiAmount * 1000);

貯まったETHの引き出し

貯まったETHを引き出す関数も用意しています。

TokenVendingMachine.sol
    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);
	}

スクリーンショット 2022-04-03 15.22.05.png

↓実行できるのはコントラクトに登録されたトークンオーナーに限定しています。

スクリーンショット 2022-04-03 15.15.20.png

↓また、コントラクト内のETH残高を超える送金を抑止しています。

スクリーンショット 2022-04-03 15.18.31.png

↑実行結果です。引き出せていることを確認できました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
2
Help us understand the problem. What are the problem?