Symbol SDK JS v3 でTransferTransaction

SDK v3 のインストールがまだの場合はコチラ

https://qiita.com/Toshi_ma/private/d3f91aabc57d7752f339

- Symbol SDK JS v3 でAggregateTransaction

https://qiita.com/Toshi_ma/items/0bda70e3362ad1bb8021

SDKがインストールできたらTransferTransactionを送ってみます。
v2との違いなど簡単に解説できたらと思います。

# TransferTransaction

<b>※インストールの続きなのでそうじゃない場合はここは不要</b>
```
cd ../../../
touch transfer.js
```

<b>※ここから本題</b>
まずは全文貼り付けますが後でちょっと解説します。コピペだけでいいよって人用。

```transfer.js
import sdk from './sdk/javascript/src/index.js';
import fetch from 'node-fetch';

const netWork = new sdk.symbol.Network(
    'testnet',
	0x98,
	new Date(Date.UTC(2022, 9, 31, 21, 7, 47)),
	new sdk.Hash256('49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4')
)

const facade = new sdk.facade.SymbolFacade(netWork);
const alicePrivateKey = new sdk.PrivateKey('ALICE_PRIVATE_KEY');
const aliceKeyPair = new sdk.symbol.KeyPair(alicePrivateKey);
const aliceAddress = facade.network.publicKeyToAddress(aliceKeyPair.publicKey);
const alicePlainAddress = new sdk.symbol.Address(aliceAddress).toString();

const deadline = new sdk.symbol.NetworkTimestamp(facade.network.fromDatetime(Date.now())).addHours(2).timestamp;

const transaction = facade.transactionFactory.create({
    type: 'transfer_transaction_v1',
    signerPublicKey: aliceKeyPair.publicKey,
    recipientAddress: 'BOB_PLAIN_ADDRESS',
    mosaics: [
		{ 
            mosaicId: 0x72C0212E67A08BCEn,
            amount: 1_000000n 
        }
	],
    message: [0,...(new TextEncoder('utf-8')).encode('Hello, Symbol!!')],
    fee: 1_000000n,
    deadline,
});

const aliceSignature = facade.signTransaction(aliceKeyPair, transaction);
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, aliceSignature);

(async()=> {
    const res = await fetch("NODE_URL", {
        method: 'put',
        body: jsonPayload  ,
        headers: {'Content-Type': 'application/json'}
    })
    console.log(await res.json());
})();
```

## facade作成
```js
const netWork = new sdk.symbol.Network(
    'testnet',
	0x98,
	new Date(Date.UTC(2022, 9, 31, 21, 7, 47)),
	new sdk.Hash256('49D6E1CE276A85B70EAFE52349AACCA389302E7A9754BCF1221E79494FC665A4')
)

const facade = new sdk.facade.SymbolFacade(netWork);
```
今回はテストネットを使用しており先日のアップデートでテストネットが新しくなったのですが、epoc timeやgeneration hashなどがまだSDKにハードコーディングされていないため自作します。MainNetの場合はこれだけでいいです。
```js
const facade = new sdk.facade.SymbolFacade(sdk.symbol.Network.MAINNET);
```

## アカウント作成
```js
const alicePrivateKey = new sdk.PrivateKey('ALICE_PRIVATE_KEY');
const aliceKeyPair = new sdk.symbol.KeyPair(alicePrivateKey);
const aliceAddress = facade.network.publicKeyToAddress(aliceKeyPair.publicKey);
const alicePlainAddress = new sdk.symbol.Address(aliceAddress).toString();
```
作成したいトランザクションによりますがv2との違いの一つで、いわゆるv2でのAccountクラスはprivateKeyから作成します。AddressクラスやPlainAddress(Nから始まる３９桁文字列)は公開鍵から作成できますがこの辺はテンプレで覚えていると良いかも。秘密鍵が分からず公開鍵からアドレスなどを取得したい場合は以下です。
```js
const bobPublicKey = new sdk.PublicKey(sdk.utils.hexToUint8('hex_public_key'));
const bobAddress = facade.network.publicKeyToAddress(bobPublicKey);
const bobPlainAddress = new sdk.symbol.Address(bobAddress).toString();
console.log(bobPlainAddress);
```

## deadline
現在時刻から２時間後の場合
```js
const deadline = new sdk.symbol.NetworkTimestamp(facade.network.fromDatetime(Date.now())).addHours(2).timestamp;
```

## Transaction構築
```js
const transaction = facade.transactionFactory.create({
    type: 'transfer_transaction_v1',
    signerPublicKey: aliceKeyPair.publicKey,
    recipientAddress: 'BOB_PLAIN_ADDRESS',
    mosaics: [
		{ 
            mosaicId: 0x72C0212E67A08BCEn,
            amount: 1_000000n 
        }
	],
    message: [0,...(new TextEncoder('utf-8')).encode('Hello, Symbol!!')],
    fee: 1_000000n,
    deadline,
});
```

```js
type: 'transfer_transaction_v1',
```
Transactionのタイプです。他のトランザクションでの文字列を知りたい場合は、

https://github.com/symbol/symbol/blob/dd8d5ec5331786a68d0e9cf89a32cbbf0855a8ba/sdk/javascript/src/symbol/models.js#L16202

ここを覗くと良いかと。文字列からTranasctionTypeを返す箇所。

```js
signerPublicKey: aliceKeyPair.publicKey,
```
ここの公開鍵はhex stringでもOKです。SDK内でいい感じにパースしてくれます。
```js
signerPublicKey: '13B00FBB13C7644E13BD786F0EA4F97820022A2606759793A5D3525A03F92A2F',
```

同じくアドレスも
```js
recipientAddress: bobAddress,
or
recipientAddress: 'TAUYF774MZWLBEUI7S2LR6BA5CYLL53QSMDVV3Y',
```

```js
mosaics: [
		{ 
            mosaicId: 0x72C0212E67A08BCEn,
            amount: 1_000000n 
        }
	],
```
モザイクIDはBigIntなので頭に`0x`、お尻に`n`を付けてあげれば数値になります。amountも同じくBigIntですが`1_000000n`も`1000000n`も同じ。桁数が分かりやすいだけ。

```js
message: [0,...(new TextEncoder('utf-8')).encode('Hello, Symbol!!')],
```
メッセージはエクスプローラーの仕様に合わせてエンコードしてからPlainMessageの場合は頭の1byteに0を足してあげる。
シンプルに
```js
message: 'Hello, Symbol!!',
```
でも構わないがその場合、APIからHexで取得した際にデコードが必要
```js
(new TextDecoder('utf-8')).decode(sdk.utils.hexToUint8('48656C6C6F2C2053796D626F6C2121'));
```

## 手数料
手数料はサンプルなので `fee: 1_000000n`としましたが、本番では出来る限り低い手数料を望むと思うので、トランザクションのサイズに合わせて後ほど手数料をセットするというのも良いかと思います。

```js
transaction.fee = new sdk.symbol.Amount(BigInt(transaction.size * 100));
```
100 は手数料乗数でv2だと`.setMaxFee(100);`の100と同じ。

## 署名＆ペイロード作成
```js
const aliceSignature = facade.signTransaction(aliceKeyPair, transaction);
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, aliceSignature);
```
v2と感覚的に違うのは署名のトランザクションへのアタッチは自分でやる。`attachSignature()`はこの後Putする際のJsonを作成し返してくれる。

## アナウンス

```js
(async()=> {
    const res = await fetch("NODE_URL", {
        method: 'put',
        body: jsonPayload  ,
        headers: {'Content-Type': 'application/json'}
    })
    console.log(await res.json());
})();
```
SDKでやってくれるのは基本的にトランザクションのペイロード作成までで、ノードへのアナウンスはfetchでもaxiosでも自分の好きなものを使えば良いです。ここではfetchでやってます。

# さいごに
シンプルなTransferTransactionは以上です。

他のトランザクションの作成サンプルは以下にあるので一度見ておくと良いかと思います。ただし、α版なため、まれにそのとおりにしても動かない場合があります。そんな時はDiscordで突っ込むと良いかと思います。SDKに修正があったがサンプルに修正が無い場合があります。

https://github.com/symbol/symbol/tree/dev/sdk/javascript/examples/descriptors

最後までお読みいただきありがとうございました！