LoginSignup
4
2

symbol-sdk@3.1.0でTypeScriptを試してみる

Last updated at Posted at 2023-10-30

はじめに

こんにちは。
symbol-sdkの3.1.0が公開されました。(執筆時点の最新版)

直前の3.0.11のリリースノートを見てみると、

TypeScript support via JSDoc documentation

という文字が見えますね。

↓リリースノートのリンク
https://github.com/symbol/symbol/releases/tag/sdk%2Fjavascript%2Fv3.0.11

ということで、TypeScriptに対応したみたいなので、少し試してみたいと思います。

まずは転送トランザクションを作ってみる

以前書いた記事を例に、転送トランザクションを作ってみようと思います。

セットアップ

まずは必要なパッケージをインストールします。

$ npm init -y
$ npm install typescript symbol-sdk@3.1.0 axios

tsconfig.jsonを作ります。

$ npx tsc --init

まずは動作確認がてら、簡単なコードを書いてみます。

test1.ts
import symbolSdk from 'symbol-sdk'

const network = symbolSdk.symbol.Network.TESTNET

console.log(network)

トランスパイルして実行します。

$ npx tsc
$ node test1.js

するとエラーになりました。

const symbol_sdk_1 = __importDefault(require("symbol-sdk"));
                                     ^
Error [ERR_REQUIRE_ESM]: require() of ES Module <略>node_modules\symbol-sdk\src\index.js  from <略>test1.js not supported.
Instead change the require of index.js in <略> to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (<略>) {
  code: 'ERR_REQUIRE_ESM'
}

CommonJSであるtest1.jsから、ESModuleのsymbol-sdkは参照できない、と言われました。

ですので、設定をESModuleにしていきます。package.jsonに以下の項目を追加します。

package.json
{
    "type": "module`
}

では、もう一度トランスパイルして実行してみます。

$ npx tsc
$ node test1.js

するとまたエラーになりました。

Object.defineProperty(exports, "__esModule", { value: true });
                      ^

ReferenceError: exports is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '<略>\package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.

ESModuleでexportsは使えませんよ、と言われました。調べた感じでは、トランスパイルがCommonJSで出力しているのが問題なようです。

tsconfig.jsonを以下のように修正します。

tsconfig.json
{
    "compilerOptions": {
        "module": "NodeNext"
    }
}

それではもう一度。

$ npx tsc
$ node test1.js
Network {
  name: 'testnet',
  identifier: 152,
  datetimeConverter: NetworkTimestampDatetimeConverter {
    epoch: 2022-10-31T21:07:47.000Z,
    timeUnits: 1
  },
<以下略>

これは実行することができました。

次に以下のコードを試してみます。

test2.ts
const fee = 1000000n

これをトランスパイルしてみます。

$ npx tsc

エラーになりました。

<略> - error TS2737: BigInt literals are not available when targeting lower than ES2020.

1 const fee = 1000000n
              ~~~~~~~~

というわけでtsconfig.jsonを以下のようにしました。

tsconfig.json
{
    "compilerOptions": {
        "target": "es2020"
    }
}

これで動くようになりました。

転送トランザクション

まずはデッドラインと鍵ペアです。

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

const facade = new symbolSdk.facade.SymbolFacade(network.name)

const privateKey = new symbolSdk.PrivateKey(PRIVATE_KEY)
// const keyPair = new facade.constructor.KeyPair(privateKey)
const keyPair = new symbolSdk.symbol.KeyPair(privateKey)

コメントアウトの行に示すように、new facade.constructor.KeyPair は使えませんでした(エディターでエラー表示になりました)。代わりに、new symbolSdk.symbol.KeyPairを使います(探しました)。

次にトランザクションです。

const currencyMosaicId = 0x72C0212E67A08BCEn

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

ここは特に問題なく、javascriptと同じように書けました。ただ、TypeScriptになったものの、transactionFactory.createの引数はobject型になっており、ここでは型定義の恩恵が受けられません。

そして署名です。


const signature = facade.signTransaction(keyPair, transaction)
// const jsonPayload = facade.transactionFactory.constructor.attachSignature(transaction, signature)
const jsonPayload = symbolSdk.symbol.SymbolTransactionFactory.attachSignature(transaction, signature)
const hash = facade.hashTransaction(transaction).toString()

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

コメントアウトの行が示すように、facade.transactionFactory.constructor.attachSignatureが使用できなかったので、symbolSdk.symbol.SymbolTransactionFactory.attachSignatureを使用しています。

最後に送信です。

// const sendRes = await axios.put(`${NODE_URL}/transactions`, jsonPayload).then((res) => res.data)
const sendRes = await axios.put(`${NODE_URL}/transactions`, JSON.parse(jsonPayload)).then((res) => res.data)
console.log(sendRes)

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

await axios
    .get(`${NODE_URL}/transactionStatus/${hash}`).then((res) => res.data)
    .then((statusRes) => {
        console.log(statusRes)
    })
    .catch((e) => {
        console.log(e.message, e.response.data)
    });

コメントアウトの行が示すように、jsonPayloadに対して、JSON.parseするようにしています。jsonPayloadstring型なのですが、axiosの仕様なのか、axios.putの第二引数に文字列型を渡すと、リクエストのContent-Typeapplication/x-www-form-urlencodedで飛んで行ってしまいました。

ですので、オブジェクトを渡すようにして、application/jsonでリクエストが飛ぶようにしています。

まとめ

やってきたことをまとめます。

package.jsonに以下を追加する。

package.json
{
    "type": "module`
}

tsconfig.jsonを以下のように設定する。

tsconfig.json
{
    "compilerOptions": {
        "target": "es2020",
        "module": "NodeNext"
    }
}

JavaScriptのコードはそのままでは動かないため、適宜修正を行う。

となります。

symbol-sdk@3.1.0が、晴れてTypeScriptに対応しましたので、reactやvueでも使ってみようと思いました。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2