symbol-sdk@3.2.1で作るトランザクション

# はじめに

こんにちは。

symbol-sdkの3系、以前は3.0.7について書きました。
新たに、3.2.1がリリースされ、書き方が少し変わったので、ここに書き記しておきたいと思います。

https://www.npmjs.com/package/symbol-sdk/v/3.2.1

## 注意事項
書いてあるコードについて、正確性や完全性を保証するものではありません。あくまで参考程度として頂き、最新情報は公式ドキュメンテーションをご確認ください。

# 要点

## デッドライン

以前はこのような形でした。少し読むのが難しいですよね。

```javascript
import symbolSdk from 'symbol-sdk';

const network = symbolSdk.symbol.Network.TESTNET;
const deadline = network.fromDatetime(new Date(Date.now() + 7200000)).timestamp;
```

今回、新しくなって、すっきりしました。

```javascript
import { Network, SymbolFacade } from 'symbol-sdk/symbol'

const facade = new SymbolFacade(Network.TESTNET.name);
const deadline = facade.now().addHours(2).timestamp;
```

## transactionFactory と attachSignature

以前

```javascript
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature);
```

今回

```javascript
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
```

`constructor`が`static`になりました。理由はわかりません。

# 環境変数

この後、各トランザクションのプログラムコードが出てきますが、以下のファイルが同じ個所にあるものとしています。

主に秘密鍵などです。

```javascript:env.js
export const NODE_URL = "";
export const ADDRESS_RECEIVER_1 = "";
export const PUBLIC_KEY_RECEIVER_1 = "";
export const ADDRESS_RECEIVER_2 = "";
export const PUBLIC_KEY_RECEIVER_2 = "";
export const PRIVATE_KEY = "";
export const ALICE_PRIVATE_KEY = "";
export const BOB_PRIVATE_KEY = "";
export const CAROL_PRIVATE_KEY = "";
```

# package.json

の中身は、最低限以下のようになっています。

`type: module`が必要です。

```json:package.json
{
  "type": "module",
  "engines": {
    "node": ">=18"
  },
  "dependencies": {
    "symbol-sdk": "3.2.1"
  }
}
```

# 転送トランザクション

```javascript
import {
  PrivateKey,
  PublicKey,
  utils,
} from 'symbol-sdk';
import {
  Address,
  KeyPair,
  MessageEncoder,
  Network,
  SymbolFacade,
  generateMosaicAliasId
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ADDRESS_RECEIVER_1,
  PUBLIC_KEY_RECEIVER_1,
  PRIVATE_KEY,
} from './env.js';
import { TextEncoder } from 'util';

const currencyMosaicId = 0x72C0212E67A08BCEn;
const facade = new SymbolFacade(Network.TESTNET.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const textEncoder = new TextEncoder();
const messageEncoder = new MessageEncoder(keyPair);
const message = messageEncoder.encode(
  new PublicKey(PUBLIC_KEY_RECEIVER_1),
  textEncoder.encode('hoge')
)
const tryDecodeResult = messageEncoder.tryDecode(
    new PublicKey(PUBLIC_KEY_RECEIVER_1),
    message
)
console.log("tryDecodeResult", tryDecodeResult)


// const message = new Uint8Array([0x00, ...textEncoder.encode('あいうえお')]);

const xymNamespaceId = generateMosaicAliasId('symbol.xym');

const addressAliasId = generateMosaicAliasId('able.to');
const hexByteArray = addressAliasId.toString(16).toUpperCase().match(/../g)
hexByteArray.reverse();
const addressAliasIdLE = hexByteArray.join('');
const addressAlias = `99${addressAliasIdLE}`.padEnd(48, '0');
const namespaceAddress = new Address(utils.hexToUint8(addressAlias))

const transaction = facade.transactionFactory.create({
  type: 'transfer_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  recipientAddress: ADDRESS_RECEIVER_1,
  // recipientAddress: namespaceAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 1000000n },
    { mosaicId: xymNamespaceId, amount: 1000000n },
  ],
  message,
});

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
  )
    .then((res) => res.json());
console.log(sendRes);


await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

##  `messageEncoder.tryDecode`の戻り値が少し変更

になりました。

以前

```javascript
const [result, decodedMessage] = messageEncoder.tryDecode
```

今回

```javascript
const tryDecodeResult = messageEncoder.tryDecode
// { isDecoded: true, message: Uint8Array(4) [ 104, 111, 103, 101 ] }
```



# モザイクのトランザクション

## モザイク作成のトランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  generateMosaicId,
  models
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';

const network = Network.TESTNET
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);


const { MosaicFlags } = models;

// const mosaicFlags = MosaicFlags.NONE.value;
const mosaicFlags = MosaicFlags.SUPPLY_MUTABLE.value |
  MosaicFlags.TRANSFERABLE.value |
  MosaicFlags.RESTRICTABLE.value |
  MosaicFlags.REVOKABLE.value;


function getRandomInt(max) {
  return Math.floor(Math.random() * max);
}

// const mosaicNonceValue = 123;
const mosaicNonceValue = getRandomInt(0xffffffff);

console.log("nonce:", mosaicNonceValue.toString(16).toUpperCase())


const definitionTransaction = facade.transactionFactory.createEmbedded({
  type: 'mosaic_definition_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  duration: new models.BlockDuration(86400n),
  divisibility: 1,
  nonce: new models.MosaicNonce(mosaicNonceValue),
  flags: new models.MosaicFlags(mosaicFlags),
});


const ownerAddress = network.publicKeyToAddress(keyPair.publicKey);
const mosaicIdRaw = generateMosaicId(ownerAddress, mosaicNonceValue);
const mosaicId = new models.UnresolvedMosaicId(mosaicIdRaw);
console.log("mosaicId:", mosaicId.toString());

const supplyTransaction = facade.transactionFactory.createEmbedded({
  type: 'mosaic_supply_change_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  mosaicId,
  delta: new models.Amount(1000000000n),
  action: models.MosaicSupplyChangeAction.INCREASE,
});


const innerTransactions = [ definitionTransaction, supplyTransaction ];
const transactionsHash = SymbolFacade.hashEmbeddedTransactions(innerTransactions)

const transaction = facade.transactionFactory.create({
  type: 'aggregate_complete_transaction_v2',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash,
});


const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

いろんなクラスが`models`配下に移りましたが、そんなに大きな変更はないかと思います。

## モザイクリボークのトランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ADDRESS_RECEIVER_1,
  PRIVATE_KEY,
} from './env.js';

const facade = new SymbolFacade(Network.TESTNET.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const mosaicId = 0x7CA376ED426683B5n;


const transaction = facade.transactionFactory.create({
  type: 'mosaic_supply_revocation_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  sourceAddress: ADDRESS_RECEIVER_1,
  mosaic: { mosaicId, amount: 100n },
});

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);


await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

こちらは、そんなに大きな変更はないかと思います。

# ネームスペースのトランザクション

## ルートネームスペース

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';
import { TextEncoder } from 'util';


const facade = new SymbolFacade(Network.TESTNET.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);


// const namespaceName = 'name1';
const namespaceName = new TextEncoder().encode('name1');

const transaction = facade.transactionFactory.create({
  type: 'namespace_registration_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  duration: new models.BlockDuration(86400n),
  registrationType: models.NamespaceRegistrationType.ROOT,
  name: namespaceName,
});


const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);


await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

こちらは、そんなに大きな変更はないかと思います。

## チャイルドネームスペース

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  generateMosaicAliasId,
  generateNamespacePath,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';
import { TextEncoder } from 'util';

const facade = new SymbolFacade(Network.TESTNET.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);


// const namespaceName = 'child1';
const namespaceName = new TextEncoder().encode('child1');

const namespaceId = generateMosaicAliasId('name1');
// const namespaceId = new models.NamespaceId(0xFBE54EC2AAA8EFDFn);

const transaction = facade.transactionFactory.create({
  type: 'namespace_registration_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  registrationType: models.NamespaceRegistrationType.CHILD,
  parentId: namespaceId,
  name: namespaceName,
});


generateNamespacePath('name1.child1')
  .map((namespaceId) => {
    return new models.NamespaceId(namespaceId);
  })
  .forEach((namespaceId, index) => {
    console.log('NamespaceId:', `#${index}`, namespaceId.toString());
  });

// const namespaceIdRaw = generateMosaicAliasId('name1.child1');
// const namespaceId = new models.NamespaceId(namespaceIdRaw);
// console.log(namespaceId.toString());


const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);


const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

こちらは、そんなに大きな変更はないかと思います。

# 別名トランザクション

## アドレスの別名トランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  Address,
  KeyPair,
  Network,
  SymbolFacade,
  generateMosaicAliasId,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ADDRESS_RECEIVER_1,
  PRIVATE_KEY,
} from './env.js';

const facade = new SymbolFacade(Network.TESTNET.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const namespaceId = generateMosaicAliasId('name1.child1');
// const namespaceId = new models.NamespaceId(0xFBE54EC2AAA8EFDFn);

// const address = ADDRESS_RECEIVER_1;
const address = new Address(ADDRESS_RECEIVER_1);

const transaction = facade.transactionFactory.create({
  type: 'address_alias_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  namespaceId,
  address,
  aliasAction: models.AliasAction.LINK,
});


const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);


const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

こちらは、そんなに大きな変更はないかと思います。


## モザイクの別名トランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  Address,
  KeyPair,
  Network,
  SymbolFacade,
  generateMosaicAliasId,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';

const facade = new SymbolFacade(Network.TESTNET.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);


const namespaceId = generateMosaicAliasId('name1.child1');
// const namespaceId = new models.NamespaceId(0xFBE54EC2AAA8EFDFn);

// const mosaicId = 0x7CA376ED426683B5n;
const mosaicId = new models.MosaicId(0x7CA376ED426683B5n);


const transaction = facade.transactionFactory.create({
  type: 'mosaic_alias_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  namespaceId,
  mosaicId,
  aliasAction: models.AliasAction.LINK,
});


const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);


const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

こちらは、そんなに大きな変更はないかと思います。

# アグリゲートトランザクション

## 連署がいらないアグリゲートコンプリート

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ALICE_PRIVATE_KEY,
  BOB_PRIVATE_KEY,
  CAROL_PRIVATE_KEY,
} from './env.js';


const currencyMosaicId = 0x72C0212E67A08BCEn;

const network = Network.TESTNET
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const alicePrivateKey = new PrivateKey(ALICE_PRIVATE_KEY);
const aliceKeyPair = new KeyPair(alicePrivateKey);
const aliceAddress = network.publicKeyToAddress(aliceKeyPair.publicKey);

const bobPrivateKey = new PrivateKey(BOB_PRIVATE_KEY);
const bobKeyPair = new KeyPair(bobPrivateKey);
const bobAddress = network.publicKeyToAddress(bobKeyPair.publicKey);

const carolPrivateKey = new PrivateKey(CAROL_PRIVATE_KEY);
const carolKeyPair = new KeyPair(carolPrivateKey);
const carolAddress = network.publicKeyToAddress(carolKeyPair.publicKey);


const innerTransaction1 = facade.transactionFactory.createEmbedded({
  type: 'transfer_transaction_v1',
  signerPublicKey: aliceKeyPair.publicKey,
  recipientAddress: bobAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 1000000n },
  ],
});

const innerTransaction2 = facade.transactionFactory.createEmbedded({
  type: 'transfer_transaction_v1',
  signerPublicKey: aliceKeyPair.publicKey,
  recipientAddress: carolAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 2000000n },
  ],
});

const innerTransactions = [ innerTransaction1, innerTransaction2 ];
const transactionsHash = SymbolFacade.hashEmbeddedTransactions(innerTransactions)

const transaction = facade.transactionFactory.create({
  type: 'aggregate_complete_transaction_v2',
  signerPublicKey: aliceKeyPair.publicKey,
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash,
});

const signature = facade.signTransaction(aliceKeyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

こちらは、そんなに大きな変更はないかと思います。

## アグリゲートボンデッド

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ALICE_PRIVATE_KEY,
  BOB_PRIVATE_KEY,
  CAROL_PRIVATE_KEY,
} from './env.js';

const currencyMosaicId = 0x72C0212E67A08BCEn;
const network = Network.TESTNET
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const alicePrivateKey = new PrivateKey(ALICE_PRIVATE_KEY);
const aliceKeyPair = new KeyPair(alicePrivateKey);
const aliceAddress = network.publicKeyToAddress(aliceKeyPair.publicKey);

const bobPrivateKey = new PrivateKey(BOB_PRIVATE_KEY);
const bobKeyPair = new KeyPair(bobPrivateKey);
const bobAddress = network.publicKeyToAddress(bobKeyPair.publicKey);

const carolPrivateKey = new PrivateKey(CAROL_PRIVATE_KEY);
const carolKeyPair = new KeyPair(carolPrivateKey);
const carolAddress = network.publicKeyToAddress(carolKeyPair.publicKey);

const innerTransaction1 = facade.transactionFactory.createEmbedded({
  type: 'transfer_transaction_v1',
  signerPublicKey: aliceKeyPair.publicKey,
  recipientAddress: bobAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 1000000n },
  ],
});

const innerTransaction2 = facade.transactionFactory.createEmbedded({
  type: 'transfer_transaction_v1',
  signerPublicKey: bobKeyPair.publicKey,
  recipientAddress: carolAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 2000000n },
  ],
});

const innerTransactions = [ innerTransaction1, innerTransaction2 ];
const transactionsHash = SymbolFacade.hashEmbeddedTransactions(innerTransactions)

const aggregateTransaction = facade.transactionFactory.create({
  type: 'aggregate_bonded_transaction_v2',
  signerPublicKey: aliceKeyPair.publicKey,
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash,
});

const signatureAggregate = facade.signTransaction(aliceKeyPair, aggregateTransaction);
const jsonPayloadAggregate = facade.transactionFactory.static.attachSignature(aggregateTransaction, signatureAggregate);
const hashAggregate = facade.hashTransaction(aggregateTransaction);

const hashLockTransaction = facade.transactionFactory.create({
  type: 'hash_lock_transaction_v1',
  signerPublicKey: aliceKeyPair.publicKey,
  fee: 1000000n,
  deadline,
  mosaic: { mosaicId: currencyMosaicId, amount: 10000000n },
  duration: new models.BlockDuration(10n),
  hash: hashAggregate
});

const signatureHashLock = facade.signTransaction(aliceKeyPair, hashLockTransaction);
const jsonPayloadHashLock = facade.transactionFactory.static.attachSignature(hashLockTransaction, signatureHashLock);
const hashHashLock = facade.hashTransaction(hashLockTransaction);

const sendResHashLock = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayloadHashLock }
)
    .then((res) => res.json());
console.log(sendResHashLock);

for (let i = 0; i < 100; i++) {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  const hashLockStatus = await fetch(
      new URL("/transactionStatus/" + hashHashLock, NODE_URL)
  )
      .then((res) => res.json());
  if (hashLockStatus.group === "confirmed") {
    break;
  }
}


const sendResAggregate = await fetch(
    new URL('/transactions/partial', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayloadAggregate }
)
    .then((res) => res.json());
console.log(sendResAggregate);


await new Promise((resolve) => setTimeout(resolve, 1000));

await fetch(new URL("/transactionStatus/" + hashAggregate, NODE_URL))
  .then((res) => res.json())
  .then((statusRes) => {
    console.log(statusRes)
  })
  .catch((e) => {
    console.log(e.message, e.response.data)
  });


const bobCosignature = bobKeyPair.sign(hashAggregate.bytes);

const bobCosignatureReq = {
  parentHash: hashAggregate.toString(),
  signature: bobCosignature.toString(),
  signerPublicKey: bobKeyPair.publicKey.toString(),
  version: "0",
}

await fetch(
    new URL("/transactions/cosignature", NODE_URL),
{ method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(bobCosignatureReq) }
)
  .then((res) => res.json())
  .then((sendRes) => {
    console.log(sendRes);
  })
  .catch((e) => {
    console.log(e.message, e.response.data)
  });


await new Promise((resolve) => setTimeout(resolve, 1000));

await fetch(new URL("/transactionStatus/" + hashAggregate, NODE_URL))
  .then((res) => res.json())
  .then((statusRes) => {
    console.log(statusRes)
  })
  .catch((e) => {
    console.log(e.message, e.response.data)
  });
```

こちらは、そんなに大きな変更はないかと思います。

ハッシュロックトランザクションを送信していたりするので、長くなってます。

## あとから連署を追加するアグリゲートコンプリート

```javascript
import {
  PrivateKey,
  utils,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ALICE_PRIVATE_KEY,
  BOB_PRIVATE_KEY,
  CAROL_PRIVATE_KEY,
} from './env.js';

const currencyMosaicId = 0x72C0212E67A08BCEn;
const network = Network.TESTNET
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const alicePrivateKey = new PrivateKey(ALICE_PRIVATE_KEY);
const aliceKeyPair = new KeyPair(alicePrivateKey);
const aliceAddress = network.publicKeyToAddress(aliceKeyPair.publicKey);

const bobPrivateKey = new PrivateKey(BOB_PRIVATE_KEY);
const bobKeyPair = new KeyPair(bobPrivateKey);
const bobAddress = network.publicKeyToAddress(bobKeyPair.publicKey);

const carolPrivateKey = new PrivateKey(CAROL_PRIVATE_KEY);
const carolKeyPair = new KeyPair(carolPrivateKey);
const carolAddress = network.publicKeyToAddress(carolKeyPair.publicKey);


const innerTransaction1 = facade.transactionFactory.createEmbedded({
  type: 'transfer_transaction_v1',
  signerPublicKey: aliceKeyPair.publicKey,
  recipientAddress: bobAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 1000000n },
  ],
});

const innerTransaction2 = facade.transactionFactory.createEmbedded({
  type: 'transfer_transaction_v1',
  signerPublicKey: bobKeyPair.publicKey,
  recipientAddress: carolAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 2000000n },
  ],
});

const innerTransactions = [ innerTransaction1, innerTransaction2 ];
const transactionsHash = SymbolFacade.hashEmbeddedTransactions(innerTransactions)

const transaction = facade.transactionFactory.create({
  type: 'aggregate_complete_transaction_v2',
  signerPublicKey: aliceKeyPair.publicKey,
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash,
});

const signature = facade.signTransaction(aliceKeyPair, transaction);
const jsonPayloadWithoutCosig = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

const { payload: payloadWithoutCosig } = JSON.parse(jsonPayloadWithoutCosig);

const aggregateComplete = models.TransactionFactory.deserialize(utils.hexToUint8(payloadWithoutCosig));
const bobCosignature = facade.cosignTransaction(bobKeyPair, aggregateComplete);
aggregateComplete.cosignatures.push(bobCosignature);
const jsonPayload = `{"payload":"${utils.uint8ToHex(aggregateComplete.serialize())}"}`;

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

こちらは、そんなに大きな変更はないかと思います。

# マルチシグトランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
} from 'symbol-sdk/symbol'
import crypto from 'crypto';
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';

const currencyMosaicId = 0x72C0212E67A08BCEn;
const network = Network.TESTNET;
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const alicePrivateKey = PrivateKey.random();
const aliceKeyPair = new KeyPair(alicePrivateKey);
const aliceAddress = network.publicKeyToAddress(aliceKeyPair.publicKey);

const bobPrivateKey = PrivateKey.random();
const bobKeyPair = new KeyPair(bobPrivateKey);
const bobAddress = network.publicKeyToAddress(bobKeyPair.publicKey);

const carolPrivateKey = PrivateKey.random();
const carolKeyPair = new KeyPair(carolPrivateKey);
const carolAddress = network.publicKeyToAddress(carolKeyPair.publicKey);

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);
const fundTransaction = facade.transactionFactory.create({
  type: 'transfer_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  recipientAddress: aliceAddress,
  mosaics: [
    { mosaicId: currencyMosaicId, amount: 1000000n },
  ],
});
const fundSignature = facade.signTransaction(keyPair, fundTransaction);
const fundJsonPayload = facade.transactionFactory.static.attachSignature(fundTransaction, fundSignature);
const fundHash = facade.hashTransaction(fundTransaction).toString();
const fundSendRes = await fetch(
  new URL("/transactions", NODE_URL),
  {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: fundJsonPayload,
  }
)
    .then((res) => res.json());

for (let i = 0; i < 100; i++) {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  const hashLockStatus = await fetch(
      new URL("/transactionStatus/" + fundHash, NODE_URL)
  )
      .then((res) => res.json());
  if (hashLockStatus.group === "confirmed") {
    break;
  }
}

const innerTransaction1 = facade.transactionFactory.createEmbedded({
  type: 'multisig_account_modification_transaction_v1',
  signerPublicKey: aliceKeyPair.publicKey,
  minRemovalDelta: 2,
  minApprovalDelta: 2,
  addressAdditions: [ bobAddress, carolAddress ],
  addressDeletions: [],
});

const innerTransactions = [ innerTransaction1 ];
const transactionsHash = SymbolFacade.hashEmbeddedTransactions(innerTransactions)

const transaction = facade.transactionFactory.create({
  type: 'aggregate_complete_transaction_v2',
  signerPublicKey: aliceKeyPair.publicKey,
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash,
});

const signature = facade.signTransaction(aliceKeyPair, transaction);
facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

const bobCosignature = facade.cosignTransaction(bobKeyPair, transaction);
const carolCosignature = facade.cosignTransaction(carolKeyPair, transaction);

transaction.cosignatures.push(bobCosignature);
transaction.cosignatures.push(carolCosignature);

const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

# メタデータトランザクション

## アカウントのメタデータトランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  metadataUpdateValue,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';
import { TextEncoder } from 'util';

const network = Network.TESTNET;
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const textEncoder = new TextEncoder();

const accountMetadataTransaction = facade.transactionFactory.createEmbedded({
  type: 'account_metadata_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  targetAddress: network.publicKeyToAddress(keyPair.publicKey),
  scopedMetadataKey: 0x0000000012345678n,
  valueSizeDelta: 4,
  value: metadataUpdateValue(textEncoder.encode(""), textEncoder.encode("fuga")),
});

const innerTransactions = [ accountMetadataTransaction ];
const transactionsHash = SymbolFacade.hashEmbeddedTransactions(innerTransactions)

const transaction = facade.transactionFactory.create({
  type: 'aggregate_complete_transaction_v2',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash
});

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

## モザイクのメタデータトランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  metadataUpdateValue,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';
import { TextEncoder } from 'util';

const network = Network.TESTNET;
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const textEncoder = new TextEncoder();

const mosaicMetadataTransaction = facade.transactionFactory.createEmbedded({
  type: 'mosaic_metadata_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  targetAddress: network.publicKeyToAddress(keyPair.publicKey),
  scopedMetadataKey: 0x0000000012345678n,
  targetMosaicId: 0x7CA376ED426683B5n,
  valueSizeDelta: 4,
  value: metadataUpdateValue(textEncoder.encode(""), textEncoder.encode("fuga")),
});

const innerTransactions = [ mosaicMetadataTransaction ];
const transactionsHash = SymbolFacade.hashEmbeddedTransactions(innerTransactions)

const transaction = facade.transactionFactory.create({
  type: 'aggregate_complete_transaction_v2',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  transactions: innerTransactions,
  transactionsHash
});

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

# シークレットロック・プルーフトランザクション

```javascript
import {
  PrivateKey,
  utils,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ADDRESS_RECEIVER_1,
  PRIVATE_KEY,
} from './env.js';
import { sha3_256 } from '@noble/hashes/sha3';
import { ripemd160 } from '@noble/hashes/ripemd160';
import { sha256 } from '@noble/hashes/sha256';
import { TextEncoder } from 'util';

const network = Network.TESTNET;
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const textEncoder = new TextEncoder();

const proof = `secret${Date.now()}`;

const secret = sha3_256.create().update(textEncoder.encode(proof)).digest();

// const secret1 = sha256.create().update(textEncoder.encode(proof)).digest();
// const secret = sha256.create().update(secret1).digest();

// const secret2 = ripemd160.create().update(secret1).digest();
// const secret = symbolSdk.utils.uint8ToHex(secret2).padEnd(64, "0");

const hashAlgorithm = models.LockHashAlgorithm.SHA3_256;
// const hashAlgorithm = models.LockHashAlgorithm.HASH_160;
// const hashAlgorithm = models.LockHashAlgorithm.HASH_256;

const processSecretLock = async () => {
  const transaction = facade.transactionFactory.create({
    type: 'secret_lock_transaction_v1',
    signerPublicKey: keyPair.publicKey.toString(),
    fee: 1000000n,
    deadline,
    recipientAddress: ADDRESS_RECEIVER_1,
    secret: secret,
    // secret: new Uint8Array(secret),
    // secret: utils.uint8ToHex(secret),
    mosaic: { mosaicId: 0xE74B99BA41F4AFEEn, amount: 1000000n },
    // duration: 86400n,
    duration: new models.BlockDuration(86400n),
    hashAlgorithm,
  });

  const signature = facade.signTransaction(keyPair, transaction);
  const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
  const hash = facade.hashTransaction(transaction).toString();
  console.log(hash);

  const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
  )
    .then((res) => res.json());
  console.log(sendRes);


  while (true) {
    await new Promise((resolve) => setTimeout(resolve, 5000));

    const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
      .then((res) => res.json());
    console.log(statusRes);

    if (statusRes.group === 'confirmed') {
      break;
    }

    if (statusRes.group !== 'unconfirmed') {
      throw new Error();
    }
  }
}

await processSecretLock();

const processSecretProof = async () => {
  const transaction = facade.transactionFactory.create({
    type: 'secret_proof_transaction_v1',
    signerPublicKey: keyPair.publicKey.toString(),
    fee: 1000000n,
    deadline,
    recipientAddress: ADDRESS_RECEIVER_1,
    secret: secret,
    hashAlgorithm,
    proof: proof,
  });

  const signature = facade.signTransaction(keyPair, transaction);
  const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
  const hash = facade.hashTransaction(transaction).toString();
  console.log(hash);

  const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
  )
    .then((res) => res.json());
  console.log(sendRes);

  await new Promise((resolve) => setTimeout(resolve, 1000));

  const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
  console.log(statusRes);
}

await processSecretProof();
```

# アカウント制限トランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ADDRESS_RECEIVER_1,
  PRIVATE_KEY,
} from './env.js';

const network = Network.TESTNET;
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const { AccountRestrictionFlags, TransactionType } = models;

const allowIncomingAddress = AccountRestrictionFlags.ADDRESS.value;
const blockIncomingAddress = AccountRestrictionFlags.ADDRESS.value | AccountRestrictionFlags.BLOCK.value;
const allowOutgoingAddress = AccountRestrictionFlags.ADDRESS.value | AccountRestrictionFlags.OUTGOING.value;
const blockOutgoingAddress = AccountRestrictionFlags.ADDRESS.value | AccountRestrictionFlags.BLOCK.value | AccountRestrictionFlags.OUTGOING.value;
const transaction1 = facade.transactionFactory.create({
  type: 'account_address_restriction_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  restrictionFlags: new AccountRestrictionFlags(allowIncomingAddress),
  restrictionAdditions: [ ADDRESS_RECEIVER_1 ],
  restrictionDeletions: [],
});

const allowMosaic = AccountRestrictionFlags.MOSAIC_ID.value;
const blockMosaic = AccountRestrictionFlags.MOSAIC_ID.value | AccountRestrictionFlags.BLOCK.value;
const transaction2 = facade.transactionFactory.create({
  type: 'account_mosaic_restriction_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  restrictionFlags: new AccountRestrictionFlags(blockMosaic),
  restrictionAdditions: [ 0x2A3CB9A67A523DD4n ],
  restrictionDeletions: [],
});

const allowOutgoingTransactionType = AccountRestrictionFlags.TRANSACTION_TYPE.value | AccountRestrictionFlags.OUTGOING.value;
const blockOutgoingTransactionType = AccountRestrictionFlags.TRANSACTION_TYPE.value | AccountRestrictionFlags.OUTGOING.value | AccountRestrictionFlags.BLOCK.value;
const transaction3 = facade.transactionFactory.create({
  type: 'account_operation_restriction_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  restrictionFlags: new AccountRestrictionFlags(blockOutgoingTransactionType),
  restrictionAdditions: [ TransactionType.MOSAIC_DEFINITION ],
  restrictionDeletions: [],
});

const transaction = transaction3;

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

# モザイク制限トランザクション

## モザイクグローバル制限

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';

const network = Network.TESTNET;
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const mosaicId = 0x34563B8772964069n;
// const mosaicId = new models.MosaicId(0x34563B8772964069n);
const restrictionKey = 0x0000000012345678n;

const { MosaicRestrictionType } = models;

const previousRestrictionType = MosaicRestrictionType.NONE;
// const previousRestrictionType = MosaicRestrictionType.EQ;
// const previousRestrictionType = MosaicRestrictionType.LT;
// const previousRestrictionType = MosaicRestrictionType.LE;
// const previousRestrictionType = MosaicRestrictionType.GT;
// const previousRestrictionType = MosaicRestrictionType.GE;
// const previousRestrictionType = MosaicRestrictionType.NE;

const newRestrictionType = MosaicRestrictionType.EQ;

const transaction = facade.transactionFactory.create({
  type: 'mosaic_global_restriction_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  mosaicId,
  restrictionKey,
  previousRestrictionType,
  previousRestrictionValue: 0n,
  newRestrictionType,
  newRestrictionValue: 1n,
  // referenceMosaicId: 0x2A3CB9A67A523DD4n,
});

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

## モザイクアドレス制限

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  ADDRESS_RECEIVER_1,
  PRIVATE_KEY,
} from './env.js';

const network = Network.TESTNET;
const facade = new SymbolFacade(network.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

// https://github.com/symbol/symbol/blob/catbuffer/schemas/v3.1.0/catbuffer/schemas/symbol/restriction_mosaic/mosaic_address_restriction.cats#L11-L13

const mosaicId = 0x34563B8772964069n;
const restrictionKey = 0x0000000012345678n;

const transaction = facade.transactionFactory.create({
  type: 'mosaic_address_restriction_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  mosaicId,
  restrictionKey,
  // previousRestrictionValue: 0xFFFFFFFFFFFFFFFFn,
  previousRestrictionValue: 1n,
  newRestrictionValue: 2n,
  targetAddress: ADDRESS_RECEIVER_1,
});

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.static.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

# キーリンクトランザクション

```javascript
import {
  PrivateKey,
} from 'symbol-sdk';
import {
  KeyPair,
  Network,
  SymbolFacade,
  models,
} from 'symbol-sdk/symbol'
import {
  NODE_URL,
  PRIVATE_KEY,
} from './env.js';

const facade = new SymbolFacade(Network.TESTNET.name);
const deadline = facade.now().addHours(2).timestamp;

const privateKey = new PrivateKey(PRIVATE_KEY);
const keyPair = new KeyPair(privateKey);

const { LinkAction } = models;

const transaction1 = facade.transactionFactory.create({
  type: 'account_key_link_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  linkedPublicKey: "F185E55118CB715F130F34060EA9F8288D7F3E32D30A1E462502E57A8800CAFD",
  linkAction: LinkAction.UNLINK,
});

const transaction2 = facade.transactionFactory.create({
  type: 'node_key_link_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  linkedPublicKey: "F185E55118CB715F130F34060EA9F8288D7F3E32D30A1E462502E57A8800CAFD",
  linkAction: LinkAction.LINK,
});

const transaction3 = facade.transactionFactory.create({
  type: 'vrf_key_link_transaction_v1',
  signerPublicKey: keyPair.publicKey.toString(),
  fee: 1000000n,
  deadline,
  linkedPublicKey: "F185E55118CB715F130F34060EA9F8288D7F3E32D30A1E462502E57A8800CAFD",
  linkAction: LinkAction.LINK,
});

const transaction = transaction3;

const signature = facade.signTransaction(keyPair, transaction);
const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature);
const hash = facade.hashTransaction(transaction).toString();

console.log(jsonPayload);
console.log(hash);

const sendRes = await fetch(
    new URL('/transactions', NODE_URL),
    { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: jsonPayload }
)
    .then((res) => res.json());
console.log(sendRes);

await new Promise((resolve) => setTimeout(resolve, 1000));

const statusRes = await fetch(new URL("/transactionStatus/" + hash, NODE_URL))
    .then((res) => res.json());
console.log(statusRes);
```

# おわりに

ほとんどすべてのトランザクションについて網羅しました。

編集画面が重いです。

symbolのDiscordを見ると、まだまだ新しいバージョンで破壊的変更が起こりそうです。

各バージョンで、どのような書き方だったかを残しておくのが重要になってくるかもしれません。