前準備
変更しない値を一括で記述しておきます。アカウントはコードで作成したものでもウォレットで作成した物、どちらでもかまいません。
import sdk from 'symbol-sdk';
export class SymConst {
/** RestGatewayURL */
static readonly REST_GATEWAY_URL = 'https://sym-test-01.opening-line.jp:3001';
/** ネットワーク識別 */
static readonly NETWORK_IDENTIFIER = sdk.symbol.Network.TESTNET.name;
/** カレントモザイクID */
static readonly CURRENCY_MOSAIC_ID = BigInt('0x72C0212E67A08BCE');
/** アリス秘密鍵 */
static readonly ALICE_PRIVATE_KEY =
'F10B0***********************************************************';
/** ボブ秘密鍵 */
static readonly BOB_PRIVATE_KEY =
'6EBF9***********************************************************';
/** ボブ公開鍵 */
static readonly BOB_PUBLIC_KEY =
'94EC711522B4B32A1B6A6ED61D86D1E3EE11AFB9B912A17F8983EED3808819FD';
/** キャロル公開鍵 */
static readonly CAROL_PUBLIC_KEY =
'249B8ADE64EFF216D43BB655EF41DC1D7B8DDF96BD655749FFAF78BE3ACE7D77';
}
トランザクション
簡単なトランスファートランザクションの発行です。
アカウント生成
アリスからボブへの転送を考えているので、アリスは秘密鍵からアカウント生成します。ボブは公開鍵からのアドレスを生成します。
// faced生成
const facade = new sdk.facade.SymbolFacade(SymConst.NETWORK_IDENTIFIER);
// 送信者:アリス
// 秘密鍵からアリスのキーペア生成
const aliceKeyPair = new sdk.symbol.KeyPair(
new sdk.PrivateKey(SymConst.ALICE_PRIVATE_KEY)
);
// 受信者:ボブ
// 文字列公開鍵からPublicKey生成
const bobPublicKey = new sdk.symbol.PublicKey(
Uint8Array.from(Buffer.from(SymConst.BOB_PUBLIC_KEY, 'hex'))
);
// ボブのアドレスを取得
const bobAddress = new sdk.symbol.Address(
facade.network.publicKeyToAddress(bobPublicKey)
);
トランザクションの生成
デッドラインは、承認され無かった場合の待ち時間で、未承認のまま期限が過ぎると取り消されます。最大6時間となっています。
転送モザイクは、配列になっていて複数モザイクを同時に転送できます。一度に転送できる上限があるのかは分かりませんが、1アカウントにつき1,000モザイクまでしか持てないので、1,000が上限になってくるかと思います。
メッセージは、平文(メッセージタイプ:0x00
)で転送します。メッセージタイプの1バイトを含む1024バイトまで格納できます。
// デッドライン設定
// 現在日時をSymbolTimeに変換
const networkTimestamp = new sdk.symbol.NetworkTimestamp(
facade.network.fromDatetime(new Date())
);
const deadlineTimestamp = networkTimestamp.addHours(2).timestamp;
// 転送モザイク設定
const sendMosaics = [
{ mosaicId: SymConst.CURRENCY_MOSAIC_ID, amount: 1_000000n },
];
// 平文メッセージ
const messageData = new Uint8Array([
0x00,
...new TextEncoder().encode('Hello, Symbol!!'),
]);
上記の値をセットして転送トランザクションを生成します。最後にトランザクション発行の手数料を設定しています。トランザクションサイズに100を掛ければ、大抵のノードが承認します。細かい手数料は/network/fees/transaction
を参照してください。
// 転送トランザクション生成
const transferTx = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: aliceKeyPair.publicKey,
recipientAddress: bobAddress,
deadline: deadlineTimestamp,
mosaics: sendMosaics,
message: messageData,
});
transferTx.fee = new sdk.symbol.Amount(BigInt(transferTx.size * 100)); // 手数料
署名
アリスのキーペアで署名を生成して、トランザクションと合わせます。トランザクションハッシュもこのタイミングで取得出来ます。今回、特に用途はないです。
// アリス署名
const transferTxSignature = facade.signTransaction(aliceKeyPair, transferTx);
const transferTxPayloadJson =
sdk.symbol.SymbolTransactionFactory.attachSignature(
transferTx,
transferTxSignature
);
const transferTxHash = facade.hashTransaction(transferTx);
アナウンス
RESTにアナウンスします。一応レスポンスはありますが、「ノードに送信できたよ!」っていうレスポンスなので、ノード側でリジェクトされている可能性もあります。別途確認のコードを追加した方が良いです(今回は省略します)。アナウンス先のノードを接続先にしたウォレットを立ち上げておくと、エラーの場合、通知が出るのでテストする際は便利です。
// RESTにアナウンス
const transactionsResponse = await fetch(
new URL('/transactions', SymConst.REST_GATEWAY_URL),
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: transferTxPayloadJson,
}
);
// アナウンス結果を表示
const transactionsResponseJson = await transactionsResponse.json();
console.log(`restResponse : ${transactionsResponseJson.message}`);
コード例
import sdk from 'symbol-sdk';
import { SymConst } from '../SymConst.js';
try {
// faced生成
const facade = new sdk.facade.SymbolFacade(SymConst.NETWORK_IDENTIFIER);
// 送信者:アリス
// 秘密鍵からアリスのキーペア生成
const aliceKeyPair = new sdk.symbol.KeyPair(
new sdk.PrivateKey(SymConst.ALICE_PRIVATE_KEY)
);
// 受信者:ボブ
// 文字列公開鍵からPublicKey生成
const bobPublicKey = new sdk.symbol.PublicKey(
Uint8Array.from(Buffer.from(SymConst.BOB_PUBLIC_KEY, 'hex'))
);
// ボブのアドレスを取得
const bobAddress = new sdk.symbol.Address(
facade.network.publicKeyToAddress(bobPublicKey)
);
// デッドライン設定
// 現在日時をSymbolTimeに変換
const networkTimestamp = new sdk.symbol.NetworkTimestamp(
facade.network.fromDatetime(new Date())
);
const deadlineTimestamp = networkTimestamp.addHours(2).timestamp;
// 転送モザイク設定
const sendMosaics = [
{ mosaicId: SymConst.CURRENCY_MOSAIC_ID, amount: 1_000000n },
];
// 平文メッセージ
const messageData = new Uint8Array([
0x00,
...new TextEncoder().encode('Hello, Symbol!!'),
]);
// 転送トランザクション生成
const transferTx = facade.transactionFactory.create({
type: 'transfer_transaction_v1',
signerPublicKey: aliceKeyPair.publicKey,
recipientAddress: bobAddress,
deadline: deadlineTimestamp,
mosaics: sendMosaics,
message: messageData,
});
transferTx.fee = new sdk.symbol.Amount(BigInt(transferTx.size * 100)); // 手数料
// 未署名トランザクションを表示
console.log(
`unsignedTx : ${Buffer.from(transferTx.serialize())
.toString('hex')
.toUpperCase()}`
);
// アリス署名
const transferTxSignature = facade.signTransaction(aliceKeyPair, transferTx);
const transferTxPayloadJson =
sdk.symbol.SymbolTransactionFactory.attachSignature(
transferTx,
transferTxSignature
);
const transferTxHash = facade.hashTransaction(transferTx);
// 署名トランザクションを表示
console.log(
`signedTx : ${Buffer.from(transferTx.serialize())
.toString('hex')
.toUpperCase()}`
);
// トランザクションハッシュを表示
console.log(`txHash : ${transferTxHash}`);
// RESTにアナウンス
const transactionsResponse = await fetch(
new URL('/transactions', SymConst.REST_GATEWAY_URL),
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: transferTxPayloadJson,
}
);
// アナウンス結果を表示
const transactionsResponseJson = await transactionsResponse.json();
console.log(`restResponse : ${transactionsResponseJson.message}`);
} catch (e) {
console.error(e);
}
メッセージを暗号化
メッセージを暗号化することも出来ます。暗号化用のクラスが用意されていて、アリスの秘密鍵とボブの公開鍵で暗号化。自動的にメッセージタイプ0x01
が付与されます。ただ、v2の二重16進数化バグがあるので、バグが修正されたv3で暗号化した文章は現在のウォレットで復号できません。
const message = "Hello Symbol!!";
const aliceMsgEncoder = new symbolSdk.symbol.MessageEncoder(aliceKeyPair);
const messageData = aliceMsgEncoder.encode(
bobPublicKey,
new TextEncoder().encode(message)
);
メッセージにバイナリデータを格納
決まりはないのですが、メッセージタイプ:0xFF
をバイナリデータとして扱います。メッセージタイプは特に決まりが無く、各アプリでどう扱うかに任せられます。
const messageData = new Uint8Array([
0xff,
...new TextEncoder().encode("Hello, Symbol!!"),
]);
以下は、Zero埋めした1023バイトをメッセージに入れたトランザクションです。