Add custom data to a namespace.
Metadata can be attached to namespaces to help users verify the ownership of the registered name. The data attached could include information such as registrant, administrative, or technical contact information.
Imagine that the company ComfyClothingCompany wants to add their information to their namespace cc
so that any user of the network can quickly identify the company’s details.
In this guide, you are going to implement a program to add metadata entries to a namespace.
Complete the getting started section.
Create a new account.
Load the account with enough symbol.xym
to pay for transaction fees, create mosaics and register namespaces.
Create a new namespace cc
with the ComfyClothingCompany’s account.
symbol-cli transaction namespace --sync
Enter namespace name: cc
Do you want to create a root namespace? [y/n]: y
Enter the namespace rental duration: 1000
Enter max_fee (absolute amount): 0
Transaction confirmed.
Define the following NamespaceMetadataTransaction.
Key |
Value |
---|---|
NAME |
ComfyClothingCompany |
ADDRESS |
ComfyClothingCompany HQ |
PHONE |
000-0000 |
// replace with network type
const networkType = NetworkType.TEST_NET;
// replace with company private key
const companyPrivateKey =
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
const companyAccount = Account.createFromPrivateKey(
companyPrivateKey,
networkType,
);
// replace with namespace name
const namespaceId = new NamespaceId('cc');
const name = 'ComfyClothingCompany';
const email = 'info@comfyclothingcompany';
const address = 'ComfyClothingCompany HQ';
const phone = '000-0000';
const nameMetadataTransaction = NamespaceMetadataTransaction.create(
Deadline.create(epochAdjustment),
companyAccount.address,
KeyGenerator.generateUInt64Key('NAME'),
namespaceId,
name.length,
name,
networkType,
);
const emailMetadataTransaction = NamespaceMetadataTransaction.create(
Deadline.create(epochAdjustment),
companyAccount.address,
KeyGenerator.generateUInt64Key('EMAIL'),
namespaceId,
email.length,
email,
networkType,
);
const addressMetadataTransaction = NamespaceMetadataTransaction.create(
Deadline.create(epochAdjustment),
companyAccount.address,
KeyGenerator.generateUInt64Key('ADDRESS'),
namespaceId,
address.length,
address,
networkType,
);
const phoneMetadataTransaction = NamespaceMetadataTransaction.create(
Deadline.create(epochAdjustment),
companyAccount.address,
KeyGenerator.generateUInt64Key('PHONE'),
namespaceId,
phone.length,
phone,
networkType,
);
// replace with network type
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
// replace with company private key
const companyPrivateKey = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
const companyAccount = symbol_sdk_1.Account.createFromPrivateKey(companyPrivateKey, networkType);
// replace with namespace name
const namespaceId = new symbol_sdk_1.NamespaceId('cc');
const name = 'ComfyClothingCompany';
const email = 'info@comfyclothingcompany';
const address = 'ComfyClothingCompany HQ';
const phone = '000-0000';
const nameMetadataTransaction = symbol_sdk_1.NamespaceMetadataTransaction.create(symbol_sdk_1.Deadline.create(epochAdjustment), companyAccount.address, symbol_sdk_1.KeyGenerator.generateUInt64Key('NAME'), namespaceId, name.length, name, networkType);
const emailMetadataTransaction = symbol_sdk_1.NamespaceMetadataTransaction.create(symbol_sdk_1.Deadline.create(epochAdjustment), companyAccount.address, symbol_sdk_1.KeyGenerator.generateUInt64Key('EMAIL'), namespaceId, email.length, email, networkType);
const addressMetadataTransaction = symbol_sdk_1.NamespaceMetadataTransaction.create(symbol_sdk_1.Deadline.create(epochAdjustment), companyAccount.address, symbol_sdk_1.KeyGenerator.generateUInt64Key('ADDRESS'), namespaceId, address.length, address, networkType);
const phoneMetadataTransaction = symbol_sdk_1.NamespaceMetadataTransaction.create(symbol_sdk_1.Deadline.create(epochAdjustment), companyAccount.address, symbol_sdk_1.KeyGenerator.generateUInt64Key('PHONE'), namespaceId, phone.length, phone, networkType);
2. All metadata is attached only with the consent of the namespace creator through Aggregate Transactions. Wrap the metadata transactions inside an AggregateCompleteTransaction and sign the aggregate with the company’s account.
const aggregateTransaction = AggregateTransaction.createComplete(
Deadline.create(epochAdjustment),
[
nameMetadataTransaction.toAggregate(companyAccount.publicAccount),
emailMetadataTransaction.toAggregate(companyAccount.publicAccount),
addressMetadataTransaction.toAggregate(companyAccount.publicAccount),
phoneMetadataTransaction.toAggregate(companyAccount.publicAccount),
],
networkType,
[],
UInt64.fromUint(2000000),
);
const aggregateTransaction = symbol_sdk_1.AggregateTransaction.createComplete(symbol_sdk_1.Deadline.create(epochAdjustment), [
nameMetadataTransaction.toAggregate(companyAccount.publicAccount),
emailMetadataTransaction.toAggregate(companyAccount.publicAccount),
addressMetadataTransaction.toAggregate(companyAccount.publicAccount),
phoneMetadataTransaction.toAggregate(companyAccount.publicAccount),
], networkType, [], symbol_sdk_1.UInt64.fromUint(2000000));
Note
If a namespace was owned by a different account, you would need to set the aggregate as bonded. Then, the namespace creator needs to accept the metadata request by cosigning the transaction.
Sign and announce the AggregateTransaction to the network.
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
'1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = companyAccount.sign(
aggregateTransaction,
networkGenerationHash,
);
console.log(signedTransaction.hash);
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp.announce(signedTransaction).subscribe(
(x) => console.log(x),
(err) => console.error(err),
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash = '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = companyAccount.sign(aggregateTransaction, networkGenerationHash);
console.log(signedTransaction.hash);
const nodeUrl = 'NODE_URL';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp.announce(signedTransaction).subscribe((x) => console.log(x), (err) => console.error(err));
When the transaction gets confirmed, try to fetch the namespace’s metadata entries.
Open a terminal window and run the following command.
Replace TCM6YD-BC3BW2-ZYXOXC-HHIRDV-MEZUIP-BRISYI-TPQ
with the namespace owner address, 85BBEA6CC462B244
with the target namespace id.
Then, set the key-value pairs you want to attatch as metadata.
Note
You can use the command symbol-cli converter stringtokey
to transform an string (e.g. NAME
) into a valid UInt64 key (8B5DD479E6AB718A
).
symbol-cli transaction namespacemetadata --target-address TCM6YD-BC3BW2-ZYXOXC-HHIRDV-MEZUIP-BRISYI-TPQ --namespace-id 85BBEA6CC462B244 --key 8B5DD479E6AB718A --value ComfyClothingCompany
symbol-cli transaction namespacemetadata --target-address TCM6YD-BC3BW2-ZYXOXC-HHIRDV-MEZUIP-BRISYI-TPQ --namespace-id 85BBEA6CC462B244 --key 802FE471ADA04D9D --value info@comfyclothingcompany
symbol-cli transaction namespacemetadata --target-address TCM6YD-BC3BW2-ZYXOXC-HHIRDV-MEZUIP-BRISYI-TPQ --namespace-id 85BBEA6CC462B244 --key D14E8FE298386BF5 --value ComfyClothingCompanyHQ
symbol-cli transaction namespacemetadata --target-address TCM6YD-BC3BW2-ZYXOXC-HHIRDV-MEZUIP-BRISYI-TPQ --namespace-id 85BBEA6CC462B244 --key FAAE8FBA0227A914 --value 000-0000