
Company News
Free Business Plan Upgrades for Open Source Maintainers
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.
@yallet/rwa-sdk
Advanced tools
SDK for minting encrypted RWA (Real World Assets) as Solana compressed NFTs (cNFTs).
npm install @yallet/rwa-sdk
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);
┌─────────────────────────────────────────────────────────────┐
│ Your Application │
├─────────────────────────────────────────────────────────────┤
│ Yallet RWA SDK │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Registry │ │ Encryption │ │ Minting │ │
│ │ (xidentity) │ │ (ECIES) │ │ (Bubblegum) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ │
│ │ Storage │ │
│ │ (Arweave) │ │
│ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Solana Blockchain │ Arweave Network │
│ (cNFT Ownership) │ (Encrypted Data Storage) │
└─────────────────────────────────────────────────────────────┘
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(),
});
Users can export their xidentity from Yallet wallet:
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).
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',
});
| Type | Description | Data Structure |
|---|---|---|
INVOICE | Invoice | InvoiceData |
NOTE | Message / note | NoteData |
FILE | File | FileData |
PHOTO | Photo | PhotoData |
CONTACT | Contact | ContactData |
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);
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(),
});
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',
}
);
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.
For full compatibility with Yallet extension decryption, use acegf WASM encryption:
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).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.
The built-in ECIES in this SDK is aligned with dev.yallet.chrome-extension (acegf WASM) so that:
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 }.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.
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,
});
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);
}
MIT
FAQs
Yallet RWA SDK - Mint encrypted invoices and assets as Solana cNFTs
We found that @yallet/rwa-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

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.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.