🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@yallet/rwa-sdk

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@yallet/rwa-sdk

Yallet RWA SDK - Mint encrypted invoices and assets as Solana cNFTs

latest
Source
npmnpm
Version
0.2.0
Version published
Maintainers
1
Created
Source

Yallet RWA SDK

SDK for minting encrypted RWA (Real World Assets) as Solana compressed NFTs (cNFTs).

Features

  • 🔐 End-to-end encryption using xidentity (X25519) public keys
  • 📦 Permanent storage on Arweave via ArDrive Turbo
  • 🌳 Compressed NFTs via Metaplex Bubblegum (low cost)
  • 👥 User registry for xidentity management
  • 📄 Multiple asset types: Invoices, Notes (messages), Files, Photos, Contacts
  • 🔗 Chrome extension compatible: Payloads match Yallet extension decrypt format
  • 🧩 Optional WASM: Use acegf WASM for encryption (see wasm/README.md)

Installation

npm install @yallet/rwa-sdk

Quick Start

import { createRWASDK, AssetType } from '@yallet/rwa-sdk';

// 1. Create SDK instance
const sdk = createRWASDK({
  rpcEndpoint: 'https://api.mainnet-beta.solana.com',
  network: 'mainnet',
  merkleTreeAddress: 'YOUR_MERKLE_TREE_ADDRESS',
  arweaveApiKey: 'YOUR_ARWEAVE_API_KEY', // Optional for free tier
});

// 2. Set up signer (for minting transactions)
import { keypairIdentity } from '@metaplex-foundation/umi';
sdk.setSigner(yourKeypair);

// 3. Register users with their xidentity
await sdk.registerUser({
  solanaAddress: 'CUSTOMER_WALLET_ADDRESS',
  xidentity: 'BASE64_XIDENTITY_PUBLIC_KEY', // From Yallet wallet
  name: 'Customer Name',
  registeredAt: Date.now(),
});

// 4. Mint encrypted invoice
const result = await sdk.mintInvoice(
  {
    invoiceId: 'INV-2024-001',
    amount: 1500.00,
    currency: 'USD',
    date: new Date().toISOString(),
    dueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
    items: [
      { description: 'Consulting Services', quantity: 10, unitPrice: 150, amount: 1500 }
    ],
  },
  'CUSTOMER_WALLET_ADDRESS',
  { name: 'Invoice #INV-2024-001' }
);

console.log('Minted:', result.assetId);
console.log('Signature:', result.signature);

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      Your Application                        │
├─────────────────────────────────────────────────────────────┤
│                     Yallet RWA SDK                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │  Registry   │  │ Encryption  │  │   Minting   │         │
│  │ (xidentity) │  │   (ECIES)   │  │ (Bubblegum) │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│                   ┌─────────────┐                           │
│                   │   Storage   │                           │
│                   │  (Arweave)  │                           │
│                   └─────────────┘                           │
├─────────────────────────────────────────────────────────────┤
│  Solana Blockchain        │         Arweave Network         │
│  (cNFT Ownership)         │      (Encrypted Data Storage)   │
└─────────────────────────────────────────────────────────────┘

User Registration Flow

Before minting assets to a user, they must register their xidentity:

// User provides their xidentity (from Yallet wallet)
// The xidentity is a base64-encoded X25519 public key

await sdk.registerUser({
  solanaAddress: 'USER_WALLET_ADDRESS',
  xidentity: 'ZzFXyDpLw7GMu3PiPopkM7hHBRWTupjcP7qxSJO2SHU=',
  name: 'John Doe',
  email: 'john@example.com', // Optional
  registeredAt: Date.now(),
});

Getting xidentity from Yallet Wallet

Users can export their xidentity from Yallet wallet:

  • Open Yallet → Settings → Export xidentity
  • The xidentity is safe to share (it's a public key)
  • Only the wallet owner can decrypt assets encrypted with their xidentity

API Reference

createRWASDK(config, options?)

Create a new SDK instance.

const sdk = createRWASDK({
  // Required
  rpcEndpoint: 'https://api.mainnet-beta.solana.com',
  network: 'mainnet', // or 'devnet'

  // Merkle Tree (required for minting)
  merkleTreeAddress: 'YOUR_TREE_ADDRESS',
  merkleTreeAuthority: 'TREE_AUTHORITY', // Optional

  // Arweave (optional)
  arweaveEndpoint: 'https://turbo.irys.xyz',
  arweaveApiKey: 'YOUR_API_KEY',

  // Backend API (optional, for tree management)
  backendApiUrl: 'https://api.yourdomain.com',
});

sdk.registerUser(user)

Register a user with their xidentity.

await sdk.registerUser({
  solanaAddress: string,  // User's Solana wallet address
  xidentity: string,      // Base64-encoded X25519 public key
  name?: string,          // Display name
  email?: string,         // Email address
  metadata?: object,      // Custom metadata
});

sdk.mintInvoice(invoice, recipientAddress, options?)

Mint an encrypted invoice to a registered user (payload matches Yallet extension decrypt format). Optionally pass pdfBase64, senderProfile, recipientProfile for extension display.

sdk.mintFile(file, recipientAddress, options?)

Mint an encrypted file (FileData: filename, mimeType, content base64, size).

sdk.mintMessage(note, recipientAddress, options?)

Mint an encrypted message/note (NoteData: title, content), with optional replyTo. Payload type is always sent (institution sends to users).

sdk.mintPhoto(photo, recipientAddress, options?)

Mint an encrypted photo (PhotoData: filename, mimeType, content base64).

Example: mintInvoice

const result = await sdk.mintInvoice(
  {
    invoiceId: 'INV-001',
    amount: 100.00,
    currency: 'USD',
    date: '2024-01-15T00:00:00Z',
    dueDate: '2024-02-15T00:00:00Z',
    description: 'Monthly subscription',
    items: [
      { description: 'Service', quantity: 1, unitPrice: 100, amount: 100 }
    ],
  },
  'RECIPIENT_ADDRESS',
  { name: 'Invoice #INV-001', pdfBase64: '...' }  // optional PDF
);

sdk.mint(request)

Mint any asset type.

const result = await sdk.mint({
  assetType: AssetType.NOTE,
  assetData: {
    title: 'Meeting Notes',
    content: 'Discussion points...',
    tags: ['meeting', 'project-x'],
  },
  recipientAddress: 'RECIPIENT_ADDRESS',
  name: 'Meeting Notes - Jan 15',
});

Asset Types

TypeDescriptionData Structure
INVOICEInvoiceInvoiceData
NOTEMessage / noteNoteData
FILEFileFileData
PHOTOPhotoPhotoData
CONTACTContactContactData

Payload builders (extension JSON–compatible)

To customize the payload before encryption, use the same builder functions the Yallet extension expects:

import {
  buildInvoicePayload,
  buildFilePayload,
  buildMessagePayload,
  buildPhotoPayload,
} from '@yallet/rwa-sdk';

const bundle = buildInvoicePayload(invoice, { pdfBase64, senderProfile, recipientProfile });
const filePayload = buildFilePayload(fileData);
const notePayload = buildMessagePayload(noteData, { replyTo: previousNftId });
const photoPayload = buildPhotoPayload(photoData);

Custom User Registry

For production, implement a database-backed registry:

import { createRWASDK } from '@yallet/rwa-sdk';

const sdk = createRWASDK(config, {
  registry: {
    type: 'http',
    httpConfig: {
      baseUrl: 'https://api.yourdomain.com/registry',
      apiKey: 'YOUR_API_KEY',
    },
  },
});

Or implement the UserRegistry interface:

import type { UserRegistry, RegisteredUser } from '@yallet/rwa-sdk';

class MyDatabaseRegistry implements UserRegistry {
  async getUser(solanaAddress: string): Promise<RegisteredUser | null> {
    // Query your database
  }
  async registerUser(user: RegisteredUser): Promise<void> {
    // Insert into database
  }
  // ... other methods
}

const sdk = createRWASDK(config, {
  registry: new MyDatabaseRegistry(),
});

Server-side Mint (Yault credential NFT)

For Yault or other apps that prefer server-side mint (no registry, no signer):

import { mintCredentialNftViaServer, RWA_UPLOAD_AND_MINT_ENDPOINTS } from '@yallet/rwa-sdk';

const result = await mintCredentialNftViaServer(
  recipientSolanaAddress,
  { user_cred, mnemonic, index, label },
  {
    xidentity: recipientXidentity,  // from recipient-addresses API
    dev: true,                      // use built-in dev endpoint
    uploadAndMintApiUrl: undefined, // override if needed
    network: 'devnet',
  }
);

Dev mode

When dev: true and uploadAndMintApiUrl is not set, the SDK uses RWA_UPLOAD_AND_MINT_ENDPOINTS.dev (api.yallet.xyz). For production, use dev: false or pass uploadAndMintApiUrl explicitly.

WASM encryption (Yallet extension–compatible)

For full compatibility with Yallet extension decryption, use acegf WASM encryption:

  • In acegf-wallet, run wasm-pack build --target web, then copy the generated pkg/acegf_bg.wasm and pkg/acegf.js into this SDK's wasm/ directory (or your deploy path).
  • In your app, initialize WASM and pass the encrypt function into the SDK:
import init from './wasm/acegf.js';  // or your path
import { createRWASDK, createWasmEncryptor } from '@yallet/rwa-sdk';

const acegf = await init();  // optional wasm path: init('/path/to/acegf_bg.wasm')
const sdk = createRWASDK(config, {
  wasmEncryptFn: createWasmEncryptor(acegf.acegf_encrypt_for_xidentity),
});

Without wasmEncryptFn, the SDK uses built-in pure JS ECIES; production should use WASM. See wasm/README.md.

Encryption ↔ extension decrypt (inverse)

The built-in ECIES in this SDK is aligned with dev.yallet.chrome-extension (acegf WASM) so that:

  • Encrypt (SDK / Yault): shared_secret = ECDH(ephemeral, xidentity)dh_key = SHA256(shared_secret)encrypted_aes_key = AES-GCM(dh_key).encrypt(iv, random_aes_key)encrypted_data = AES-GCM(aes_key).encrypt(iv, plaintext). Payload on Arweave: { encrypted: { ephemeral_pub, encrypted_aes_key, iv, encrypted_data }, metadata }.
  • Decrypt (extension): dh_key = SHA256(ECDH(ephemeral_pub, recipient_private))aes_key = AES-GCM(dh_key).decrypt(iv, encrypted_aes_key)plaintext = AES-GCM(aes_key).decrypt(iv, encrypted_data) → decode base64, optional gzip, then envelope.data (e.g. note { title, content, metadata }).

Envelope shape: { version, type, timestamp, uuid, schema?, previousToken?, data: asset }. The extension expects envelope.data to have e.g. title and content for notes. Server-side credential mint uses the same envelope and note shape so the extension can decrypt and show the note.

Merkle Tree Setup

Before minting, you need a Merkle tree. Create one using Metaplex:

import { createTree } from '@metaplex-foundation/mpl-bubblegum';

const { tree } = await createTree(umi, {
  maxDepth: 14,        // 16,384 NFTs capacity
  maxBufferSize: 64,
});

sdk.setTreeConfig({
  treeAddress: tree.publicKey,
  treeAuthority: umi.identity.publicKey,
  maxDepth: 14,
  capacity: 16384,
  used: 0,
  remaining: 16384,
  usagePercent: 0,
});

Error Handling

const result = await sdk.mintInvoice(invoice, recipientAddress);

if (!result.success) {
  console.error('Minting failed:', result.error);
  // Handle error
} else {
  console.log('Success! Asset ID:', result.assetId);
}

License

MIT

Keywords

yallet

FAQs

Package last updated on 08 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts