6.ネームスペース
Symbol ブロックチェーンではネームスペースをレンタルしてアドレスやモザイクに視認性の高い単語をリンクさせることができます。 ネームスペースは最大 64 文字、利用可能な文字は a, b, c, …, z, 0, 1, 2, …, 9, _ , - です。
6.1 手数料の計算
ネームスペースのレンタルにはネットワーク手数料とは別にレンタル手数料が発生します。 ネットワークの活性度に比例して価格が変動しますので、取得前に確認するようにしてください。
ルートネームスペースを 365 日レンタルする場合の手数料を計算します。
nwRepo = repo.createNetworkRepository();
rentalFees = await nwRepo.getRentalFees().toPromise();
rootNsperBlock = rentalFees.effectiveRootNamespaceRentalFeePerBlock.compact();
rentalDays = 365;
rentalBlock = (rentalDays * 24 * 60 * 60) / 30;
rootNsRenatalFeeTotal = rentalBlock * rootNsperBlock;
console.log("rentalBlock:" + rentalBlock);
console.log("rootNsRenatalFeeTotal:" + rootNsRenatalFeeTotal);
出力例
> rentalBlock:1051200
> rootNsRenatalFeeTotal:210240000 //約210XYM
期間はブロック数で指定します。1 ブロックを 30 秒として計算しました。 最低で 30 日分はレンタルする必要があります(最大で 1825 日分)。
サブネームスペースの取得手数料を計算します。
childNamespaceRentalFee = rentalFees.effectiveChildNamespaceRentalFee.compact();
console.log(childNamespaceRentalFee);
出力例
> 10000000 //10XYM
サブネームスペースに期間指定はありません。ルートネームスペースをレンタルしている限り使用できます。
6.2 レンタル
ルートネームスペースをレンタルします(例:xembook)
tx = sym.NamespaceRegistrationTransaction.createRootNamespace(
sym.Deadline.create(epochAdjustment),
"xembook",
sym.UInt64.fromUint(86400),
networkType
).setMaxFee(100);
signedTx = alice.sign(tx, generationHash);
await txRepo.announce(signedTx).toPromise();
サブネームスペースをレンタルします(例:xembook.tomato)
subNamespaceTx = sym.NamespaceRegistrationTransaction.createSubNamespace(
sym.Deadline.create(epochAdjustment),
"tomato", //作成するサブネームスペース
"xembook", //紐づけたいルートネームスペース
networkType
).setMaxFee(100);
signedTx = alice.sign(subNamespaceTx, generationHash);
await txRepo.announce(signedTx).toPromise();
2 階層目のサブネームスペースを作成したい場合は 例えば、xembook.tomato.morning を定義したい場合は以下のようにします。
subNamespaceTx = sym.NamespaceRegistrationTransaction.createSubNamespace(
,
"morning", //作成するサブネームスペース
"xembook.tomato", //紐づけたいルートネームスペース
,
)
有効期限の計算
レンタル済みルートネームスペースの有効期限を計算します。
nsRepo = repo.createNamespaceRepository();
chainRepo = repo.createChainRepository();
blockRepo = repo.createBlockRepository();
namespaceId = new sym.NamespaceId("xembook");
nsInfo = await nsRepo.getNamespace(namespaceId).toPromise();
lastHeight = (await chainRepo.getChainInfo().toPromise()).height;
lastBlock = await blockRepo.getBlockByHeight(lastHeight).toPromise();
remainHeight = nsInfo.endHeight.compact() - lastHeight.compact();
endDate = new Date(
lastBlock.timestamp.compact() + remainHeight * 30000 + epochAdjustment * 1000
);
console.log(endDate);
ネームスペース情報の終了ブロックを取得し、現在のブロック高から差し引いた残ブロック数に 30 秒(平均ブロック生成間隔)を掛け合わせた日時を出力します。 テストネットでは設定した有効期限よりも 1 日程度更新期限が猶予されます。メインネットはこの値が 30 日となっていますのでご留意ください
出力例
> Tue Mar 29 2022 18:17:06 GMT+0900 (日本標準時)
6.3 リンク
アカウントへのリンク
namespaceId = new sym.NamespaceId("xembook");
address = sym.Address.createFromRawAddress(
"TBIL6D6RURP45YQRWV6Q7YVWIIPLQGLZQFHWFEQ"
);
tx = sym.AliasTransaction.createForAddress(
sym.Deadline.create(epochAdjustment),
sym.AliasAction.Link,
namespaceId,
address,
networkType
).setMaxFee(100);
signedTx = alice.sign(tx, generationHash);
await txRepo.announce(signedTx).toPromise();
リンク先のアドレスは自分が所有していなくても問題ありません。
モザイクへリンク
namespaceId = new sym.NamespaceId("xembook.tomato");
mosaicId = new sym.MosaicId("3A8416DB2D53xxxx");
tx = sym.AliasTransaction.createForMosaic(
sym.Deadline.create(epochAdjustment),
sym.AliasAction.Link,
namespaceId,
mosaicId,
networkType
).setMaxFee(100);
signedTx = alice.sign(tx, generationHash);
await txRepo.announce(signedTx).toPromise();
モザイクを作成したアドレスと同一の場合のみリンクできるようです。
6.4 未解決で使用
送信先に UnresolvedAccount として指定して、アドレスを特定しないままトランザクションを署名・アナウンスします。 チェーン側で解決されたアカウントに対しての送信が実施されます。
namespaceId = new sym.NamespaceId("xembook");
tx = sym.TransferTransaction.create(
sym.Deadline.create(epochAdjustment),
namespaceId, //UnresolvedAccount:未解決アカウントアドレス
[],
sym.EmptyMessage,
networkType
).setMaxFee(100);
signedTx = alice.sign(tx, generationHash);
await txRepo.announce(signedTx).toPromise();
送信モザイクに UnresolvedMosaic として指定して、モザイク ID を特定しないままトランザクションを署名・アナウンスします。
namespaceId = new sym.NamespaceId("xembook.tomato");
tx = sym.TransferTransaction.create(
sym.Deadline.create(epochAdjustment),
address,
[
new sym.Mosaic(
namespaceId, //UnresolvedMosaic:未解決モザイク
sym.UInt64.fromUint(1) //送信量
),
],
sym.EmptyMessage,
networkType
).setMaxFee(100);
signedTx = alice.sign(tx, generationHash);
await txRepo.announce(signedTx).toPromise();
XYM をネームスペースで使用する場合は以下のように指定します。
namespaceId = new sym.NamespaceId("symbol.xym");
> NamespaceId {fullName: 'symbol.xym', id: Id}
fullName: "symbol.xym"
id: Id {lower: 1106554862, higher: 3880491450}
Id は内部では Uint64 と呼ばれる数値 {lower: 1106554862, higher: 3880491450}
で保持されています。
6.5 参照
アドレスへリンクしたネームスペースの参照します
nsRepo = repo.createNamespaceRepository();
namespaceInfo = await nsRepo
.getNamespace(new sym.NamespaceId("xembook"))
.toPromise();
console.log(namespaceInfo);
出力例
NamespaceInfo
active: true
> alias: AddressAlias
address: Address {address: 'TBIL6D6RURP45YQRWV6Q7YVWIIPLQGLZQFHWFEQ', networkType: 152}
mosaicId: undefined
type: 2 //AliasType
depth: 1
endHeight: UInt64 {lower: 500545, higher: 0}
index: 1
levels: [NamespaceId]
ownerAddress: Address {address: 'TBIL6D6RURP45YQRWV6Q7YVWIIPLQGLZQFHWFEQ', networkType: 152}
parentId: NamespaceId {id: Id}
registrationType: 0 //NamespaceRegistrationType
startHeight: UInt64 {lower: 324865, higher: 0}
AliasType は以下の通りです。
{0: 'None', 1: 'Mosaic', 2: 'Address'}
NamespaceRegistrationType は以下の通りです。
{0: 'RootNamespace', 1: 'SubNamespace'}
モザイクへリンクしたネームスペースを参照します。
nsRepo = repo.createNamespaceRepository();
namespaceInfo = await nsRepo
.getNamespace(new sym.NamespaceId("xembook.tomato"))
.toPromise();
console.log(namespaceInfo);
出力例
NamespaceInfo
> active: true
alias: MosaicAlias
address: undefined
mosaicId: MosaicId
id: Id {lower: 1360892257, higher: 309702839}
type: 1 //AliasType
depth: 2
endHeight: UInt64 {lower: 500545, higher: 0}
index: 1
levels: (2) [NamespaceId, NamespaceId]
ownerAddress: Address {address: 'TBIL6D6RURP45YQRWV6Q7YVWIIPLQGLZQFHWFEQ', networkType: 152}
parentId: NamespaceId {id: Id}
registrationType: 1 //NamespaceRegistrationType
startHeight: UInt64 {lower: 324865, higher: 0}
逆引き
アドレスに紐づけられたネームスペースを全て調べます。
nsRepo = repo.createNamespaceRepository();
accountNames = await nsRepo
.getAccountsNames([
sym.Address.createFromRawAddress("TBIL6D6RURP45YQRWV6Q7YVWIIPLQGLZQFHWFEQ"),
])
.toPromise();
namespaceIds = accountNames[0].names.map((name) => {
return name.namespaceId;
});
console.log(namespaceIds);
モザイクに紐づけられたネームスペースを全て調べます。
nsRepo = repo.createNamespaceRepository();
mosaicNames = await nsRepo
.getMosaicsNames([new sym.MosaicId("72C0212E67A08BCE")])
.toPromise();
namespaceIds = mosaicNames[0].names.map((name) => {
return name.namespaceId;
});
console.log(namespaceIds);
レシートの参照
トランザクションに使用されたネームスペースをブロックチェーン側がどう解決したかを確認します。
receiptRepo = repo.createReceiptRepository();
state = await receiptRepo
.searchAddressResolutionStatements({ height: 179401 })
.toPromise();
出力例
data: Array(1)
0: ResolutionStatement
height: UInt64 {lower: 179401, higher: 0}
resolutionEntries: Array(1)
0: ResolutionEntry
resolved: Address {address: 'TBIL6D6RURP45YQRWV6Q7YVWIIPLQGLZQFHWFEQ', networkType: 152}
source: ReceiptSource {primaryId: 1, secondaryId: 0}
resolutionType: 0 //ResolutionType
unresolved: NamespaceId
id: Id {lower: 646738821, higher: 2754876907}
ResolutionType は以下の通りです。
{0: 'Address', 1: 'Mosaic'}
注意事項
ネームスペースはレンタル制のため、過去のトランザクションで使用したネームスペースのリンク先と 現在のネームスペースのリンク先が異なる可能性があります。 過去のデータを参照する際などに、その時どのアカウントにリンクしていたかなどを知りたい場合は 必ずレシートを参照するようにしてください。
6.6 現場で使えるヒント
外部ドメインとの相互リンク
ネームスペースは重複取得がプロトコル上制限されているため、 インターネットドメインや実世界で周知されている商標名と同一のネームスペースを取得し、 外部(公式サイトや印刷物など)からネームスペース存在の認知を公表することで、 Symbol 上のアカウントのブランド価値を構築することができます (法的な効力については調整が必要です)。 外部ドメイン側のハッキングあるいは、Symbol 側でのネームスペース更新忘れにはご注意ください。
ネームスペースを取得するアカウントについての注意
ネームスペースはレンタル期限という概念をもつ機能です。 今のところ、取得したネームスペースは放棄か延長の選択肢しかありません。 運用譲渡などが発生する可能性のあるシステムでネームスペース活用を検討する場合は マルチシグ化(9 章)したアカウントでネームスペースを取得することをおすすめします。