Previous << 3 - 基本編Part3
Next >> 5 - 所持金表示
TL;DR Flowブロックチェーンのトランザクションって一体何?
ブロックチェーンのトランザクションはブロックチェーンの書き換え処理をブロックに詰めて世界中のノードに伝播させて、新しいブロックが入ったブロックチェーン情報を共有してもらうことを意味します。
前回はFlow CLIを使ってトランザクションを行いました。しかし、それは実際にシステムで使用するものではなく、CLIの便利機能だと思ってください。
システムでトランザクションを実行する時にはFCL(flow client library)を使用します。これはJavaScriptのライブラリです。
また、前回書いたようにトランザクションには0.001円ほどの費用がかかります。これは、仕方がないのです。迷惑メールは誰もが貰った事があると思います。あれは何故起きるかというと、メール送信が無料だからです。ブロックチェーンは世界中に散らばったノードに等しい情報を伝播させる必要があります。もし無料であればそのネットワークはスパム攻撃でパンクしてしまいます。それに対処する目的で費用が発生します。
FCL(flow client library)はブラウザからスマートコントラクトにアクセスする為のライブラリ以外にも使い道があります。そうです、Node.jsもブラウザのJavaScriptと全く同じように動きますから、サーバーサイドでも使えるのです。
先程費用が発生する、と書きましたがどうやって支払うのでしょう?そんなお金持ってません、と言われるかも知れません。でも大丈夫、最低限のお金はアカウントを作成した時にウォレットが用意してくれます。おぉ、なんと親切。あと、トランザクション費用は、基本的にはウォレットが代わりに支払ってくれます。だから大丈夫です。
じゃあ、サーバーサイドからトランザクションを実行する時は?
自分で用意します。お金であるFLOWを持ってないとトランザクションは失敗します。そのお金ってどうやって管理しているの?というと、実はこれはResourceで、誰もがアカウント作成時から持っています。アカウントを作成する時にアカウント作成者が必要最低限のお金を負担するので、誰もが最初からこのResourceを持っています。
しかし、トランザクションを実行するだけの余分なお金が最初は無いので、サーバーサイドから実行する時には誰かからお金(0.001円)をもらう必要があります。アドレスはアカウント作成時に分かりますから、ウォレットなどを使って送金しておきます。それで初めてサーバーサイドからトランザクションを実行できます。
サーバーサイドから実行する時は、ウォレットがやっている事を自分でするんだ、と思ってください。最初は送金を自分でやることから始めるといいでしょう。
こちらもJacob Tucker氏の動画を参考にするといいでしょう。2つあります。
▶️ https://www.youtube.com/watch?v=VEbQYACodqg
▶️ https://www.youtube.com/watch?v=vmo_FaMe6p0
Why Flow
FLOW(または$FLOW)トークンは、Flowネットワークのネイティブ通貨です。開発者およびユーザーは、FLOWを使用してネットワーク上で取引(transact)を行うことができます。開発者は、ピアツーピア決済(他人同士の決済)、サービス料金徴収、または消費者向け特典(rewards)のために、FLOWを直接アプリに統合することができます。
ということでやっていきます、P2P(ピアツーピア)決済アプリ開発!
💡もし、エミュレータの起動方法やスマートコントラクトのデプロイについて操作に自信がない場合はこちらを参照してください。
承認者、支払者 そして 提案者
Flowには3種類の承認関数をトランザクションでセットする必要があり、それぞれ、アカウントの変更権限を持つ承認者、トランザクションフィーを支払う支払者、Dos攻撃に対応するための提案者です。Dos攻撃に対応するための提案者アドレスは、短期間にトランザクションを繰り返す場合、トランザクションの度にキーIDを変更してローテーションさせる必要があります。
これらの承認関数はブラウザでトランザクション実行に使用する場合はウォレットが処理を引き継いで行う専用のメソッドがありますが、バックエンドでトランザクション実行をする場合は自分たちで作成する必要があります。
Non-Custodial Account
バックエンドでトランザクションを行うとき、それは専らAdmin処理ということになります。代表的なAdmin処理としてここではFLOWトークン送金をバックエンドで行います。バックエンドで行う場合、ウォレットを使わずに秘密鍵を使ってトランザクションを実施します。この方法をNon-Custodial
方式といいます。バックエンドでは秘密鍵を堅牢に管理できるためです。
バックエンドでトランザクションを実行するときは秘密鍵(private key)を必要としますが、絶対にGithubに保存しないでください。.gitignoreなどのファイルを使用して秘密鍵が漏洩しないように注意してください。
バックエンドでトランザクションを実行する手順は:
- FCLをnpmでインストール
- sha3とellipticをnpmでインストール(Flowで使われるハッシュ関数や署名関数に必要)
npm install @onflow/fcl --save-dev
npm install elliptic sha3 --save-dev
- FlowTokenを送金するプログラムを書きます。(
5.01FLOW
送金します、Mainnet)
const fcl = require("@onflow/fcl");
const { SHA3 } = require("sha3");
var EC = require("elliptic").ec;
var ec = new EC("p256");
require("dotenv").config();
fcl
.config()
.put("flow.network", "mainnet")
.put("accessNode.api", "https://rest-mainnet.onflow.org");
// CHANGE THESE THINGS FOR YOU
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const ADDRESS = process.env.ADDRESS;
const KEY_ID = parseInt(process.env.KEY_ID);
const hash = (message) => {
const sha = new SHA3(256);
sha.update(Buffer.from(message, "hex"));
return sha.digest();
};
const sign = (message) => {
const key = ec.keyFromPrivate(Buffer.from(PRIVATE_KEY, "hex"));
const sig = key.sign(hash(message)); // hashMsgHex -> hash
const n = 32;
const r = sig.r.toArrayLike(Buffer, "be", n);
const s = sig.s.toArrayLike(Buffer, "be", n);
return Buffer.concat([r, s]).toString("hex");
};
async function authorizationFunction(account) {
return {
...account,
tempId: `${ADDRESS}-${KEY_ID}`,
addr: fcl.sansPrefix(ADDRESS),
keyId: Number(KEY_ID),
signingFunction: async (signable) => {
return {
addr: fcl.withPrefix(ADDRESS),
keyId: Number(KEY_ID),
signature: sign(signable.message),
};
},
};
}
async function sendTx() {
const addr = process.env.RECIPIENT_ADDRESS;
const transactionId = await fcl.mutate({
cadence: `
import FungibleToken from 0xf233dcee88fe0abe
import FlowToken from 0x1654653399040a61
transaction(amount: UFix64, to: Address) {
let vault: @FlowToken.Vault
prepare(signer: auth(BorrowValue) &Account) {
self.vault <- signer.storage
.borrow<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>(from: /storage/flowTokenVault)!
.withdraw(amount: amount) as! @FlowToken.Vault
}
execute {
getAccount(to)
.capabilities
.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
.borrow()!
.deposit(from: <-self.vault)
}
}
`,
args: (arg, t) => [arg(5.01, t.UFix64), arg(addr, t.Address)],
payer: authorizationFunction,
proposer: authorizationFunction,
authorizations: [authorizationFunction],
limit: 999,
});
console.log({ transactionId });
fcl.tx(transactionId).subscribe((res) => {
console.log(res);
});
}
sendTx();
(ハッシュ関数や署名関数の詳細についてはこちらやこちら、およびこちらをご確認ください。)
- Node.jsで送金を実行します。
node sendFlow.js
Deprecation メッセージが出ていますが、このようにSEALEDとなったら送金は成功しています。Bloctoウォレットなどで確認してみましょう。
この記事のソースコードはこちらにあります。