payableな関数にすればコントラクトへの送金と引き出しが可能になります。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
// 価格情報を取得するためにオラクル(chainlink)のインターフェースをインポートする
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract FundMe {
// 送金元のアドレスと送金された数量をマッピングする
// 送金元のアドレスを指定してcallすれば送金された数量が確認できるようになる
mapping(address => uint256) public addressToAmountFunded;
// 送金元一覧を作成する
address[] public funders;
// コントラクトの所有者がだれか確認できるようにする
address public owner;
// デプロイした人をコントラクトの所有者とする
// constructorはデプロイ後すぐに実行される
constructor() {
owner = msg.sender;
}
// コントラクトに送金する関数(payableにしたら送金可能な関数になる)
function fund() public payable {
// 送金が5ドル以上でないと拒否する
uint256 minimumUSD = 5 * 10 ** 18;
require(getConversionRate(msg.value) >= minimumUSD, "You need more ETH");
// 送金元が送金した数量をマッピングに記録する(msg.senderは送金元のアドレス、msg.valueは送金された数量)
addressToAmountFunded[msg.sender] += msg.value;
// 送金元一覧に追加する
funders.push(msg.sender);
}
// ETH/USDの最新為替情報を取得する関数(Chainlinkのコントラクトを使用)
function getPrice() public view returns (uint256) {
// インターフェースをpriceFeedという名前で読み込む
// インターフェースがデプロイされているアドレスは資料を参照(https://docs.chain.link/docs/ethereum-addresses/)
AggregatorV3Interface priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
// 価格情報を取得する
// 使わない変数は/*と*/で囲ってあげるとすっきりします
(/*uint80 roundId*/,
int256 answer,
/*uint256 startedAt*/,
/*uint256 updatedAt*/,
/*uint80 answeredInRound*/)
= priceFeed.latestRoundData();
// 価格情報を戻す
return uint256(answer * 10000000000);
}
// ETHの数量を入力したらUSD価格を返す関数
function getConversionRate(uint256 ethAmount) public view returns (uint256) {
// 上で定義したgetPrice()でETH/USDの為替を取得し、入力したETHの数量を掛けて戻す
uint256 ethPrice = getPrice();
uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
return ethAmountInUsd;
}
// 関数実行の前提条件をmodifierで定義する
modifier onlyOwner {
// コントラクトの所有者のみ引き出しが可能
require(msg.sender == owner, "Must be the owner of this contract");
_; // 前提が満たされればmodifierを利用している関数を実行
}
// コントラクトに溜まっているETHを全額引き出す関数
// onlyOwnerというmodifierを挟むことでコントラクトの所有者のみ実行できるようにする
function withdraw() payable onlyOwner public {
// thisとはこのコントラクトが保存されているデプロイされているアドレス
payable(msg.sender).transfer(address(this).balance);
// 送金元一覧のインデックス0から最後まで繰り返し
for (uint256 funderIndex=0; funderIndex < funders.length; funderIndex++) {
address funder = funders[funderIndex];
// 送金した数量を0にリセットする
addressToAmountFunded[funder] = 0;
}
// 送金元一覧を空にする
funders = new address[](0);
}
}
ETH/USDの価格情報はオラクル(Chainlink)から取得しているため、ローカルではなくKovanテスト環境でデプロイする必要があります。KovanのETHが欲しければChainlinkのfaucetから取得可能です。
Kovanテスト環境にデプロイするためには、ENVIRONMENTに「Injected Web3」を選択し、MetamaskをRemixに接続し、自分のCONTRACTを指定してDEPLOYをクリックし、Metamaskで承認します。
getPrice()
関数などはviewタイプなので価格取得する際にガス代は発生しません。