どうも、shoheiです。
大阪在住のフリーランスエンジニアです。現在はFlutterを使ってプロダクト開発をしています。
今回はFirebase Cloud Functionsを使ってCatapult APIの作り方を紹介します。
・Github
https://github.com/hukusuke1007/nem2_api_server
準備
Firebaseの設定を行います。Firebaseコンソールより、プロジェクトを作成してください。
作成後、Cloud Functionを利用できるようにしてください。
https://firebase.google.com/products/functions/?hl=ja
なお、Cloud FunctionにDeployして外部APIを利用する場合は有料の利用プランでないと利用することができません。
今回はローカル上で立ち上げたCloud Functionから利用する想定で紹介します。
お手元のターミナルで firebase init で Cloud Function のテンプレートを作成します。
firebase init
? Which Firebase CLI features do you want to setup for this folder? Press Space to select features, then Enter to confirm your choi
ces.
◯ Database: Deploy Firebase Realtime Database Rules
◯ Firestore: Deploy rules and create indexes for Firestore
❯◉ Functions: Configure and deploy Cloud Functions
◯ Hosting: Configure and deploy Firebase Hosting sites
◯ Storage: Deploy Cloud Storage security rules
A functions directory will be created in your project with a Node.js
package pre-configured. Functions can be deployed with firebase deploy.
? What language would you like to use to write Cloud Functions? TypeScript
? Do you want to use TSLint to catch probable bugs and enforce style? Yes
✔ Wrote functions/package.json
✔ Wrote functions/tslint.json
✔ Wrote functions/tsconfig.json
✔ Wrote functions/src/index.ts
✔ Wrote functions/.gitignore
? Do you want to install dependencies with npm now? Yes
構築が完了するとカレントディレクトリに functions ディレクトリが作成されます。
ディレクトリ構成は次の通りです。
.
├── package.json
├── src
│ └── index.ts
├── tsconfig.json
└── tslint.json
必要なライブラリをインストールします。
yarn add cors dotenv express inversify reflect-metadata nem2-sdk rxjs
yarn add --dev @types/cors @types/dotenv @types/express
package.json に node のバージョンを設定します。
"engines": {
"node": "10"
},
tsconfig.json を変更します。
{
"compilerOptions": {
"target": "es2017",
"lib": ["es2017", "dom"],
"module": "commonjs",
"noImplicitReturns": true,
"outDir": "lib",
"experimentalDecorators": true,
"moduleResolution": "node",
"types": ["reflect-metadata"],
"emitDecoratorMetadata": true,
"sourceMap": true
},
"compileOnSave": true,
"include": [
"src"
]
}
次に tslint.json をダウンロードして上書きしてください。
https://github.com/hukusuke1007/nem2_api_server/blob/master/functions/tslint.json
実装
っと言いたいところでしたが、全て解説するとかなり長くなるので既に用意しているコードを利用します。
ここの src ディレクトリをダウンロードして上書きしてください。
https://github.com/hukusuke1007/nem2_api_server/tree/master/functions/src
src ディレクトリ内の構成は次の通りです。
.
├── common
│ ├── Config.ts
│ └── Utils.ts
├── domain
│ ├── dto
│ │ ├── FaucetDTO.ts
│ │ ├── SendMosaicDTO.ts
│ │ └── response
│ │ └── ResponseBody.ts
│ ├── model
│ │ └── TransactionResult.ts
│ ├── repository
│ │ ├── AggregateTransactionRepository.ts
│ │ ├── TransactionRepository.ts
│ │ └── WalletRepository.ts
│ ├── type
│ │ └── Types.ts
│ └── use_case
│ └── CatapultUseCase.ts
├── index.ts
├── infrastructure
│ ├── AggregateTransactionDataSource.ts
│ ├── TransactionDataSource.ts
│ ├── WalletDatasource.ts
│ └── helper
│ └── ListenerHelper.ts
├── inversify.config.ts
└── presentation
└── v1
├── index.ts
└── router
├── catapult.ts
└── index.ts
src/presentation/v1/router/catapult.ts を見ると次のAPIを用意しています。
API | 機能 |
---|---|
wallet | Catapultのウォレット作成 |
faucet | Catapultコインを取得 |
sendMosaic | Catapultコインを送信 |
ノードの設定
dotenvsample から .env を作成します。
cp dotenvsample .env
それぞれの環境変数にノード情報を設定してください。
※ノードの情報はNEM2 Slackまで
# Blockchain network type
# MAIN_NET = 104
# TEST_NET = 152
# MIJIN = 96
# MIJIN_TEST = 144
NODE_NETWORK = 144
# Blockchain server URL
NODE_URL_SCHEME = 'https'
NODE_WS_SCHEME = 'https'
NODE_DOMAIN = ''
NODE_PORT = '3001'
# Blockchain generation hash
# curl https://XXXXX:3001/block/1
# is meta.generationHash
NODE_GENERATION_HASH = ''
FAUCET_PRIVATE_KEY = ''
次に動作確認用のshellを取り入れます。以下のディレクトリをダウンロードして functions ディレクトリ直下に保存してください。
https://github.com/hukusuke1007/nem2_api_server/tree/master/functions/request
全ての準備が整えば次のような構成になります。
├── .env
├── package-lock.json
├── package.json
├── node_modules
├── request
│ ├── address.sh
│ ├── faucet.sh
│ ├── sendMosaic.sh
│ ├── sendMosaicNoFee.sh
│ └── wallet.sh
├── src
│ ├── common
│ │ ├── Config.ts
│ │ └── Utils.ts
│ ├── domain
│ │ ├── dto
│ │ │ ├── FaucetDTO.ts
│ │ │ ├── SendMosaicDTO.ts
│ │ │ └── response
│ │ │ └── ResponseBody.ts
│ │ ├── model
│ │ │ └── TransactionResult.ts
│ │ ├── repository
│ │ │ ├── AggregateTransactionRepository.ts
│ │ │ ├── TransactionRepository.ts
│ │ │ └── WalletRepository.ts
│ │ ├── type
│ │ │ └── Types.ts
│ │ └── use_case
│ │ └── CatapultUseCase.ts
│ ├── index.ts
│ ├── infrastructure
│ │ ├── AggregateTransactionDataSource.ts
│ │ ├── TransactionDataSource.ts
│ │ ├── WalletDatasource.ts
│ │ └── helper
│ │ └── ListenerHelper.ts
│ ├── inversify.config.ts
│ └── presentation
│ └── v1
│ ├── index.ts
│ └── router
│ ├── catapult.ts
│ └── index.ts
├── tsconfig.json
├── tslint.json
└── yarn.lock
動作確認
ターミナルを二つ立ち上げます。
1つ目のターミナルでは次のコマンドで実行して Cloud Functions を起動します。
yarn serve
✔ functions: Using node@10 from host.
✔ functions: Emulator started at http://localhost:5000
i functions: Watching "/Users/hukusuke/Desktop/Start/Development/mokumoku/nem2_api_server/functions" for Cloud Functions...
✔ functions[v1-router-catapult-api]: http function initialized (http://localhost:5000/nem2-wallet-d3f63/asia-northeast1/v1-router-catapult-api).
2つ目のターミナルではCatapult APIに対してリクエストを送ります。
ウォレット作成
それでは、ウォレットを作成します。
先ほどダウンロードした request ディレクトリの wallet.sh を使います。
wallet.sh の API を利用するURLに書き換えてください。
API="http://localhost:5000/nem2-wallet-d3f63/asia-northeast1/v1-router-catapult-api" # ローカルで立ち上げたCloud FunctionのAPI
echo "--- Request ---"
curl -w '\n' -X GET $API/wallet
実行すると、ウォレットの情報が取れるのでメモします。
./request/wallet.sh
--- Request ---
{"status":200,"data":{"address":"SCG2E4AHU4NTL7EU2HY6ZY7PWMGLR462KQT6O5CV","privateKey":"E3413B6DD4E904A37BCC2F42A6A97094425E3BD918BCC3F49E3EBD66A2EED270","publicKey":"74ED318D28DFF3B7D63C6C24E297BE5AA2D28DD4C1352ED92FFE88E8FECFB48A","network":144}}
Catapultコイン獲得
次に faucet.sh を使ってCatapultコインを獲得します。
address に先ほど作成したウォレットアドレスに書き換えてください。
API="http://localhost:5000/nem2-wallet-d3f63/asia-northeast1/v1-router-catapult-api"
echo "--- Request ---"
curl -w '\n' -X POST $API/faucet \
-H "Content-Type: application/json" \
-d '
{
"address": "SADMO4S3Q7MN44YZFVQBU75ILFMRE2PDBE3WUXAE",
"amount": 70
}
'
実行するとコインを獲得できます。
./request/faucet.sh
--- Request ---
{"status":200,"data":{"message":"success","data":{"hash":"2A26241FC314F4C94CCA8B1B9709F149066BE69CC5F511C95522916B6161773B","isConfirmed":false,"data":{"transaction":{"type":16724,"network":144,"version":36865,"maxFee":"20000","deadline":"116260150514","signature":"BC1E649433C1CD4FFDB9DF9129E597DEC85D461D83FC1D52A1ACD420309EFE9A888A991344B3F14F0048919BB90E6CB9096ED8FC04BED3BEA52331EA55332C09","signerPublicKey":"9C7A61893BB7D8A39457D69C489F77B304F263A3BD927AF058432FCA65EA774D","recipientAddress":{"address":"SADMO4S3Q7MN44YZFVQBU75ILFMRE2PDBE3WUXAE","networkType":144},"mosaics":[{"amount":"20000000","id":"85BBEA6CC462B244"}],"message":{"type":0,"payload":""}}}}}}
残高確認
address.sh を使って残高を確認します。蛇口から取得後、トランザクションが承認させるまで少しだけ時間をあけてから確認してください。
ENDPOINT と TO_ADDRESS を書き換えて実行してください。
ENDPOINT="https://fushicho2-fee.opening-line.jp:3001"
TO_ADDRESS="SADMO4S3Q7MN44YZFVQBU75ILFMRE2PDBE3WUXAE"
echo "-- Address balance ---"
curl -w '\n' -X GET $ENDPOINT/account/$TO_ADDRESS
実行すると、amount で残高を確認できます。
./request/address.sh
-- Address balance ---
{"account":{"address":"9006C7725B87D8DE73192D601A7FA859591269E309376A5C04","addressHeight":"26135","publicKey":"0000000000000000000000000000000000000000000000000000000000000000","publicKeyHeight":"0","accountType":0,"linkedAccountKey":"0000000000000000000000000000000000000000000000000000000000000000","activityBuckets":[],"mosaics":[{"id":"59CFA2FBA9A4E6CD","amount":"70000000"}],"importance":"0","importanceHeight":"0"}}
Catapultコインを送信
sendMosaic.sh を使います。予め送信先のアカウントを wallet.sh から作成して準備してください。
fromPrivateKey, toAddress, amount を書き換えてください。
API="http://localhost:5000/nem2-wallet-d3f63/asia-northeast1/v1-router-catapult-api"
echo "--- Request ---"
curl -w '\n' -X POST $API/sendMosaic \
-H "Content-Type: application/json" \
-d '
{
"fromPrivateKey": "C8F8CAF55CA1796AAC31D552BFAF26948B3EE731237695B97DD5D34AC57BCFB3",
"toAddress": "SADMO4S3Q7MN44YZFVQBU75ILFMRE2PDBE3WUXAE",
"amount": 10
}
'
実行すると、送金できます。
./request/sendMosaic.sh
--- Request ---
{"status":200,"data":{"message":"success","data":{"hash":"C22A31BE67834D7990EC5261482298D96099D1AFA223430FB41A7DBF07AC8AD3","isConfirmed":false,"data":{"transaction":{"type":16724,"network":144,"version":36865,"maxFee":"20000","deadline":"116260910379","signature":"379939BD48DA8A4F2B66D2CF599F2C56F65F64EF504EB940337A646BB6E05114446B6B68074C4788ED9CAF59C3B726C00BB00417EBD8D0773A39350F2CCD990B","signerPublicKey":"2DD7E62D59564E3A2B04213BFDA532813BAF235A7D4959F4306BF24A5A37CE45","recipientAddress":{"address":"SADMO4S3Q7MN44YZFVQBU75ILFMRE2PDBE3WUXAE","networkType":144},"mosaics":[{"amount":"10000000","id":"85BBEA6CC462B244"}],"message":{"type":0,"payload":""}}}}}}
デプロイ
次のコマンドでCloud Functionsへデプロイできます。
yarn deploy
終わりに
Catapultノードがはやく安定してほしい(切実
本当はAggregateTransactionで手数料なくてもトランザクション発行できるよ〜っていうのを詳細に書きたかった。