Previous << FCL Reference
Next >> Authentication
Overview
このリファレンスでは、FCL経由でアクセスできるSDKで利用可能なメソッドを説明し、それらのメソッドの動作について詳しく説明しています。FCL/SDKはオープンソースであり、ライセンスに従ってご利用いただけます。
ライブラリクライアントの仕様は、こちらでご覧いただけます。
Getting Started
Installing
FCL経由でFlow SDKにアクセスしますのでFCLをインストールします。
NPM:
npm install --save @onflow/fcl @onflow/types
Yarn:
yarn add @onflow/fcl @onflow/types
Importing the Library
javascriptでインポートできます。
import * as fcl from "@onflow/fcl"
import * as types from "@onflow/types"
Connect
デフォルトでは、ライブラリはアクセスノードとの通信にHTTPを使用します。そして、正しいアクセスノードAPI URLで設定されていといけません。ホストに到達できない場合、エラーが返されます。
📖HTTP/REST APIの情報はこちらでご確認いただけます。Flow HTTP/RESTのパブリックアクセスノードは、以下からアクセスできます。
- Testnet
https://rest-testnet.onflow.org
- Mainnet
https://rest-mainnet.onflow.org
- Local Emulator
127.0.0.1:8888
Example:
import { config } from "@onflow/fcl"
config({
"accessNode.api": "https://rest-testnet.onflow.org"
})
Querying the Flow Network
アクセスノードとの接続が確立されたら、Flowネットワークにqueryで問い合わせて、ブロック、アカウント、イベント、トランザクションに関するデータを取得することができます。以下では、これらのデータをそれぞれ取得する方法について説明していきます。
Get Blocks
ネットワークにIDと高さによるブロックをqueryします、または最新のブロックの取得します。
📖 ブロックIDは、ブロックペイロード全体のSHA3-256 hashです。このハッシュは、(GetLatestBlock
からのレスポンスなど)ブロックレスポンスオブジェクトのIDとして保存されています。
📖 ブロック高さは、チェーン上のブロックの高さを表します。最新のブロック高さは、有効なブロックが生成されるごとに1ずつ増加します。
Examples
この例では、最新のブロックの取得方法と、高さまたはIDによるその他のブロックの取得方法を説明しています。
import * as fcl from "@onflow/fcl";
/* Get latest block */
const latestBlock = await fcl.latestBlock(true); // If true, get the latest sealed block
/* Get block by ID (uses builder function) */
await fcl.send([fcl.getBlock(), fcl.atBlockId("23232323232")]).then(fcl.decode);
/* Get block at height (uses builder function) */
await fcl.send([fcl.getBlock(), fcl.atBlockHeight(123)]).then(fcl.decode)
Result output: BlockObject
Get Account
任意のアカウントを、Flowネットワークの最新ブロックまたは指定したブロック高さから取得します。
📖 Account addressは、アカウントを一意に識別するものです。0x
という接頭辞に注意してください。デフォルトの表現ではこの接頭辞を使うべきですが、ユーザーが入力する接頭辞がない表現については慎重に安全に処理してください。
アカウントには以下のデータが含まれます。
- Address:アカウントのアドレス。
- Balance:アカウントの残高。
- Contracts:アカウントにデプロイされたコントラクトのリスト。
- Keys:アカウントに関連付けられたキーのリスト。
Examples
最新のブロックからと、特定のブロック高さからアカウントを取得する方法を例示します。
import * as fcl from "@onflow/fcl";
/* Get account from latest block height */
const account = await fcl.account("0x1d007d755706c469");
/* Get account at a specific block height */
fcl.send([
fcl.getAccount("0x1d007d755706c469"),
fcl.atBlockHeight(123)
]);
Result output: AccountObject
Get Transactions
トランザクションIDを指定して、ネットワークからトランザクションを取得します。 トランザクションを送信した後、ステータスを確認するためにトランザクションの結果を取得することもできます。
📖 トランザクションIDは、エンコードされたトランザクションペイロードのハッシュであり、ネットワークにトランザクションを送信する前に計算することができます。
⚠️ 提供するトランザクションIDは、直近のspork以降のものでなければなりません。
📖 トランザクションステータスは、ブロックチェーン上のトランザクションの状態を表します。ステータスは、sealedされるまでは変更される可能性があります。
Status | Final | Description |
---|---|---|
UNKNOWN | ❌ | The transaction has not yet been seen by the network |
PENDING | ❌ | The transaction has not yet been included in a block |
FINALIZED | ❌ | The transaction has been included in a block |
EXECUTED | ❌ | The transaction has been executed but the result has not yet been sealed |
SEALED | ✅ | The transaction has been executed and the result is sealed in a block |
EXPIRED | ✅ | The transaction reference block is outdated before being executed |
import * as fcl from "@onflow/fcl";
/* Snapshot the transaction at a point in time */
fcl.tx(transactionId).snapshot();
/* Subscribe to a transaction's updates */
fcl.tx(transactionId).subscribe(callback);
/* Provides the transaction once the status is finalized */
fcl.tx(transactionId).onceFinalized();
/* Provides the transaction once the status is executed */
fcl.tx(transactionId).onceExecuted();
/* Provides the transaction once the status is sealed */
fcl.tx(transactionId).onceSealed();
Result output: TransactionStatusObject
Get Events
指定されたブロックの高さの範囲内にある、またはブロックIDのリストから、指定された型のイベントを取得します。
📖 Event typeは、標準フォーマットに従った文字列です。
A.{contract address}.{contract name}.{event name}
イベントに関する詳細をドキュメントで確認してください。このスタンダードに対する例外はcore eventsであり、このドキュメントで詳細をご確認ください。
📖 Block height rangeは、チェーン内の開始ブロックと終了ブロックの高さを表します。
Examples
ブロックの範囲内および複数のブロックIDでイベントを取得する方法を示します。
import * as fcl from "@onflow/fcl";
/* Get events at block height range */
await fcl
.send([
fcl.getEventsAtBlockHeightRange(
"A.7e60df042a9c0868.FlowToken.TokensWithdrawn", /* event name */
35580624, /* block to start looking for events at */
35580624
/* block to stop looking for events at */
),
])
.then(fcl.decode);
/* Get events from list of block ids */
await fcl
.send([
fcl.getEventsAtBlockIds("A.7e60df042a9c0868.FlowToken.TokensWithdrawn", [
"c4f239d49e96d1e5fbcf1f31027a6e582e8c03fcd9954177b7723fdb03d938c7",
"5dbaa85922eb194a3dc463c946cc01c866f2ff2b88f3e59e21c0d8d00113273f",
]),
])
.then(fcl.decode);
Result output: EventObject
Get Collections
同じブロックに含まれているトランザクションの塊を取得します。これをcollectionsと呼びます。コレクションは、ブロックあたりのトランザクション数を増やすことで、コンセンサス処理のスループットを向上させるために使用され、それらはブロックとトランザクションの間のリンクとして働きます。
📖 コレクションIDは、collectionペイロードのSHA3-256ハッシュです。
コレクションの取得例:
import * as fcl from "@onflow/fcl";
const collection = await fcl
.send([
fcl.getCollection(
"cccdb0c67d015dc7f6444e8f62a3244ed650215ed66b90603006c70c5ef1f6e5"
),
])
.then(fcl.decode);
Result output: CollectionObject
Execute Scripts
スクリプトを使用すると、Flowブロックチェーン上で変更が発生しない任意のCadenceコードを書いて、そのデータを受け取ることができます。Cadenceはこちらに、スクリプトについてはこちらで詳しく説明されていますが、現時点で私達はスクリプトコードの実行とデータの取得のみに興味を持ちます。
Flowブロックチェーンの最新の状態に対してスクリプトを実行することもできますし、ブロックの高さまたはブロックIDで定義されたヒストリーの特定の時点でスクリプトを実行することもできます。
📖 ブロックIDはブロックのペイロード全体の SHA3-256 ハッシュですが、ブロックのレスポンスのプロパティからその値を取得できます。
📖 ブロック高さはチェーン内のブロックの高さを表します。
import * as fcl from "@onflow/fcl";
const result = await fcl.query({
cadence: `
access(all) fun main(a: Int, b: Int, addr: Address): Int {
log(addr)
return a + b
}
`,
args: (arg, t) => [
arg(7, t.Int), // a: Int
arg(6, t.Int), // b: Int
arg("0xba1132bc08f82fe2", t.Address), /* addr: Address */
],
});
Example output:
console.log(result); /* 13 */
Mutate Flow Network
Flowは、他の多くのブロックチェーンと同じ様に、共有されたグローバルチェーンの状態を変化させるトランザクションを誰でも送信することができます。トランザクションは、状態の変化を記述したペイロードと、特定アカウントによる所有状態の変化を許可した1つ以上の承認、を含むオブジェクトです。
トランザクションデータは、SDKの助けを借りて、作成/署名されます。署名されたトランザクションのペイロードは、その後、アクセスノードAPIに送信されます。トランザクションが無効であった場合、または正しい数の承認署名が用意されていなかった場合、トランザクションは拒否されます。
Transactions
トランザクションとは署名済みのデータセットでしかなく、どのようにネットワークの状態を変化させるかと、その実行を定義したり制限したりするプロパティを指示したスクリプト・コードを含んでいます。これらのプロパティについては、以下で説明します。
📖 Scriptフィールドは、状態の変化のロジックを記述するトランザクションの一部です。Flowでは、トランザクションロジックはCadenceで書かれます。以下は、トランザクションのスクリプトの例です。
transaction(greeting: String) {
execute {
log(greeting.concat(", World!"))
}
}
📖 Arguments: トランザクションは、Cadenceスクリプトに渡されるゼロ個以上の引数を受け入れることができます。トランザクションの引数は、Cadenceスクリプト内で宣言された数と順序と一致する必要があります。上記のサンプルスクリプトでは、単一のString
引数を受け入れています。
📖 Proposal keyは、シーケンス番号として機能し、リプレイ攻撃やその他の潜在的な攻撃を防止するために、提供されなければなりません。
各アカウントのキーは別個のトランザクションのシーケンス番号を管理しています。トランザクションにそのシーケンス番号を付与するキーは、提案キー(proposal key)と呼ばれます。
提案キーは3つのフィールドを含みます。
- Account address
- Key index
- Sequence number
トランザクションは、宣言されたシーケンス番号がそのキーの現在のチェーン上のシーケンス番号と一致する場合のみ有効です。トランザクションが実行された後、シーケンス番号は1つインクリメントされます。
📖 Payerは、トランザクションの料金を支払うアカウントです。トランザクションは、必ず1つのPayerを指定する必要があります。Payerは、ネットワーク料金とガス料金の支払いの責任を負うのみであり、トランザクションはPayerアカウントに保存されているリソースやコードにアクセスする権限はありません。
📖 Authorizersとは、トランザクションがリソースを読み取り、変更することを承認するアカウントです。トランザクションは、アクセスする必要のあるアカウントの数に応じて、authorizerをゼロまたは複数指定できます。
トランザクションの承認者の数は、Cadenceスクリプトのprepareステートメントで宣言された&Account
パラメータの数と一致する必要があります。
複数の承認者を含むトランザクションの例:
transaction {
prepare(authorizer1: &Account, authorizer2: &Account) { }
}
📖 Gas limitとは、トランザクションに必要な計算量の制限値であり、ガスリミットを超えると処理が中断されます。Cadenceでは、トランザクションごとの操作数を計測によって測定しています。詳細は、Cadenceのドキュメントを参照してください。
ガスリミットは、トランザクションスクリプトの複雑さによって異なります。専用のガス測定ツールが利用可能になるまでは、エミュレータを使用して複雑なトランザクションをテストし、安全なリミットを決定することをお勧めします。
📖 Reference block(参照ブロック) は、ネットワークによってトランザクションが有効とみなされる、expiration window(有効期限の期間)(ブロック単位)を指定します。 トランザクションがexpiry block(有効期限ブロック)を過ぎて送信された場合、そのトランザクションは拒否されます。 Flowは、トランザクション上のReference block(参照ブロック) フィールドを使用してトランザクションの有効期限を計算します。 トランザクションは、600
ブロックがReference block(参照ブロック)の上にコミットされると有効期限切れとなり、これは平均的なMainnetブロックレートでは約10分かかります。
Mutate
FCLの「mutate」は、トランザクションの構築、署名、送信(building, signing, and sending a transaction)を裏側で実行します。FCLを使用してブロックチェーンの状態を変更するには、以下を行います。
import * as fcl from "@onflow/fcl"
await fcl.mutate({
cadence: `
transaction(a: Int) {
prepare(acct: &Account) {
log(acct)
log(a)
}
}
`,
args: (arg, t) => [
arg(6, t.Int)
],
limit: 50
})
Flowはトランザクションの署名に関しては、高い柔軟性をサポートしており、複数の承認者(マルチシグ取引)を定義したり、提案者とは異なる支払者アカウントを持つことができます。以下では、高度な署名シナリオについて説明します。
Single party, single signature
- Proposer, payer and authorizer are the same account (
0x01
). - Only the envelope must be signed.
- Proposal key must have full signing weight.
Account | Key ID | Weight |
---|---|---|
0x01 |
1 | 1000 |
/* There are multiple ways to acheive this */
import * as fcl from "@onflow/fcl"
/* FCL provides currentUser as an authorization function */
await fcl.mutate({
cadence: `
transaction {
prepare(acct: &Account) {}
}
`,
proposer: currentUser,
payer: currentUser,
authorizations: [currentUser],
limit: 50,
})
/* Or, simplified */
mutate({
cadence: `
transaction {
prepare(acct: &Account) {}
}
`,
authz: currentUser, /* Optional. Will default to currentUser if not provided. */
limit: 50,
})
/* Or, create a custom authorization function */
const authzFn = async (txAccount) => {
return {
...txAccount,
addr: "0x01",
keyId: 0,
signingFunction: async(signable) => {
return {
addr: "0x01",
keyId: 0,
signature
}
}
}
}
mutate({
cadence: `
transaction {
prepare(acct: &Account) {}
}
`,
proposer: authzFn,
payer: authzFn,
authorizations: [authzFn],
limit: 50,
})
Single party, multiple signatures
- Proposer, payer and authorizer are the same account (
0x01
). - Only the envelope must be signed.
- Each key has weight 500, so two signatures are required.
Account | Key ID | Weight |
---|---|---|
0x01 |
1 | 500 |
0x01 |
2 | 500 |
import * as fcl from "@onflow/fcl"
const authzFn = async (txAccount) => {
return [
{
...txAccount,
addr: "0x01",
keyId: 0,
signingFunction: async(signable) => {
return {
addr: "0x01",
keyId: 0,
signature
}
}
},
{
...txAccount,
addr: "0x01",
keyId: 1,
signingFunction: async(signable) => {
return {
addr: "0x01",
keyId: 1,
signature
}
}
}
]
}
mutate({
cadence: `
transaction {
prepare(acct: &Account) {}
}
`,
proposer: authzFn,
payer: authzFn,
authorizations: [authzFn],
limit: 50,
})
Multiple parties
- Proposer and authorizer are the same account (
0x01
). - Payer is a separate account (
0x02
). - Account
0x01
signs the payload. - Account
0x02
signs the envelope.- Account
0x02
must sign last since it is the payer.
- Account
Account | Key ID | Weight |
---|---|---|
0x01 |
1 | 1000 |
0x02 |
3 | 1000 |
import * as fcl from "@onflow/fcl"
const authzFn = async (txAccount) => {
return {
...txAccount,
addr: "0x01",
keyId: 0,
signingFunction: async(signable) => {
return {
addr: "0x01",
keyId: 0,
signature
}
}
}
}
const authzTwoFn = async (txAccount) => {
return {
...txAccount,
addr: "0x02",
keyId: 0,
signingFunction: async(signable) => {
return {
addr: "0x02",
keyId: 0,
signature
}
}
}
}
mutate({
cadence: `
transaction {
prepare(acct: &Account) {}
}
`,
proposer: authzFn,
payer: authzTwoFn,
authorizations: [authzFn],
limit: 50,
})
Multiple parties, two authorizers
- Proposer and authorizer are the same account (
0x01
). - Payer is a separate account (
0x02
). - Account
0x01
signs the payload. - Account
0x02
signs the envelope.- Account
0x02
must sign last since it is the payer.
- Account
- Account
0x02
is also an authorizer to show how to include two&Account
objects into an transaction
Account | Key ID | Weight |
---|---|---|
0x01 |
1 | 1000 |
0x02 |
3 | 1000 |
import * as fcl from "@onflow/fcl"
const authzFn = async (txAccount) => {
return {
...txAccount,
addr: "0x01",
keyId: 0,
signingFunction: async(signable) => {
return {
addr: "0x01",
keyId: 0,
signature
}
}
}
}
const authzTwoFn = async (txAccount) => {
return {
...txAccount,
addr: "0x02",
keyId: 0,
signingFunction: async(signable) => {
return {
addr: "0x02",
keyId: 0,
signature
}
}
}
}
mutate({
cadence: `
transaction {
prepare(acct: &Account, acct2: &Account) {}
}
`,
proposer: authzFn,
payer: authzTwoFn,
authorizations: [authzFn, authzTwoFn],
limit: 50,
})
Multiple parties, multiple signatures
- Proposer and authorizer are the same account (
0x01
). - Payer is a separate account (
0x02
). - Account
0x01
signs the payload. - Account
0x02
signs the envelope.- Account
0x02
must sign last since it is the payer.
- Account
- Both accounts must sign twice (once with each of their keys).
Account | Key ID | Weight |
---|---|---|
0x01 |
1 | 500 |
0x01 |
2 | 500 |
0x02 |
3 | 500 |
0x02 |
4 | 500 |
import * as fcl from "@onflow/fcl"
const authzFn = async (txAccount) => {
return [
{
...txAccount,
addr: "0x01",
keyId: 0,
signingFunction: async(signable) => {
return {
addr: "0x01",
keyId: 0,
signature
}
}
},
{
...txAccount,
addr: "0x01",
keyId: 1,
signingFunction: async(signable) => {
return {
addr: "0x01",
keyId: 1,
signature
}
}
}
]
}
const authzTwoFn = async (txAccount) => {
return [
{
...txAccount,
addr: "0x02",
keyId: 0,
signingFunction: async(signable) => {
return {
addr: "0x02",
keyId: 0,
signature
}
}
},
{
...txAccount,
addr: "0x02",
keyId: 1,
signingFunction: async(signable) => {
return {
addr: "0x02",
keyId: 1,
signature
}
}
}
]
}
mutate({
cadence: `
transaction {
prepare(acct: &Account) {}
}
`,
proposer: authzFn,
payer: authzTwoFn,
authorizations: [authzFn],
limit: 50,
})
トランザクションが構築され、署名されると、Flowブロックチェーンに送信され、そこで実行されます。送信が成功した場合、トランザクションの結果を取得できます。
Last updated on Dec 11, 2024 by Chase Fleming
翻訳元
Flow BlockchainのCadence version1.0ドキュメント (FCL SDK Reference)
Flow BlockchainのCadence version1.0ドキュメント (FCL SDK Reference)