Flow Go SDK

[Previous << WalletConnect 2.0 Manual Configuration](https://qiita.com/flowcadence/items/da6327777ef6c7e811cb)
[Next >> Migration Guide v0.25.0](https://qiita.com/flowcadence/items/f53d55ad70523d27f114)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#reference-2020832ebee1810a325a

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/714873fb-db9f-66a9-139c-8d740415a09d.png)

* [View on GitHub](https://github.com/onflow/flow-go-sdk)
* [SDK Specifications](https://qiita.com/flowcadence/items/c1a1364b2dba4262bdc1)
* [Contribute](https://github.com/onflow/flow-go-sdk/blob/master/CONTRIBUTING.md)
* [Report a Bug](https://github.com/onflow/flow-go-sdk/issues)

<h1>Overview</h1>

このリファレンスでは、SDKで利用可能なすべてのメソッドを紹介し、それらのメソッドがどのように機能するかを詳細に説明しています。SDKはオープンソースであり、ライセンスに従ってご利用いただけます。

ライブラリクライアントの仕様は、[こちらでご覧いただけます](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client)。

<h1>Getting Started</h1>
<h3>Installing</h3>

Go Flow SDKをインストールする推奨の方法は、Goモジュールを使用することです。

Goのプロジェクトをすでに初期化している場合は、ターミナルで次のコマンドを実行することができます。
```
go get github.com/onflow/flow-go-sdk
```
通常、dependenciesを特定のバージョンに固定しておくことが推奨されています。最新のバージョンを確認するには、[SDK releases](https://github.com/onflow/flow-go-sdk/tags)ページを参照してください。

<h3>Importing the Library</h3>

ライブラリのインストールが済んだら、インポートできます。
```ruby
import "github.com/onflow/flow-go-sdk"
```
<h1>Connect</h1>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#New)

Go SDKライブラリは、アクセスノードとの通信にHTTPまたはgRPC APIを使用し、正しいアクセスノードAPI URLが設定されていなければなりません。ライブラリは、Flow AN APIに接続するためのデフォルト・ファクトリーを提供しており、クライアントインタフェースを使用すれば、HTTPとgRPCを簡単に切り替えることができます。（クライアントインタフェースも提供されています）

クライアントの作成に関するその他の例を、こちらで参照してください。
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/blob/master/examples/http_grpc_clients/main.go)

Basic Example：
```ruby
/* common client interface */
var flowClient client.Client

/* initialize an http emulator client */
flowClient, err := http.NewClient(http.EmulatorHost)

/* initialize a gPRC emulator client */
flowClient, err = grpc.NewClient(grpc.EmulatorHost)
```
HTTP クライアントまたは gRPC クライアントを直接初期化することで、ネットワークのオプションにアクセスすることもできます。しかし、共通のインターフェースが実装されていないため、これらを簡単に切り替えることはできないことには注意してください。これは、実装がそれらの高度なオプションを必要とする場合にのみお勧めします。高度な例：
```ruby
/* initialize http specific client */
httpClient, err := http.NewHTTPClient(http.EMULATOR_URL)

/* initialize grpc specific client */
grpcClient, err := grpc.NewGRPCClient(
    grpc.EMULATOR_URL,
    grpcOpts.WithTransportCredentials(insecure.NewCredentials()),
)
```
<h1>Querying the Flow Network</h1>

アクセスノードとの接続が確立されたら、Flowネットワークにqueryで問い合わせて、ブロック、アカウント、イベント、トランザクションに関するデータを取得することができます。以下では、これらのデータをそれぞれ取得する方法について説明していきます。

<h3>Get Blocks</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetBlockByHeight)

ネットワークにIDと高さによるブロックをqueryします、または最新のブロックの取得します。

📖 **ブロックID**は、ブロックペイロード全体のSHA3-256 hashです。このハッシュは、（`GetLatestBlock`からのレスポンスなど）ブロックレスポンスオブジェクトのIDとして保存されています。

📖 **ブロック高さ**は、チェーン上のブロックの高さを表します。最新のブロック高さは、有効なブロックが生成されるごとに1ずつ増加します。

**Examples**
この例では、最新のブロックの取得方法と、高さまたはIDによるその他のブロックの取得方法を説明しています。

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_blocks/main.go)

```ruby
func demo() {
    ctx := context.Background()
    flowClient := examples.NewFlowClient()

    /* get the latest sealed block */
    isSealed := true
    latestBlock, err := flowClient.GetLatestBlock(ctx, isSealed)
    printBlock(latestBlock, err)

    /* get the block by ID */
    blockID := latestBlock.ID.String()
    blockByID, err := flowClient.GetBlockByID(ctx, flow.HexToID(blockID))
    printBlock(blockByID, err)

    /* get block by height */
    blockByHeight, err := flowClient.GetBlockByHeight(ctx, 0)
    printBlock(blockByHeight, err)
}

func printBlock(block *flow.Block, err error) {
    examples.Handle(err)

    fmt.Printf("\nID: %s\n", block.ID)
    fmt.Printf("height: %d\n", block.Height)
    fmt.Printf("timestamp: %s\n\n", block.Timestamp)
}
```
出力結果:
```ruby
ID: 835dc83939141097aa4297aa6cf69fc600863e3b5f9241a0d7feac1868adfa4f
height: 10
timestamp: 2021-10-06 15:06:07.105382 +0000 UTC


ID: 835dc83939141097aa4297aa6cf69fc600863e3b5f9241a0d7feac1868adfa4f
height: 10
timestamp: 2021-10-06 15:06:07.105382 +0000 UTC


ID: 7bc42fe85d32ca513769a74f97f7e1a7bad6c9407f0d934c2aa645ef9cf613c7
height: 0
timestamp: 2018-12-19 22:32:30.000000042 +0000 UTC
```

<h3>Get Account</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetAccount)

任意のアカウントを、Flowネットワークの最新ブロックまたは指定したブロック高さから取得します。`GetAccount`メソッドは、実際には最新ブロックからアカウントを取得するメソッドの別名です。

📖 **Account address**は、アカウントを一意に識別するものです。`0x`という接頭辞に注意してください。デフォルトの表現ではこの接頭辞を使うべきですが、ユーザーが入力する接頭辞がない表現については慎重に安全に処理してください。

アカウントには以下のデータが含まれます。
* Address：アカウントのアドレス。
* Balance：アカウントの残高。
* Contracts：アカウントにデプロイされたコントラクトのリスト。
* Keys：アカウントに関連付けられたキーのリスト。

**Examples**
最新のブロックからと、特定のブロック高さからアカウントを取得する方法を例示します。

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_accounts/main.go)
```ruby
func demo() {
    ctx := context.Background()
    flowClient := examples.NewFlowClient()

    /* get account from the latest block */
    address := flow.HexToAddress("f8d6e0586b0a20c7")
    account, err := flowClient.GetAccount(ctx, address)
    printAccount(account, err)

    /* get account from the block by height 0 */
    account, err = flowClient.GetAccountAtBlockHeight(ctx, address, 0)
    printAccount(account, err)
}

func printAccount(account *flow.Account, err error) {
    examples.Handle(err)

    fmt.Printf("\nAddress: %s", account.Address.String())
    fmt.Printf("\nBalance: %d", account.Balance)
    fmt.Printf("\nContracts: %d", len(account.Contracts))
    fmt.Printf("\nKeys: %d\n", len(account.Keys))
}
```
出力結果:
```ruby
Address: f8d6e0586b0a20c7
Balance: 999999999999600000
Contracts: 2
Keys: 1

Address: f8d6e0586b0a20c7
Balance: 999999999999600000
Contracts: 2
Keys: 1
```
<h3>Get Transactions</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetTransaction)

トランザクション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 |

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_transactions/main.go)
```ruby
func demo(txID flow.Identifier) {
    ctx := context.Background()
    flowClient := examples.NewFlowClient()

    tx, err := flowClient.GetTransaction(ctx, txID)
    printTransaction(tx, err)

    txr, err := flowClient.GetTransactionResult(ctx, txID)
    printTransactionResult(txr, err)
}

func printTransaction(tx *flow.Transaction, err error) {
    examples.Handle(err)

    fmt.Printf("\nID: %s", tx.ID().String())
    fmt.Printf("\nPayer: %s", tx.Payer.String())
    fmt.Printf("\nProposer: %s", tx.ProposalKey.Address.String())
    fmt.Printf("\nAuthorizers: %s", tx.Authorizers)
}

func printTransactionResult(txr *flow.TransactionResult, err error) {
    examples.Handle(err)

    fmt.Printf("\nStatus: %s", txr.Status.String())
    fmt.Printf("\nError: %v", txr.Error)
}
```
Example output:
```ruby
ID: fb1272c57cdad79acf2fcf37576d82bf760e3008de66aa32a900c8cd16174e1c
Payer: f8d6e0586b0a20c7
Proposer: f8d6e0586b0a20c7
Authorizers: []
Status: SEALED
Error: <nil>
```

<h3>Get Events</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetEventsForBlockIDs)

指定されたブロックの高さの範囲内にある、またはブロックIDのリストから、指定された型のイベントを取得します。

📖 **Event type**は、標準フォーマットに従った文字列です。
```ruby
A.{contract address}.{contract name}.{event name}
```
[イベントに関する詳細をドキュメント](https://qiita.com/flowcadence/items/41308221443f207a7921)で確認してください。このスタンダードに対する例外はcore eventsであり、[このドキュメント](https://qiita.com/flowcadence/items/5e0aea26c0ce24fab7e9)で詳細をご確認ください。

📖 **Block height range**は、チェーン内の開始ブロックと終了ブロックの高さを表します。

**Examples**

ブロックの範囲内および複数のブロックIDでイベントを取得する方法を示します。

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/blob/master/examples/get_events/main.go)
```ruby
func demo(deployedContract *flow.Account, runScriptTx *flow.Transaction) {
    ctx := context.Background()
    flowClient := examples.NewFlowClient()

    /* Query for account creation events by type */
    result, err := flowClient.GetEventsForHeightRange(ctx, "flow.AccountCreated", 0, 30)
    printEvents(result, err)

    /* Query for our custom event by type */
    customType := fmt.Sprintf("AC.%s.EventDemo.EventDemo.Add", deployedContract.Address.Hex())
    result, err = flowClient.GetEventsForHeightRange(ctx, customType, 0, 10)
    printEvents(result, err)

    /* Get events directly from transaction result */
    txResult, err := flowClient.GetTransactionResult(ctx, runScriptTx.ID())
    examples.Handle(err)
    printEvent(txResult.Events)
}

func printEvents(result []client.BlockEvents, err error) {
    examples.Handle(err)

    for _, block := range result {
        printEvent(block.Events)
    }
}

func printEvent(events []flow.Event) {
    for _, event := range events {
        fmt.Printf("\n\nType: %s", event.Type)
        fmt.Printf("\nValues: %v", event.Value)
        fmt.Printf("\nTransaction ID: %s", event.TransactionID)
    }
}
```
Example output:
```ruby
Type: flow.AccountCreated
Values: flow.AccountCreated(address: 0xfd43f9148d4b725d)
Transaction ID: ba9d53c8dcb0f9c2f854f93da8467a22d053eab0c540bde0b9ca2f7ad95eb78e

Type: flow.AccountCreated
Values: flow.AccountCreated(address: 0xeb179c27144f783c)
Transaction ID: 8ab7bfef3de1cf8b2ffb36559446100bf4129a9aa88d6bc59f72a467acf0c801

...

Type: A.eb179c27144f783c.EventDemo.Add
Values: A.eb179c27144f783c.EventDemo.Add(x: 2, y: 3, sum: 5)
Transaction ID: f3a2e33687ad23b0e02644ebbdcd74a7cd8ea7214065410a8007811d0bcbd353
```
<h3>Get Collections</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.GetCollection)

同じブロックに含まれているトランザクションの塊を取得します。これを**collections**と呼びます。コレクションは、ブロックあたりのトランザクション数を増やすことで、コンセンサス処理のスループットを向上させるために使用され、それらはブロックとトランザクションの間のリンクとして働きます。

📖 **コレクションID**は、collectionペイロードのSHA3-256ハッシュです。

コレクションの取得例：
```ruby
func demo(exampleCollectionID flow.Identifier) {
    ctx := context.Background()
    flowClient := examples.NewFlowClient()

    /* get collection by ID */
    collection, err := flowClient.GetCollection(ctx, exampleCollectionID)
    printCollection(collection, err)
}

func printCollection(collection *flow.Collection, err error) {
    examples.Handle(err)

    fmt.Printf("\nID: %s", collection.ID().String())
    fmt.Printf("\nTransactions: %s", collection.TransactionIDs)
}
```
Example output:
```ruby
ID: 3d7b8037381f2497d83f2f9e09422c036aae2a59d01a7693fb6003b4d0bc3595
Transactions: [cf1184e3de4bd9a7232ca3d0b9dd2cfbf96c97888298b81a05c086451fa52ec1]
```
<h3>Execute Scripts</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.ExecuteScriptAtLatestBlock)
スクリプトを使用すると、Flowブロックチェーン上で変更が発生しない任意のCadenceコードを書いて、そのデータを受け取ることができます。[Cadenceとスクリプトについてはこちら](https://qiita.com/flowcadence/items/9b08c176d64eff402a4d)で詳しく説明されていますが、現時点で私達はスクリプトコードの実行とデータの取得のみに興味を持ちます。

Flowブロックチェーンの最新の状態に対してスクリプトを実行することもできますし、ブロックの高さまたはブロックIDで定義されたヒストリーの特定の時点でスクリプトを実行することもできます。

📖 **ブロックID**はブロックのペイロード全体の SHA3-256 ハッシュですが、ブロックのレスポンスのプロパティからその値を取得できます。

📖 **ブロック高さ**はチェーン内のブロックの高さを表します。
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/blob/master/examples/execute_script/main.go)
```ruby
func demo() {
    ctx := context.Background()
    flowClient := examples.NewFlowClient()

    script := []byte(`
        access(all) fun main(a: Int): Int {
            return a + 10
        }
    `)
    args := []cadence.Value{ cadence.NewInt(5) }
    value, err := flowClient.ExecuteScriptAtLatestBlock(ctx, script, args)

    examples.Handle(err)
    fmt.Printf("\nValue: %s", value.String())

    complexScript := []byte(`
        access(all) struct User {
            access(all) var balance: UFix64
            access(all) var address: Address
            access(all) var name: String

            init(name: String, address: Address, balance: UFix64) {
                self.name = name
                self.address = address
                self.balance = balance
            }
        }

        access(all) fun main(name: String): User {
            return User(
                name: name,
                address: 0x1,
                balance: 10.0
            )
        }
    `)
    args = []cadence.Value{ cadence.NewString("Dete") }
    value, err = flowClient.ExecuteScriptAtLatestBlock(ctx, complexScript, args)
    printComplexScript(value, err)
}

type User struct {
	balance uint64
	address flow.Address
	name string
}

func printComplexScript(value cadence.Value, err error) {
    examples.Handle(err)
    fmt.Printf("\nString value: %s", value.String())

    s := value.(cadence.Struct)
    u := User{
        balance: s.Fields[0].ToGoValue().(uint64),
        address: s.Fields[1].ToGoValue().([flow.AddressLength]byte),
        name:    s.Fields[2].ToGoValue().(string),
    }

    fmt.Printf("\nName: %s", u.name)
    fmt.Printf("\nAddress: %s", u.address.String())
    fmt.Printf("\nBalance: %d", u.balance)
}
```
Example output:
```ruby
Value: 15
String value: s.34a17571e1505cf6770e6ef16ca387e345e9d54d71909f23a7ec0d671cd2faf5.User(balance: 10.00000000, address: 0x1, name: "Dete")
Name: Dete
Address: 0000000000000001
Balance: 1000000000
```

<h1>Mutate Flow Network</h1>

Flowは、他の多くのブロックチェーンと同じ様に、共有されたグローバルチェーンの状態を変化させるトランザクションを誰でも送信することができます。トランザクションは、状態の変化を記述したペイロードと、特定アカウントによる所有状態の変化を許可した1つ以上の承認、を含むオブジェクトです。

トランザクションデータは、SDKの助けを借りて、作成/署名されます。署名されたトランザクションのペイロードは、その後、アクセスノードAPIに送信されます。トランザクションが無効であった場合、または正しい数の承認署名が用意されていなかった場合、トランザクションは拒否されます。

トランザクションを実行するには、いくつかの手順が必要です。
* [Building transaction](#build-the-transaction).
* [Signing transaction](#sign-transactions).
* [Sending transaction](#send-transactions).
<h1>Transactions</h1>

トランザクションとは署名済みのデータセットでしかなく、どのようにネットワークの状態を変化させるかと、その実行を定義したり制限したりするプロパティを指示したスクリプト・コードを含んでいます。これらのプロパティについては、以下で説明します。

📖 **Script**フィールドは、状態の変化のロジックを記述するトランザクションの一部です。Flowでは、トランザクションロジックは[Cadence](https://qiita.com/flowcadence/items/87147a26f1d2b89b46ca)で書かれます。以下は、トランザクションのスクリプトの例です。
```ruby
transaction(greeting: String) {
  execute {
    log(greeting.concat(", World!"))
  }
}
```
📖 **Arguments**: トランザクションは、Cadenceスクリプトに渡されるゼロ個以上の引数を受け入れることができます。トランザクションの引数は、Cadenceスクリプト内で宣言された数と順序と一致する必要があります。上記のサンプルスクリプトでは、単一の`String`引数を受け入れています。

📖 [**Proposal key**](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca#proposal-key)は、シーケンス番号として機能し、リプレイ攻撃やその他の潜在的な攻撃を防止するために、提供されなければなりません。

各アカウントのキーは別個のトランザクションのシーケンス番号を管理しています。トランザクションにそのシーケンス番号を付与するキーは、提案キー(proposal key)と呼ばれます。

提案キーは3つのフィールドを含みます。
* Account address
* Key index
* Sequence number

トランザクションは、宣言されたシーケンス番号がそのキーの現在のチェーン上のシーケンス番号と一致する場合のみ有効です。トランザクションが実行された後、シーケンス番号は1つインクリメントされます。

📖 [**Payer**](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca#signer-roles)は、トランザクションの料金を支払うアカウントです。トランザクションは、必ず1つのPayerを指定する必要があります。Payerは、ネットワーク料金とガス料金の支払いの責任を負うのみであり、トランザクションはPayerアカウントに保存されているリソースやコードにアクセスする権限はありません。

📖 [**Authorizers**](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca#signer-roles)とは、トランザクションがリソースを読み取り、変更することを承認するアカウントです。トランザクションは、アクセスする必要のあるアカウントの数に応じて、authorizerをゼロまたは複数指定できます。

トランザクションの承認者の数は、Cadenceスクリプトのprepareステートメントで宣言された&Accountパラメータの数と一致する必要があります。

複数の承認者を含むトランザクションの例：
```ruby
transaction {
  prepare(authorizer1: &Account, authorizer2: &Account) { }
}
```
**Gas Limit**

📖 **Gas limit**とは、トランザクションに必要な計算量の制限値であり、ガスリミットを超えると処理が中断されます。Cadenceでは、トランザクションごとの操作数を計測によって測定しています。詳細は、[Cadenceのドキュメント](https://qiita.com/flowcadence/items/87147a26f1d2b89b46ca)を参照してください。

ガスリミットは、トランザクションスクリプトの複雑さによって異なります。専用のガス測定ツールが利用可能になるまでは、エミュレータを使用して複雑なトランザクションをテストし、安全なリミットを決定することをお勧めします。

**Reference Block**

📖 **Reference block(参照ブロック)** は、ネットワークによってトランザクションが有効とみなされる、expiration window(有効期限の期間)（ブロック単位）を指定します。 トランザクションがexpiry block(有効期限ブロック)を過ぎて送信された場合、そのトランザクションは拒否されます。 Flowは、トランザクション上の*Reference block(参照ブロック)* フィールドを使用してトランザクションの有効期限を計算します。 トランザクションは、`600`ブロックがReference block(参照ブロック)の上にコミットされると有効期限切れとなり、これは平均的なMainnetブロックレートでは約10分かかります。

<h3>Build Transactions</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk#Transaction)

トランザクションの組み立てには、上述した必須プロパティの設定とトランザクション・オブジェクトの作成が含まれます。

ここで、ネットワーク上で実行される、学習用の良い例となるシンプルなトランザクション・スクリプトを定義します。
```ruby
transaction(greeting: String) {

  let guest: Address

  prepare(authorizer: &Account) {
    self.guest = authorizer.address
  }

  execute {
    log(greeting.concat(",").concat(self.guest.toString()))
  }
}
```
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/blob/master/examples/transaction_signing/single_party/main.go)
```ruby
import (
  "context"
  "os"
  "github.com/onflow/flow-go-sdk"
  "github.com/onflow/flow-go-sdk/client"
)

func main() {

  greeting, err := os.ReadFile("Greeting2.cdc")
  if err != nil {
    panic("failed to load Cadence script")
  }

  proposerAddress := flow.HexToAddress("9a0766d93b6608b7")
  proposerKeyIndex := 3

  payerAddress := flow.HexToAddress("631e88ae7f1d7c20")
  authorizerAddress := flow.HexToAddress("7aad92e5a0715d21")

  var accessAPIHost string

  /* Establish a connection with an access node */
  flowClient := examples.NewFlowClient()

  /* Get the latest sealed block to use as a reference block */
  latestBlock, err := flowClient.GetLatestBlockHeader(context.Background(), true)
  if err != nil {
    panic("failed to fetch latest block")
  }

  /* Get the latest account info for this address */
  proposerAccount, err := flowClient.GetAccountAtLatestBlock(context.Background(), proposerAddress)
  if err != nil {
    panic("failed to fetch proposer account")
  }

  /* Get the latest sequence number for this key */
  sequenceNumber := proposerAccount.Keys[proposerKeyIndex].SequenceNumber

  tx := flow.NewTransaction().
    SetScript(greeting).
    SetComputeLimit(100).
    SetReferenceBlockID(latestBlock.ID).
    SetProposalKey(proposerAddress, proposerKeyIndex, sequenceNumber).
    SetPayer(payerAddress).
    AddAuthorizer(authorizerAddress)

  /* Add arguments last */

  hello := cadence.NewString("Hello")

  err = tx.AddArgument(hello)
  if err != nil {
    panic("invalid argument")
  }
}
```
[トランザクションの作成](#build-the-transaction)に成功したら、次に署名を行います。

<h3>Sign Transactions</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk#Transaction.SignEnvelope)

Flowでは、トランザクションの作成や署名を行う際に、より柔軟性を高める新しい概念が導入されています。

[トランザクションの作成](#build-the-transaction)に成功したら、次に署名を行います。Flowトランザクションにはエンベロープ署名とペイロード署名があり、それぞれについて[署名に関するドキュメント](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca)で確認してください。

トランザクション構築の手短な例：
```ruby
import (
    "github.com/onflow/flow-go-sdk"
    "github.com/onflow/flow-go-sdk/crypto"
)

var (
    myAddress    flow.Address
    myAccountKey flow.AccountKey
    myPrivateKey crypto.PrivateKey
)

tx := flow.NewTransaction().
    SetScript([]byte("transaction { execute { log(\"Hello, World!\") } }")).
    SetComputeLimit(100).
    SetProposalKey(myAddress, myAccountKey.Index, myAccountKey.SequenceNumber).
    SetPayer(myAddress)
```
トランザクション署名の処理は、`crypto.Signer` インターフェイスを通じて行われます。最も簡単な（かつ最も安全性の低い）`crypto.Signer` の実装は、`crypto.InMemorySigner` です。

署名をより安全に生成するには、[HSM（ハードウェア・セキュリティ・モジュール）](https://en.wikipedia.org/wiki/Hardware_security_module)などのハードウェアデバイスに保存されたキーを使用することなどが考えられます。`crypto.Signer` のインターフェイスはさまざまな署名の実装をサポートする柔軟性を備えており、メモリ内(in-memory)での実装に限定されていません。

Simple signature example:
```ruby
/* construct a signer from your private key and configured hash algorithm */
mySigner, err := crypto.NewInMemorySigner(myPrivateKey, myAccountKey.HashAlgo)
if err != nil {
    panic("failed to create a signer")
}

err = tx.SignEnvelope(myAddress, myAccountKey.Index, mySigner)
if err != nil {
    panic("failed to sign transaction")
}
```
トランザクションの署名においては、Flowは高い柔軟性をサポートしており、複数の承認者（マルチシグ・トランザクション）を定義したり、提案者とは異なる支払者アカウントを持つことができます。以下では、高度な署名シナリオについて説明します。

### [Single party, single signature](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca#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 |

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/tree/master/examples#single-party-single-signature)

```ruby
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))

key1 := account1.Keys[0]

/* create signer from securely-stored private key */
key1Signer := getSignerForKey1()

referenceBlock, _ := flow.GetLatestBlock(ctx, true)
tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer: &Account) { log(signer.address) }
        }
    `)).
    SetComputeLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetReferenceBlockID(referenceBlock.ID).
    SetPayer(account1.Address).
    AddAuthorizer(account1.Address)

/* account 1 signs the envelope with key 1 */
err := tx.SignEnvelope(account1.Address, key1.Index, key1Signer)
```
### [Single party, multiple signatures](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca#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 |

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/tree/master/examples#single-party-multiple-signatures)

```ruby
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))

key1 := account1.Keys[0]
key2 := account1.Keys[1]

/* create signers from securely-stored private keys */
key1Signer := getSignerForKey1()
key2Signer := getSignerForKey2()

referenceBlock, _ := flow.GetLatestBlock(ctx, true)
tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer: &Account) { log(signer.address) }
        }
    `)).
    SetComputeLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetReferenceBlockID(referenceBlock.ID).
    SetPayer(account1.Address).
    AddAuthorizer(account1.Address)

/* account 1 signs the envelope with key 1 */
err := tx.SignEnvelope(account1.Address, key1.Index, key1Signer)

/* account 1 signs the envelope with key 2 */
err = tx.SignEnvelope(account1.Address, key2.Index, key2Signer)
```
### [Multiple parties](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca#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 | Key ID | Weight |
|:-:|:-:|:-:|
| `0x01` | 1 | 1000 |
| `0x02` | 3 | 1000 |


[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties)

```ruby
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))
account2, _ := c.GetAccount(ctx, flow.HexToAddress("02"))

key1 := account1.Keys[0]
key3 := account2.Keys[0]

/* create signers from securely-stored private keys */
key1Signer := getSignerForKey1()
key3Signer := getSignerForKey3()

referenceBlock, _ := flow.GetLatestBlock(ctx, true)
tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer: &Account) { log(signer.address) }
        }
    `)).
    SetComputeLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetReferenceBlockID(referenceBlock.ID).
    SetPayer(account2.Address).
    AddAuthorizer(account1.Address)

/* account 1 signs the payload with key 1 */
err := tx.SignPayload(account1.Address, key1.Index, key1Signer)

/* account 2 signs the envelope with key 3
   note: payer always signs last */
err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer)
```
### [Multiple parties, two authorizers](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca#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 `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 |

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties-two-authorizers)

```ruby
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))
account2, _ := c.GetAccount(ctx, flow.HexToAddress("02"))

key1 := account1.Keys[0]
key3 := account2.Keys[0]

/* create signers from securely-stored private keys */
key1Signer := getSignerForKey1()
key3Signer := getSignerForKey3()

referenceBlock, _ := flow.GetLatestBlock(ctx, true)
tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer1: &Account, signer2: &Account) {
              log(signer.address)
              log(signer2.address)
          }
        }
    `)).
    SetComputeLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetReferenceBlockID(referenceBlock.ID).
    SetPayer(account2.Address).
    AddAuthorizer(account1.Address).
    AddAuthorizer(account2.Address)

/* account 1 signs the payload with key 1 */
err := tx.SignPayload(account1.Address, key1.Index, key1Signer)

/* account 2 signs the envelope with key 3
   note: payer always signs last */
err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer)
```
### [Multiple parties, multiple signatures](https://qiita.com/flowcadence/items/6393a2af33f82475a7ca#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.
* 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 |


[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/tree/master/examples#multiple-parties-multiple-signatures)

```ruby
account1, _ := c.GetAccount(ctx, flow.HexToAddress("01"))
account2, _ := c.GetAccount(ctx, flow.HexToAddress("02"))

key1 := account1.Keys[0]
key2 := account1.Keys[1]
key3 := account2.Keys[0]
key4 := account2.Keys[1]

/* create signers from securely-stored private keys */
key1Signer := getSignerForKey1()
key2Signer := getSignerForKey1()
key3Signer := getSignerForKey3()
key4Signer := getSignerForKey4()

referenceBlock, _ := flow.GetLatestBlock(ctx, true)
tx := flow.NewTransaction().
    SetScript([]byte(`
        transaction {
            prepare(signer: &Account) { log(signer.address) }
        }
    `)).
    SetComputeLimit(100).
    SetProposalKey(account1.Address, key1.Index, key1.SequenceNumber).
    SetReferenceBlockID(referenceBlock.ID).
    SetPayer(account2.Address).
    AddAuthorizer(account1.Address)

/* account 1 signs the payload with key 1 */
err := tx.SignPayload(account1.Address, key1.Index, key1Signer)

/* account 1 signs the payload with key 2 */
err = tx.SignPayload(account1.Address, key2.Index, key2Signer)

/* account 2 signs the envelope with key 3
   note: payer always signs last */
err = tx.SignEnvelope(account2.Address, key3.Index, key3Signer)

/* account 2 signs the envelope with key 4
   note: payer always signs last */
err = tx.SignEnvelope(account2.Address, key4.Index, key4Signer)
```

<h3>Send Transactions</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/client#Client.SendTransaction)

トランザクションが[生成](#build-the-transaction)され[署名](#sign-transactions)されると、Flowブロックチェーンに送信され、そこで実行されます。送信が成功した場合、[トランザクションの結果を取得](#get-transactions)できます。

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/0cfb680a-9923-6da5-e316-596d08a2bcac.png)](https://github.com/onflow/flow-go-sdk/blob/master/examples/send_transactions/main.go)
```ruby
func demo(tx *flow.Transaction) {
    ctx := context.Background()
    flowClient := examples.NewFlowClient()

    err := flowClient.SendTransaction(ctx, *tx)
    if err != nil {
        fmt.Println("error sending transaction", err)
    }
}
```

<h3>Create Accounts</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://pkg.go.dev/github.com/onflow/flow-go-sdk/templates#CreateAccount)

Flowでは、アカウントの作成はトランザクション内で行われます。なぜなら、このネットワークでは公開鍵(public key)とアカウント(account)間で多対多の関係が許容されているためで、オフラインで公開鍵から新しいアカウントのアドレス(new account address)を導き出すことは不可能だからです。

Flow VMは、決定論的(deterministic)なアドレス生成アルゴリズムを使用してチェーン上のアカウントのアドレスを割り当てます。アドレス生成の詳細については、[アカウントとkeysのドキュメント](https://qiita.com/flowcadence/items/83d778f84f462cb43318)をご覧ください。

**Public Key**

Flowは、ECDSAキーペアを使用してユーザーアカウントへのアクセスをコントロールします。各キーペアは、SHA2-256またはSHA3-256ハッシュアルゴリズムと組み合わせても使用できます。

⚠️ 新しいアカウントを管理(control)するには、少なくとも1つの公開鍵を認証する必要があります。

Flowは、追加のメタデータなしに、ECDSA公開鍵を生の形式で表示します。各鍵は1バイトのスライスで、ビッグエンディアンバイト形式で、XとYの成分を連結したものを含みます。

Flowアカウントには、ゼロ（制御不可能）またはそれ以上の(アカウント鍵と呼ばれる)公開鍵を含めることができます。アカウントの詳細については、[ドキュメントを参照](https://qiita.com/flowcadence/items/83d778f84f462cb43318)してください。

アカウントキーには以下のデータが含まれます。
* 生の公開鍵（上記参照）
* 署名アルゴリズム
* ハッシュアルゴリズム
* 重み（0～1000の整数）

アカウントの作成はトランザクション内で行われるため、そのトランザクションをネットワークに送信するには誰かが費用を負担する必要しなければなりません。この人物をアカウント作成者と呼びます。まず最初に[トランザクションの送信](#send-transactions)の項を必ずお読みください。
```ruby
var (
  creatorAddress    flow.Address
  creatorAccountKey *flow.AccountKey
  creatorSigner     crypto.Signer
)

var accessAPIHost string

/* Establish a connection with an access node */
flowClient := examples.NewFlowClient()

/* Use the templates package to create a new account creation transaction */
tx := templates.CreateAccount([]*flow.AccountKey{accountKey}, nil, creatorAddress)

/* Set the transaction payer and proposal key */
tx.SetPayer(creatorAddress)
tx.SetProposalKey(
    creatorAddress,
    creatorAccountKey.Index,
    creatorAccountKey.SequenceNumber,
)

/* Get the latest sealed block to use as a reference block */
latestBlock, err := flowClient.GetLatestBlockHeader(context.Background(), true)
if err != nil {
    panic("failed to fetch latest block")
}

tx.SetReferenceBlockID(latestBlock.ID)

/* Sign and submit the transaction */
err = tx.SignEnvelope(creatorAddress, creatorAccountKey.Index, creatorSigner)
if err != nil {
    panic("failed to sign transaction envelope")
}

err = flowClient.SendTransaction(context.Background(), *tx)
if err != nil {
    panic("failed to send transaction to network")
}
```
アカウント作成トランザクションが送信された後、[トランザクションの結果を取得する](#get-transactions)ことで、新しいアカウントのアドレスを取得できます。

新しいアカウントのアドレスは、システムレベルの`flow.AccountCreated`イベントで発行されます。
```ruby
result, err := flowClient.GetTransactionResult(ctx, tx.ID())
if err != nil {
    panic("failed to get transaction result")
}

var newAddress flow.Address

if result.Status != flow.TransactionStatusSealed {
    panic("address not known until transaction is sealed")
}

for _, event := range result.Events {
    if event.Type == flow.EventAccountCreated {
        newAddress = flow.AccountCreatedEvent(event).Address()
        break
    }
}
```
<h3>Generate Keys</h3>

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3912821/f8144689-226d-f3a6-80a8-deebafb9e1fb.png)](https://qiita.com/flowcadence/items/83d778f84f462cb43318#signature-and-hash-algorithms)

Flowは、[ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)署名を使用してユーザーアカウントへのアクセスを制御します。各キーペアは、`SHA2-256`または`SHA3-256`ハッシュアルゴリズムと組み合わせて使用できます。

P-256（secp256r1）曲線のECDSA秘密鍵を生成する方法は次のとおりです。
```ruby
import "github.com/onflow/flow-go-sdk/crypto"

/* deterministic seed phrase
   note: this is only an example, please use a secure random generator for the key seed */
seed := []byte("elephant ears space cowboy octopus rodeo potato cannon pineapple")

privateKey, err := crypto.GeneratePrivateKey(crypto.ECDSA_P256, seed)

/* the private key can then be encoded as bytes (i.e. for storage) */
encPrivateKey := privateKey.Encode()
/* the private key has an accompanying public key */
publicKey := privateKey.PublicKey()
```
上記の例では、ECDSA キーペアに P-256 (secp256r1) 楕円曲線を使用しています。Flowは、ビットコインやイーサリアムで使用されているsecp256k1曲線もサポートしています。[サポートされているアルゴリズムについてはこちら](https://qiita.com/flowcadence/items/83d778f84f462cb43318#signature-and-hash-algorithms)をご覧ください。

<h1>Transfering Flow</h1>

これは、Flow Go SDK を使用して FLOW トークンの転送トランザクションを構築する方法の一例です。
<h3>Cadence Script</h3>

以下のCadenceスクリプトは、送信者から受信者にFLOWトークンを転送します。

*注：このトランザクションはFlow Mainnetのみと互換性があります。*
```ruby
/* This transaction is a template for a transaction that
 * could be used by anyone to send tokens to another account
 * that has been set up to receive tokens.
 *
 * The withdraw amount and the account from getAccount
 * would be the parameters to the transaction
 */

import "FungibleToken"
import "FlowToken"

transaction(amount: UFix64, to: Address) {

    /* The Vault resource that holds the tokens that are being transferred */
    let sentVault: @{FungibleToken.Vault}

    prepare(signer: auth(BorrowValue) &Account) {

        /* Get a reference to the signer's stored vault */
        let vaultRef = signer.storage.borrow<auth(FungibleToken.Withdraw) &FlowToken.Vault>(from: /storage/flowTokenVault)
			?? panic("Could not borrow reference to the owner's Vault!")

        /* Withdraw tokens from the signer's stored vault */
        self.sentVault <- vaultRef.withdraw(amount: amount)
    }

    execute {

        /* Get a reference to the recipient's Receiver */
        let receiverRef =  getAccount(to)
            .capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
			?? panic("Could not borrow receiver reference to the recipient's Vault")

        /* Deposit the withdrawn tokens in the recipient's receiver */
        receiverRef.deposit(from: <-self.sentVault)
    }
}
```

<h3>Build the Transaction</h3>

```ruby
import (
    "github.com/onflow/cadence"
    "github.com/onflow/flow-go-sdk"
)

/* Replace with script above */
const transferScript string = TOKEN_TRANSFER_CADENCE_SCRIPT

var (
    senderAddress    flow.Address
    senderAccountKey flow.AccountKey
    senderPrivateKey crypto.PrivateKey
)

func main() {
    tx := flow.NewTransaction().
        SetScript([]byte(transferScript)).
        SetComputeLimit(100).
        SetPayer(senderAddress).
        SetAuthorizer(senderAddress).
        SetProposalKey(senderAddress, senderAccountKey.Index, senderAccountKey.SequenceNumber)

    amount, err := cadence.NewUFix64("123.4")
    if err != nil {
        panic(err)
    }

    recipient := cadence.NewAddress(flow.HexToAddress("0xabc..."))

    err = tx.AddArgument(amount)
    if err != nil {
        panic(err)
    }

    err = tx.AddArgument(recipient)
    if err != nil {
        panic(err)
    }
}
```

*Last updated on **Dec 6, 2024** by **Alex Ni***

翻訳元

https://developers.flow.com/tools/clients/flow-go-sdk

***
<b>[Previous << WalletConnect 2.0 Manual Configuration](https://qiita.com/flowcadence/items/da6327777ef6c7e811cb)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (Flow Go SDK)

<b>[Next >> Migration Guide v0.25.0](https://qiita.com/flowcadence/items/f53d55ad70523d27f114)</b>