#はじめに
FirebaseのCloud Functionsを使ってNode.js(TypeScript)のETH testnet用トークン配布システムを作ります
#事前準備
まず、何らかの方法でETHのアドレスと秘密鍵を用意してください
あらかじめtestnet(ここではrinkeby)のETHを入れておきましょう
#セットアップ
firebaseプロジェクトをこちらから作ってください
firebaseのCLI入れてない方は入れましょう
npm install -g firebase-tools
mkdir eth-faucet
cd eth-faucet
firebase login
firebase init
その後「Select a default Firebase project for this directory:」と言われるので先ほど作ったFirebaseのプロジェクトを選択
※反映されてない場合は「don't setup a default project」を選択し、あとでfirebase use --add [project-id]
とすればOK

TypeScriptを選択しTSLintも導入してもらいましょう
最後にFirebase Consoleでプロジェクトの課金設定をBlazeにします
理由は無料版だとfirebase関連以外の外部パッケージが使えないからです


#作っていく
Express, web3, ethreumjs-txを導入します
ExpressはNode.jsの最小限なフレームワークです
Expressの型定義ファイルもインストールします
cd functions
npm install --save express web3 ethereumjs-tx
npm install --save-dev @types/express
次にsrc/index.ts
を編集します
全体のコードはこちらです
import * as functions from 'firebase-functions';
import * as Express from 'express';
const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
const app = Express();
const networks = {
main: 'wss://mainnet.infura.io/ws/v3/',
ropsten: 'wss://ropsten.infura.io/ws/v3/',
kovan: 'wss://kovan.infura.io/ws/v3/',
rinkeby: 'wss://rinkeby.infura.io/ws/v3/'
};
// InfuraのAPI-KEY(作る)
const apiKey = 'YOUR-API-KEY';
// テストネット(ここではrinkebyを選択)
const network = networks.rinkeby;
// rinkebyネットワークに接続する処理
const getWeb3 = () => {
const provider = network + apiKey;
const web3 = new Web3(provider);
return web3;
}
app.get('/:address', async(req:Express.Request, res: Express.Response) => {
try {
const from = '用意したETHアカウントのアドレス';
const to = req.params.address;
const privateKey = '用意したETHアカウントの秘密鍵';
const amount = 0.01 // faucetとして配布したいETHの量
const web3 = getWeb3();
const value = web3.utils.toWei(amount.toString(), 'ether');
const gasParams = {
from: from,
to: to,
value: value,
}
const gasLimit = await web3.eth.estimateGas(gasParams);
const gasPrice = await web3.eth.getGasPrice();
const count = await web3.eth.getTransactionCount(from);
const data = null;
const id = await web3.eth.net.getId();
const params = {
nonce: web3.utils.numberToHex(count),
gasPrice: web3.utils.numberToHex(gasPrice),
gasLimit: web3.utils.numberToHex(gasLimit),
to: to,
from: from,
value: web3.utils.numberToHex(value),
data: data,
chainId: id
}
//Transaction作成
const tx = new Tx(params);
const _privateKey = Buffer.from(privateKey.slice(2), 'hex');
//Transactionに秘密鍵で署名
tx.sign(_privateKey);
const rawTx = '0x' + tx.serialize().toString('hex');
const result = await web3.eth.sendSignedTransaction(rawTx);
//Transactionを送信した結果がtrueならresponseを返す
if(result.status == true) {
res.send('送金が完了しました\n')
}
}
catch(error) {
res.status(500).send(error)
}
})
exports.app = functions.https.onRequest(app);
その後以下を実行
firebase deploy --only functions:app
そしてcurlでルートにETHの送り先アドレスを込めて叩く
curl https://us-central1-<project-id>.cloudfunctions.net/app/<送り先のアドレス>
コンソール上で送金が完了しましたと出ればOK
この時、Error: could not handle the request
のようにtimeout errorが出ることがありますがEtherscanでみるときちんと送金はされています