ユーザーにETHを送ろう
🎁 ユーザーに ETH を贈る
コントラクトの魅力の1つとして、コントラクトに関与したユーザーに報酬を支払える機能を実装できることが挙げらます。
よって、このレッスンでは、ETHをユーザーに送る機能をコントラクトに実装する方法を学びます。
まず、あなたのWebアプリケーションで「👋(wave)」を送ってくれた人に「0.0001ETH(≒$0.30)」を提供するスクリプトを作成していきます。
引き続き、Sepolia Test Network上にコントラクトをデプロイするので、ユーザーに送るのは偽のETHになります。
WavePortal.sol
のwave
関数を下記のように更新していきます。
function wave(string memory _message) public {
_totalWaves += 1;
console.log("%s waved w/ message %s", msg.sender, _message);
/*
* 「👋(wave)」とメッセージを配列に格納。
*/
_waves.push(Wave(msg.sender, _message, block.timestamp));
/*
* コントラクト側でemitされたイベントに関する通知をフロントエンドで取得できるようにする。
*/
emit NewWave(msg.sender, block.timestamp, _message);
/*
* 「👋(wave)」を送ってくれたユーザーに0.0001ETHを送る
*/
uint256 prizeAmount = 0.0001 ether;
require(
prizeAmount <= address(this).balance,
"Trying to withdraw more money than the contract has."
);
(bool success, ) = (msg.sender).call{value: prizeAmount}("");
require(success, "Failed to withdraw money from contract.");
}
コードを見ていきましょう。
まず、下記で
prizeAmount
という変数を定義し、0.0001
ETH を指定しています。uint256 prizeAmount = 0.0001 ether;
そして、下記では、ユーザーに送る ETH の額がコントラクトが持つ残高より下回っていることを確認しています。
require(
prizeAmount <= address(this).balance,
"Trying to withdraw more money than the contract has."
);
address(this).balance
はコントラクトが持つの資金の残高を示しています。
require
は、何らかの条件がtrue
もしくはfalse
であることを確認するif
文のような役割を果たします。 もしrequire
の結果がfalse
の場合(=コントラクトが持つ資金が足りない場合)は、トランザクションをキャンセルします。コントラクトに資金を提供する方法については、次のレッスンで説明します。
下記のコードはユーザーに送金を行うために実装されています。
(bool success, ) = (msg.sender).call{value:prizeAmount}("")
下記のコードは、トランザクション(=送金)が成功したことを確認しています。
require(success, "Failed to withdraw money from contract.");
成功した場合は送金を行い、成功しなかった場合は、エラー文を出力しています。
次に、WavePortal.sol
のconstructor
を下記のように変更します。
constructor() payable {
console.log("We have been constructed!");
}
payable
を加えることで、コントラクトに送金機能を実装します。
🏦 コントラクトに資金を提供する
上記で、ユーザーにETHを送金するためのコードを実装しました。 次に、その資金源となるETHをコントラクトに付与する作業を行います。
テストを実施するために、 run.js
を更新します。
run.js
はコントラクトのコア機能のテストを行うためのスクリプトです。
const main = async () => {
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
/*
* 0.1ETHをコントラクトに提供してデプロイする
*/
const waveContract = await waveContractFactory.deploy({
value: hre.ethers.utils.parseEther("0.1"),
});
await waveContract.deployed();
console.log("Contract deployed to:", waveContract.address);
/*
* コントラクトの残高を取得し、結果を出力(0.1ETHであることを確認)
*/
let contractBalance = await hre.ethers.provider.getBalance(
waveContract.address
);
console.log(
"Contract balance:",
hre.ethers.utils.formatEther(contractBalance)
);
/*
* Waveし、トランザクションが完了するまで待機
*/
let waveTxn = await waveContract.wave("A message!");
await waveTxn.wait();
/*
* Waveした後のコントラクトの残高を取得し、結果を出力(0.0001ETH引かれていることを確認)
*/
contractBalance = await hre.ethers.provider.getBalance(waveContract.address);
console.log(
"Contract balance:",
hre.ethers.utils.formatEther(contractBalance)
);
let allWaves = await waveContract.getAllWaves();
console.log(allWaves);
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();
詳しく見ていきましょう。
1 . 0.1ETH をコントラクトに提供する
const waveContract = await waveContractFactory.deploy({
value: hre.ethers.utils.parseEther("0.1"),
});
hre.ethers.utils.parseEther("0.1")
によって、コントラクトがデプロイされた際に、コントラクトに0.1 ETHの資金を提供することを宣言しています。
let contractBalance = await hre.ethers.provider.getBalance(
waveContract.address
);
ここでは、ethers.js
が提供しているgetBalance
関数を使って、コントラクトのアドレスに紐づいている残高をcontractBalance
に格納しています。
ethers.js
の公式ドキュメントは こちら(英語)です。
2 . コントラクトの資金を確認する
console.log("Contract balance:", hre.ethers.utils.formatEther(contractBalance));
ここでは、hre.ethers.utils.formatEther(contractBalance)
を使用してwei単位の残高をETH単位に変換したうえで出力し、コントラクトに0.1ETHの残高があるか確認しています。
3 . wave
したあとのコントラクトの残高を確認する
/*
* Wave
*/
let waveTxn = await waveContract.wave("A message!");
await waveTxn.wait();
/*
* Waveした後のコントラクトの残高を取得し、結果を出力(0.0001ETH引かれていることを確認)
*/
contractBalance = await hre.ethers.provider.getBalance(waveContract.address);
console.log("Contract balance:", hre.ethers.utils.formatEther(contractBalance));
ここでは、wave
が呼ばれた後に0.0001 ETH
がコントラクトの資金から差し引かれるか、確認しています。