--secrets-provider="gcpkms://projects//locations//keyRings//cryptoKeys/"
5
###
[hashtag](https://docs.keeta.com/guides/deploying-a-node#define-gcp-project-for-pulumi)
Define GCP Project for Pulumi
Define the GCP environment that Pulumi should deploy to. This will add the GCP Project to the Pulumi..yaml file that was initialized in the previous step.
Copy
config --stack set gcp:project
6
###
[hashtag](https://docs.keeta.com/guides/deploying-a-node#add-encrypted-representative-seed)
Add Encrypted Representative SEED
Encrypted variables can be added to the Pulumi configuration as secrets, encrypted with the KMS provided earlier. In this case, `KEETANET_LAMBDA_SEED` is the environment variable the node uses along with the index of the Representative from `Regions` in the configuration to compute the private key used for Voting by the Representative. The SEED should be a 32-character hex string. For example, using openssl, a seed could be generated with `openssl rand -hex 32`
Copy
pulumi config --stack set --secret keetanet-cloud-deploy:KEETANET_LAMBDA_SEED
7
###
[hashtag](https://docs.keeta.com/guides/deploying-a-node#deploy-the-pulumi-stack)
Deploy the Pulumi Stack
The following command will build the necessary binaries and deploy all of the infrastructure components. Pulumi will display the changes with a prompt to proceed or cancel.
Copy
make do-deploy
[PreviousTokenizing Real-World Assetschevron-left](https://docs.keeta.com/guides/tokenizing-real-world-assets)
[NextOfficial Linkschevron-right](https://docs.keeta.com/other-documentation/official-links)
Last updated 4 months ago
* [Install Prerequisites](https://docs.keeta.com/guides/deploying-a-node#install-prerequisites)
* [Clone the Node Repository](https://docs.keeta.com/guides/deploying-a-node#clone-the-node-repository)
* [Create Deployment Config](https://docs.keeta.com/guides/deploying-a-node#create-deployment-config)
* [Initialize Pulumi Stack](https://docs.keeta.com/guides/deploying-a-node#initialize-pulumi-stack)
* [Define GCP Project for Pulumi](https://docs.keeta.com/guides/deploying-a-node#define-gcp-project-for-pulumi)
* [Add Encrypted Representative SEED](https://docs.keeta.com/guides/deploying-a-node#add-encrypted-representative-seed)
* [Deploy the Pulumi Stack](https://docs.keeta.com/guides/deploying-a-node#deploy-the-pulumi-stack)
---
# Tokenizing Real-World Assets | Keeta Network
This guide shows how to create a **non-fungible token (NFT)** that represents a real-world asset — like a document, a product, or a right of ownership — on the Keeta Network.
1
###
[hashtag](https://docs.keeta.com/guides/tokenizing-real-world-assets#prepare-your-accounts)
Prepare your accounts
You'll need two accounts:
* A **signer account** to send the transaction
* An **authority account** to sign the metadata (can be the same in testing)
Copy
const signer = KeetaNet.lib.Account.fromSeed(DEMO_SEED, 0);
const authority = KeetaNet.lib.Account.fromSeed(DEMO_SEED, 1);
2
###
[hashtag](https://docs.keeta.com/guides/tokenizing-real-world-assets#create-metadata-for-your-real-world-asset)
Create metadata for your real-world asset
This includes:
* A unique ID for the asset (e.g. serial number, URL, or database ref)
* A digital signature proving the authority account approved it
Copy
const assetIdBuffer = Buffer.from(ASSET_ID, 'utf-8');
const signatureBuffer = await authority.sign(assetIdBuffer);
const metadata = {
asset_id: ASSET_ID,
authority: authority.publicKeyString.get(),
signature: signatureBuffer.toString('base64')
};
const metadataBase64 = Buffer.from(JSON.stringify(metadata)).toString('base64');
3
###
[hashtag](https://docs.keeta.com/guides/tokenizing-real-world-assets#start-a-transaction-builder)
Start a transaction builder
This prepares your transaction to include all operations in one publishable bundle.
Copy
const builder = client.initBuilder();
builder.updateAccounts({
signer,
account: signer
});
4
###
[hashtag](https://docs.keeta.com/guides/tokenizing-real-world-assets#create-the-token-account)
Create the token account
This is where the NFT will live. It’s a new account of type `TOKEN`.
Copy
const token = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN);
await client.computeBuilderBlocks(builder); // seal block so token exists
5
###
[hashtag](https://docs.keeta.com/guides/tokenizing-real-world-assets#make-it-non-fungible)
Make it non-fungible
Set the token’s supply to `1`. That means only one account can own this NFT at a time.
Copy
builder.modifyTokenSupply(1n, { account: token.account });
6
###
[hashtag](https://docs.keeta.com/guides/tokenizing-real-world-assets#attach-metadata-and-permissions)
Attach metadata and permissions
Now link your signed metadata to the token, and set permissions so it can be held by any user.
Copy
builder.setInfo({
name: 'RWA-DEMO',
description: 'Token representing a real-world asset',
metadata: metadataBase64,
defaultPermission: new KeetaNet.lib.Permissions(['ACCESS'], [])
}, {
account: token.account
});
7
###
[hashtag](https://docs.keeta.com/guides/tokenizing-real-world-assets#publish-the-transaction)
Publish the transaction
Finalize and submit your transaction to the Keeta Network.
Copy
await client.computeBuilderBlocks(builder);
await client.publishBuilder(builder);
Your NFT now lives on-chain and holds signed, verifiable metadata that links it to a real-world asset.
To see its address:
Copy
console.log('Token address:', token.account.publicKeyString.get());
[hashtag](https://docs.keeta.com/guides/tokenizing-real-world-assets#full-code-example)
Full Code Example
--------------------------------------------------------------------------------------------------------------
Copy
const KeetaNet = require('@keetanetwork/keetanet-client');
const DEMO_SEED = 'D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0D3M0';
const ASSET_ID = 'asset://unique-asset-id-001';
async function main() {
// 1️⃣ Create two accounts from the seed:
// - signer: sends the transaction
// - authority: signs the metadata (can be same as signer for demo)
const signer = KeetaNet.lib.Account.fromSeed(DEMO_SEED, 0);
const authority = KeetaNet.lib.Account.fromSeed(DEMO_SEED, 1);
// 2️⃣ Connect to the Keeta test network using the signer account
const client = KeetaNet.UserClient.fromNetwork('test', signer);
// 3️⃣ Create and sign the asset metadata
const assetIdBuffer = Buffer.from(ASSET_ID, 'utf-8');
const signatureBuffer = await authority.sign(assetIdBuffer);
const metadata = {
asset_id: ASSET_ID,
authority: authority.publicKeyString.get(),
signature: signatureBuffer.toString('base64')
};
const metadataBase64 = Buffer.from(JSON.stringify(metadata)).toString('base64');
// 4️⃣ Start building a transaction
const builder = client.initBuilder();
builder.updateAccounts({
signer,
account: signer
});
// 5️⃣ Generate a new token account (this will be your NFT)
const token = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN);
// 6️⃣ Compute a block to seal the token creation (required before you can modify it)
await client.computeBuilderBlocks(builder);
// 7️⃣ Set the token supply to 1 — making it a non-fungible token
builder.modifyTokenSupply(1n, {
account: token.account
});
// 8️⃣ Attach the metadata and set default permissions (allow others to hold it)
builder.setInfo({
name: 'RWA-DEMO',
description: 'Non-Fungible Token representing a real-world asset',
metadata: metadataBase64,
defaultPermission: new KeetaNet.lib.Permissions(['ACCESS'], [])
}, {
account: token.account
});
// 9️⃣ Compute and publish all blocks to the network
await client.computeBuilderBlocks(builder);
await client.publishBuilder(builder);
// 🔚 Done — log the token's public address
console.log('✅ RWA Token created at:', token.account.publicKeyString.get());
}
main().catch(console.error);
[PreviousResolving the Blockchain Trilemmachevron-left](https://docs.keeta.com/industry-comparison/resolving-the-blockchain-trilemma)
[NextDeploying a Nodechevron-right](https://docs.keeta.com/guides/deploying-a-node)
Last updated 7 months ago
* [Prepare your accounts](https://docs.keeta.com/guides/tokenizing-real-world-assets#prepare-your-accounts)
* [Create metadata for your real-world asset](https://docs.keeta.com/guides/tokenizing-real-world-assets#create-metadata-for-your-real-world-asset)
* [Start a transaction builder](https://docs.keeta.com/guides/tokenizing-real-world-assets#start-a-transaction-builder)
* [Create the token account](https://docs.keeta.com/guides/tokenizing-real-world-assets#create-the-token-account)
* [Make it non-fungible](https://docs.keeta.com/guides/tokenizing-real-world-assets#make-it-non-fungible)
* [Attach metadata and permissions](https://docs.keeta.com/guides/tokenizing-real-world-assets#attach-metadata-and-permissions)
* [Publish the transaction](https://docs.keeta.com/guides/tokenizing-real-world-assets#publish-the-transaction)
* [Full Code Example](https://docs.keeta.com/guides/tokenizing-real-world-assets#full-code-example)
---
# Create a Storage Account | Keeta Network
This example demonstrates how to create tokens, establish shared storage accounts, and manage complex permission scenarios in Keeta. Building on the basic storage account concepts, this code shows a complete workflow involving token creation, liquidity provisioning, and delegated sending capabilities.
###
[hashtag](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-by-step)
Step by Step
1
###
[hashtag](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-1-initial-setup-and-account-generation)
Initial Setup and Account Generation
Establish the foundation by generating a random seed and create three accounts: a liquidity provider (index 0), accountA (index 1), and accountB (index 2). Each account connects to the Keeta test network.
Copy
async function main() {
const seed = KeetaNet.lib.Account.generateRandomSeed({ asString: true });
console.log("seed =", seed);
// Create liquidity provider account (token creator)
const liquidityProviderAccount = KeetaNet.lib.Account.fromSeed(seed, 0);
const liquidityProviderClient = KeetaNet.UserClient.fromNetwork("test", liquidityProviderAccount);
// Create two user accounts for shared storage
const accountA = KeetaNet.lib.Account.fromSeed(seed, 1);
const accountB = KeetaNet.lib.Account.fromSeed(seed, 2);
const userClientA = KeetaNet.UserClient.fromNetwork("test", accountA);
const userClientB = KeetaNet.UserClient.fromNetwork("test", accountB);
console.log("accountA.publicKey =", accountA.publicKeyString.toString());
console.log("accountB.publicKey =", accountB.publicKeyString.toString());
}
2
###
[hashtag](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-2-token-creation-and-minting)
Token Creation and Minting
This creates a new token account using the TOKEN algorithm, sets public access permissions, mints 10,000 tokens, and publishes the token to the blockchain. The liquidity provider becomes the initial holder of all tokens.
Copy
async function createToken(userClient: KeetaNet.UserClient) {
const builder = userClient.initBuilder();
// Create a new token account
const pendingTokenAccount = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN)
await builder.computeBlocks();
const tokenAccount = pendingTokenAccount.account;
console.log("tokenAccount.publicKey =", tokenAccount.publicKeyString.toString());
// Set token permissions and metadata
builder.setInfo({
name: '',
description: '',
metadata: '',
defaultPermission: new KeetaNet.lib.Permissions(['ACCESS']), // Public token
}, { account: tokenAccount });
// Mint 10,000 tokens
builder.modifyTokenSupply(10_000n, { account: tokenAccount });
builder.modifyTokenBalance(tokenAccount, 10_000n);
// Publish to blockchain
await userClient.publishBuilder(builder);
console.log("Token account created and minted.\n");
return tokenAccount;
}
// Call the function in main()
console.log("\nCreating liquidity provider account and token account...");
const tokenAccount = await createToken(liquidityProviderClient);
console.log("liquidityProviderClient.balances[] =", await liquidityProviderClient.allBalances());
3
###
[hashtag](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-3-storage-account-creation-with-permissions)
Storage Account Creation with Permissions
This creates a storage account with default permissions allowing token holding and deposits. AccountB receives `SEND_ON_BEHALF` permission, enabling it to send tokens from the storage account without being the owner.
Copy
// Check initial storage accounts (should be empty)
console.log("\nChecking storage accounts before creation:");
console.log("accountA.storageAccounts[] =", (await userClientA.listACLsByPrincipal()).filter(acl => acl.entity.isStorage()));
console.log("accountB.storageAccounts[] =", (await userClientB.listACLsByPrincipal()).filter(acl => acl.entity.isStorage()));
// Create storage account
const builder = userClientA.initBuilder();
const pendingStorageAccount = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.STORAGE);
await builder.computeBlocks();
const storageAccount = pendingStorageAccount.account;
console.log("storageAccount.publicKey =", storageAccount.publicKeyString.toString());
// Set default permissions
builder.setInfo({
name: '',
description: '',
metadata: '',
defaultPermission: new KeetaNet.lib.Permissions([\
'STORAGE_CAN_HOLD', // Allow holding any token\
'STORAGE_DEPOSIT', // Allow anyone to deposit\
])
}, { account: storageAccount });
// Grant SEND_ON_BEHALF permission to accountB
builder.updatePermissions(
accountB,
new KeetaNet.lib.Permissions(['SEND_ON_BEHALF']),
undefined,
undefined,
{ account: storageAccount }
);
// Publish storage account
await userClientA.publishBuilder(builder);
console.log("Storage account created and permissions updated.");
4
###
[hashtag](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-4-token-distribution)
Token Distribution
The liquidity provider distributes tokens: 1,000 tokens to the storage account for shared use and 5,000 tokens to accountA for individual use. This creates a realistic shared treasury scenario.
Copy
// Check balances before distribution
console.log("\nChecking balances before deposit:");
console.log("accountA.balances[] =", await userClientA.allBalances());
console.log("accountB.balances[] =", await userClientB.allBalances());
console.log("storageAccount.balances[] =", await userClientA.allBalances({ account: storageAccount }));
// Distribute tokens from liquidity provider
console.log("\nDepositing tokens from the liquidity provider...");
const builderSend = await liquidityProviderClient.initBuilder();
builderSend.send(storageAccount, 1_000n, tokenAccount); // 1,000 to storage
builderSend.send(accountA, 5_000n, tokenAccount); // 5,000 to accountA
await liquidityProviderClient.publishBuilder(builderSend);
// Check balances after distribution
console.log("\nChecking balances after deposit:");
console.log("accountA.balances[] =", await userClientA.allBalances());
console.log("accountB.balances[] =", await userClientB.allBalances());
console.log("storageAccount.balances[] =", await userClientA.allBalances({ account: storageAccount }));
5
###
[hashtag](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#delegated-operations-using-send_on_behalf)
Delegated Operations Using SEND\_ON\_BEHALF
AccountB uses its `SEND_ON_BEHALF` permission to send tokens from the storage account: 500 tokens to accountA and 300 tokens to itself. The `{ account: storageAccount }` parameter specifies the source account for delegated operations.
Copy
// accountB sends tokens from storageAccount using SEND_ON_BEHALF permission
await userClientB.send(accountA, 500n, tokenAccount, undefined, { account: storageAccount });
await userClientB.send(accountB, 300n, tokenAccount, undefined, { account: storageAccount });
// Check final balances
console.log("\nChecking balances after accountB sends tokens from storageAccount:");
console.log("accountA.balances[] =", await userClientA.allBalances());
console.log("accountB.balances[] =", await userClientB.allBalances());
console.log("storageAccount.balances[] =", await userClientA.allBalances({ account: storageAccount }));
This workflow demonstrates how to create a complete token ecosystem with shared storage and delegated permissions, enabling team treasuries, shared wallets, and controlled token distribution systems.
[hashtag](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#full-code-example)
Full Code Example
----------------------------------------------------------------------------------------------------------------------------------------
Copy
import * as KeetaNet from "@keetanetwork/keetanet-client";
// Token creation function
async function createToken(userClient: KeetaNet.UserClient) {
const builder = userClient.initBuilder();
// Create a new token account
const pendingTokenAccount = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN)
await builder.computeBlocks();
const tokenAccount = pendingTokenAccount.account;
console.log("tokenAccount.publicKey =", tokenAccount.publicKeyString.toString());
// Setting the token account default permissions
builder.setInfo(
{
name: '',
description: '',
metadata: '',
defaultPermission: new KeetaNet.lib.Permissions([\
'ACCESS', // Public token\
]),
},
{ account: tokenAccount },
)
// Minting the token
builder.modifyTokenSupply(10_000n, { account: tokenAccount });
builder.modifyTokenBalance(tokenAccount, 10_000n)
// Publish the blocks
await userClient.publishBuilder(builder);
console.log("Token account created and minted.\n");
return tokenAccount;
}
async function main() {
const seed = KeetaNet.lib.Account.generateRandomSeed({ asString: true });
console.log("seed =", seed);
/**
* Creating liquidity provider account and token account
*/
console.log("\nCreating liquidity provider account and token account...");
const liquidityProviderAccount = KeetaNet.lib.Account.fromSeed(seed, 0);
const liquidityProviderClient = KeetaNet.UserClient.fromNetwork("test", liquidityProviderAccount);
const tokenAccount = await createToken(liquidityProviderClient);
console.log("liquidityProviderClient.balances[] =", await liquidityProviderClient.allBalances());
/**
* Creating two user accounts (accountA and accountB)
* to demonstrate shared storage account creation.
*/
const accountA = KeetaNet.lib.Account.fromSeed(seed, 1);
const accountB = KeetaNet.lib.Account.fromSeed(seed, 2);
const userClientA = KeetaNet.UserClient.fromNetwork("test", accountA);
const userClientB = KeetaNet.UserClient.fromNetwork("test", accountB);
console.log("\nGetting accounts:");
console.log("accountA.publicKey =", accountA.publicKeyString.toString());
console.log("accountB.publicKey =", accountB.publicKeyString.toString());
/**
* Checking owned storage accounts
*/
console.log("\nChecking storage accounts before creation:");
console.log("accountA.storageAccounts[] =", (await userClientA.listACLsByPrincipal()).filter(acl => acl.entity.isStorage()));
console.log("accountB.storageAccounts[] =", (await userClientB.listACLsByPrincipal()).filter(acl => acl.entity.isStorage()));
/**
* Creating a storage account
*/
// Initialize the user client builder
const builder = userClientA.initBuilder();
// Create a new storage account
const pendingStorageAccount = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.STORAGE);
// Compute the pending storage account
await builder.computeBlocks();
// Get the storage account
const storageAccount = pendingStorageAccount.account;
console.log("storageAccount.publicKey =", storageAccount.publicKeyString.toString());
// Setting the storage account default permissions
builder.setInfo({
name: '',
description: '',
metadata: '',
defaultPermission: new KeetaNet.lib.Permissions([\
'STORAGE_CAN_HOLD', // Allow the storage account to hold any token\
'STORAGE_DEPOSIT', // Allow everyone to deposit into the storage account\
])
}, { account: storageAccount });
// Until here, only `accountA` has access to the storageAccount, his permission is "OWNER".
/**
* Adding permission for `accountB` on the `storageAccount`
*
* Here we can set "ADMIN" or "SEND_ON_BEHALF" permissions for `accountB`.
* "ADMIN" would allow `accountB` to manage the storage account, while
* "SEND_ON_BEHALF" would allow `accountB` to send tokens from the storage account
*/
builder.updatePermissions(
accountB,
new KeetaNet.lib.Permissions(['SEND_ON_BEHALF']),
undefined,
undefined,
{ account: storageAccount }
);
// Publish the blocks
await userClientA.publishBuilder(builder);
console.log("Storage account created and permissions updated.");
/**
* Checking owned storage accounts
*/
console.log("\nChecking storage accounts after creation:");
console.log("accountA.storageAccounts[] =", (await userClientA.listACLsByPrincipal()).filter(acl => acl.entity.isStorage()).map(acl => acl.entity.publicKeyString.toString()));
console.log("accountB.storageAccounts[] =", (await userClientB.listACLsByPrincipal()).filter(acl => acl.entity.isStorage()).map(acl => acl.entity.publicKeyString.toString()));
/**
* Checking balances before deposit
*/
console.log("\nChecking balances before deposit:");
console.log("accountA.balances[] =", await userClientA.allBalances());
console.log("accountB.balances[] =", await userClientB.allBalances());
console.log("accountA.storageAccount.balances[] =", await userClientA.allBalances({ account: storageAccount }));
console.log("accountB.storageAccount.balances[] =", await userClientB.allBalances({ account: storageAccount }));
/**
* Depositing tokens from the liquidity provider
* LP -> SEND 1_000 -> storageAccount
* LP -> SEND 5_000 -> accountA
*/
console.log("\nDepositing tokens from the liquidity provider...");
const builderSend = await liquidityProviderClient.initBuilder();
builderSend.send(storageAccount, 1_000n, tokenAccount);
builderSend.send(accountA, 5_000n, tokenAccount);
await liquidityProviderClient.publishBuilder(builderSend);
/**
* Checking balances after deposit
*/
console.log("\nChecking balances after deposit:");
console.log("accountA.balances[] =", await userClientA.allBalances());
console.log("accountB.balances[] =", await userClientB.allBalances());
console.log("accountA.storageAccount.balances[] =", await userClientA.allBalances({ account: storageAccount }));
console.log("accountB.storageAccount.balances[] =", await userClientB.allBalances({ account: storageAccount }));
/**
* Depositing tokens from the storage account
* accountB using storageAccount -> SEND 500 -> accountA
* accountB using storageAccount -> SEND 300 -> accountB
*/
await userClientB.send(accountA, 500n, tokenAccount, undefined, { account: storageAccount });
await userClientB.send(accountB, 300n, tokenAccount, undefined, { account: storageAccount });
console.log("\nChecking balances after accountB sends 500 tokens from storageAccount to accountA:");
console.log("accountA.balances[] =", await userClientA.allBalances());
console.log("accountB.balances[] =", await userClientB.allBalances());
console.log("accountA.storageAccount.balances[] =", await userClientA.allBalances({ account: storageAccount }));
console.log("accountB.storageAccount.balances[] =", await userClientB.allBalances({ account: storageAccount }));
}
main().then(() => {
console.log("Done");
process.exit(0);
}).catch((err) => {
console.error("Error:", err);
process.exit(1);
});
[PreviousStorage Accountschevron-left](https://docs.keeta.com/components/accounts/storage-accounts)
[NextSingle-Token Storage Accountchevron-right](https://docs.keeta.com/components/accounts/storage-accounts/single-token-storage-account)
Last updated 5 months ago
* [Step by Step](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-by-step)
* [Initial Setup and Account Generation](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-1-initial-setup-and-account-generation)
* [Token Creation and Minting](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-2-token-creation-and-minting)
* [Storage Account Creation with Permissions](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-3-storage-account-creation-with-permissions)
* [Token Distribution](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#step-4-token-distribution)
* [Delegated Operations Using SEND\_ON\_BEHALF](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#delegated-operations-using-send_on_behalf)
* [Full Code Example](https://docs.keeta.com/components/accounts/storage-accounts/create-a-storage-account#full-code-example)
---
# Email Protection | Cloudflare
Please enable cookies.
Email Protection
================
You are unable to access this email address docs.keeta.com
----------------------------------------------------------
The website from which you got to this page is protected by Cloudflare. Email addresses on that page have been hidden in order to keep them from being accessed by malicious bots. **You must enable Javascript in your browser in order to decode the e-mail address**.
If you have a website and are interested in protecting it in a similar way, you can [sign up for Cloudflare](https://www.cloudflare.com/sign-up?utm_source=email_protection)
.
* [How does Cloudflare protect email addresses on website from spammers?](https://developers.cloudflare.com/waf/tools/scrape-shield/email-address-obfuscation/)
* [Can I sign up for Cloudflare?](https://developers.cloudflare.com/fundamentals/setup/account/create-account/)
Cloudflare Ray ID: **9bfdf353cba21eda** • Your IP: Click to reveal 54.237.218.47 • Performance & security by [Cloudflare](https://www.cloudflare.com/5xx-error-landing)
---
# generateIdentifier | Keeta Network
The `generateIdentifier()` operation creates a new identifier for an account or asset, such as a network, token, or storage entity. This function is typically used when initializing new assets or accounts that require a unique identifier on the Keeta Network.
This operation is part of the \`builder\` and is added to a transaction before publishing.
[hashtag](https://docs.keeta.com/components/blocks/operations/generateidentifier#when-to-use)
When to Use
--------------------------------------------------------------------------------------------------------------
* Creating a new token, network, or storage account
* Assigning a unique identifier to a new asset
* Initializing accounts before attaching metadata or permissions
[hashtag](https://docs.keeta.com/components/blocks/operations/generateidentifier#when-to-use-it)
When to Use It?
---------------------------------------------------------------------------------------------------------------------
* Ensuring each asset or account has a unique and valid identifier
* Streamlining the creation of new entities on the network
[hashtag](https://docs.keeta.com/components/blocks/operations/generateidentifier#example-creating-a-new-token-account-with-generateidentifier-and-setting-info)
Example; Creating a new token account with generateIdentifier and setting info
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Here’s a simplified example using the transaction builder. See the ‘[Tokenizing Real-World Assets](https://docs.keeta.com/guides/tokenizing-real-world-assets)
’ section for a full implementation,
Copy
// Step 1: Generate a new token identifier with custom options
const pendingAccount = builder.generateIdentifier('TOKEN', {
owner: user.account, // Assign the initial owner of the token
symbol: 'DEMO', // Token symbol
decimals: 2, // Number of decimal places
metadata: {
category: 'Real World Asset',
createdBy: 'Demo Script'
}
});
// Step 2: Prepare base64-encoded metadata (for demonstration)
const assetInfo = {
assetType: 'Real World Asset',
issuer: 'Demo Organization',
issuedAt: new Date().toISOString()
};
const metadata_base64 = Buffer.from(JSON.stringify(assetInfo)).toString('base64');
// Step 3: Attach info and default permissions to the new token account
builder.setInfo({
name: 'DEMORWA',
description: 'Demo Token for Real World Asset',
metadata: metadata_base64, // base64-encoded JSON with asset info + signature
defaultPermission: newKeetaNet.lib.Permissions(['ACCESS'], [])
}, {
account: pendingAccount.account // The account you're attaching this info to
});
* type – The category of identifier to generate. Can be \`NETWORK\`, \`TOKEN\`, or \`STORAGE\`.
* options – (Optional) Additional parameters to customize the identifier generation.
* Returns – A \`PendingAccount\` object representing the newly created identifier.
Last updated 6 months ago
* [When to Use](https://docs.keeta.com/components/blocks/operations/generateidentifier#when-to-use)
* [When to Use It?](https://docs.keeta.com/components/blocks/operations/generateidentifier#when-to-use-it)
* [Example; Creating a new token account with generateIdentifier and setting info](https://docs.keeta.com/components/blocks/operations/generateidentifier#example-creating-a-new-token-account-with-generateidentifier-and-setting-info)
---