# Tokenizing Real-World Assets

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.

{% stepper %}
{% step %}

### 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)

```typescript
const signer = KeetaNet.lib.Account.fromSeed(DEMO_SEED, 0);
const authority = KeetaNet.lib.Account.fromSeed(DEMO_SEED, 1);
```

{% endstep %}

{% step %}

### 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

```typescript
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');
```

{% endstep %}

{% step %}

### Start a transaction builder

This prepares your transaction to include all operations in one publishable bundle.

```typescript
const builder = client.initBuilder();
builder.updateAccounts({
  signer,
  account: signer
});
```

{% endstep %}

{% step %}

### Create the token account

This is where the NFT will live. It’s a new account of type `TOKEN`.

```typescript
const token = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN);
await client.computeBuilderBlocks(builder); // seal block so token exists
```

{% endstep %}

{% step %}

### Make it non-fungible

Set the token’s supply to `1`. That means only one account can own this NFT at a time.

```typescript
builder.modifyTokenSupply(1n, { account: token.account });
```

{% endstep %}

{% step %}

### Attach metadata and permissions

Now link your signed metadata to the token, and set permissions so it can be held by any user.

```typescript
builder.setInfo({
  name: 'RWA-DEMO',
  description: 'Token representing a real-world asset',
  metadata: metadataBase64,
  defaultPermission: new KeetaNet.lib.Permissions(['ACCESS'], [])
}, {
  account: token.account
});
```

{% endstep %}

{% step %}

### Publish the transaction

Finalize and submit your transaction to the Keeta Network.

```typescript
await client.computeBuilderBlocks(builder);
await client.publishBuilder(builder);
```

{% endstep %}
{% endstepper %}

Your NFT now lives on-chain and holds signed, verifiable metadata that links it to a real-world asset.

To see its address:

```typescript
console.log('Token address:', token.account.publicKeyString.get());
```

## Full Code Example

```typescript
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);
```
