Skip to content

IQCoreTeam/iqlabs-solana-sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

129 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IQLabs SDK

Draft: This document is in progress and will be refined.


Table of Contents

  1. Core Concepts

  2. Function Details

2.1. Advanced Functions (list only)


Core Concepts

These are the key concepts to know before using the IQLabs SDK.


Data Storage (Code In)

This is how you store any data (files, text, JSON) on-chain.

How is it stored?

Depending on data size, the SDK picks the optimal method:

  • Small data (< 900 bytes): store immediately, fastest
  • Medium data (< 8.5 KB): split into multiple transactions
  • Large data (>= 8.5 KB): upload in parallel for speed

Key related functions


User State PDA

An on-chain profile account for a user.

What gets stored?

  • Profile info (name, profile picture, bio, etc.)
  • Number of uploaded files
  • Friend request records

Note: Friend requests are not stored as values in the PDA; they are sent as transactions.

When is it created?

It is created automatically the first time you call codeIn(). No extra setup is required, but the first user may need to sign twice.


Connection PDA

An on-chain account that manages relationships between two users (friends, messages, etc.).

What states can it have?

  • pending: a friend request was sent but not accepted yet
  • approved: the request was accepted and the users are connected
  • blocked: one side blocked the other

Important: A blocked connection can only be unblocked by the blocker.

Key related functions


Database Tables

Store JSON data in tables like a database.

How are tables created?

You can create tables explicitly with createTable(), or implicitly — the first write via writeRow() creates the table automatically.

Note: A table is uniquely identified by the combination of dbRootId and tableSeed (table name).

Key related functions


Token & Collection Gating

Tables can be gated so that only users holding a specific token or NFT collection can write data.

Gate Types

Type GateType Description
Token GateType.Token User must hold >= amount of the specified SPL token mint
Collection GateType.Collection User must hold any NFT from the specified Metaplex verified collection

How it works

  • Table creator sets the gate when creating or updating a table
  • Writers don't need to do anything special — the SDK automatically resolves the required token account (and metadata account for collections) when calling writeRow() or manageRowData()
  • If no gate is set, the table is public (default behavior, no change for existing users)

Gate parameter

gate?: {
  mint: PublicKey;       // token mint address OR collection address
  amount?: number;       // minimum token amount (default: 1, ignored for collections)
  gateType?: GateType;   // GateType.Token (default) or GateType.Collection
}

Notes

  • For token gates, amount specifies the minimum balance required (e.g., 100 means "must hold >= 100 tokens")
  • For collection gates, the user can present any NFT from that collection. amount is ignored (NFTs always have amount=1)
  • Omitting the gate parameter or passing undefined creates a public table with no restrictions

Encryption (Crypto)

The SDK includes a built-in encryption module (iqlabs.crypto) for encrypting data before storing it on-chain.

Three encryption modes

  • DH Encryption (single recipient): Ephemeral X25519 ECDH → HKDF-SHA256 → AES-256-GCM. Use when encrypting data for one specific recipient.
  • Password Encryption: PBKDF2-SHA256 (250k iterations) → AES-256-GCM. Use for password-protected data that anyone with the password can decrypt.
  • Multi-recipient Encryption (PGP-style hybrid): Generates a random content encryption key (CEK), encrypts data once, then wraps the CEK for each recipient via ECDH. Use when encrypting data for multiple recipients.

Key derivation

Users can derive a deterministic X25519 keypair from their wallet signature using deriveX25519Keypair(). This means users don't need to manage separate encryption keys — their wallet is the key.

Key related functions


Function Details

Data Storage and Retrieval

codeIn()

Parameters input: { connection, signer } object
data: data to upload (string or string[])
filename: optional filename (string)
method: upload method (number, default: 0)
filetype: file type hint (string, default: '')
onProgress: optional progress callback (percent: number) => void
Returns Transaction signature (string)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

// Upload data
const signature = await iqlabs.writer.codeIn(
  { connection, signer },
  'Hello, blockchain!'
);

// Upload with filename
const sig = await iqlabs.writer.codeIn(
  { connection, signer },
  'file contents here',
  'hello.txt'
);

readCodeIn()

Parameters txSignature: transaction signature (string)
speed: rate limit profile (optional, 'light' | 'medium' | 'heavy' | 'extreme')
onProgress: optional progress callback (percent: number) => void
Returns { metadata: string, data: string | null }

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

const result = await iqlabs.reader.readCodeIn('5Xg7...');
console.log(result.data);      // 'Hello, blockchain!'
console.log(result.metadata);  // JSON string with file metadata

Connection Management

requestConnection()

Parameters connection: Solana RPC Connection
signer: Signer
dbRootId: database ID (Uint8Array or string)
partyA: first user pubkey (string)
partyB: second user pubkey (string)
tableName: connection table name (string or Uint8Array)
columns: column list (Array<string | Uint8Array>)
idCol: ID column (string or Uint8Array)
extKeys: extension keys (Array<string | Uint8Array>)
Returns Transaction signature (string)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

await iqlabs.writer.requestConnection(
  connection, signer, 'my-db',
  myWalletAddress, friendWalletAddress,
  'dm_table', ['message', 'timestamp'], 'message_id', []
);

manageConnection()

Note: There is no high-level SDK wrapper for this function. Use the contract-level instruction builder directly.

Parameters builder: InstructionBuilder
accounts: { db_root, connection_table, signer } (PublicKey)
args: { db_root_id, connection_seed, new_status }
Returns TransactionInstruction

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

const builder = iqlabs.contract.createInstructionBuilder(iqlabs.contract.PROGRAM_ID);

// Approve a friend request
const approveIx = iqlabs.contract.manageConnectionInstruction(
  builder,
  { db_root, connection_table, signer: myPubkey },
  { db_root_id, connection_seed, new_status: iqlabs.contract.CONNECTION_STATUS_APPROVED }
);

// Block a user
const blockIx = iqlabs.contract.manageConnectionInstruction(
  builder,
  { db_root, connection_table, signer: myPubkey },
  { db_root_id, connection_seed, new_status: iqlabs.contract.CONNECTION_STATUS_BLOCKED }
);

readConnection()

Parameters dbRootId: database ID (Uint8Array or string)
partyA: first wallet (string)
partyB: second wallet (string)
Returns { status: 'pending' | 'approved' | 'blocked' | 'unknown', requester: 'a' | 'b', blocker: 'a' | 'b' | 'none' }

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

const { status, requester, blocker } = await iqlabs.reader.readConnection('my-db', partyA, partyB);
console.log(status); // 'pending' | 'approved' | 'blocked'

writeConnectionRow()

Parameters connection: Solana RPC Connection
signer: Signer
dbRootId: database ID (Uint8Array or string)
connectionSeed: connection seed (Uint8Array or string)
rowJson: JSON data (string)
Returns Transaction signature (string)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

await iqlabs.writer.writeConnectionRow(
  connection, signer, 'my-db', connectionSeed,
  JSON.stringify({ message_id: '123', message: 'Hello friend!', timestamp: Date.now() })
);

fetchUserConnections()

Fetch all connections (friend requests) for a user by analyzing their UserState PDA transaction history. Each connection includes its dbRootId, identifying which app the connection belongs to.

Parameters userPubkey: user public key (string or PublicKey)
options: optional settings
Options limit: max number of transactions to fetch
before: signature to paginate from
speed: rate limit profile ('light' | 'medium' | 'heavy' | 'extreme')
Returns Array of { dbRootId, connectionPda, partyA, partyB, status, requester, blocker, timestamp }

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

const connections = await iqlabs.reader.fetchUserConnections(myPubkey, {
  speed: 'light',
  limit: 100
});

// Filter by status
const pendingRequests = connections.filter(c => c.status === 'pending');
const friends = connections.filter(c => c.status === 'approved');
const blocked = connections.filter(c => c.status === 'blocked');

// Check connection details
connections.forEach(conn => {
  console.log(`${conn.partyA} <-> ${conn.partyB}, status: ${conn.status}`);
});

Table Management

createTable()

Parameters connection: Solana RPC Connection
signer: Signer
dbRootId: database ID (Uint8Array or string)
tableSeed: table seed (Uint8Array or string)
tableName: display name (string or Uint8Array)
columnNames: column names (Array<string | Uint8Array>)
idCol: ID column (string or Uint8Array)
extKeys: extension keys (Array<string | Uint8Array>)
gate: optional access gate (see Token & Collection Gating)
writers: optional writer whitelist (PublicKey[])
Returns Transaction signature (string)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

// No gate (public table)
await iqlabs.writer.createTable(
  connection, signer, 'my-db', 'users', 'Users Table',
  ['name', 'email'], 'user_id', []
);

// With token gate (must hold >= 100 tokens)
await iqlabs.writer.createTable(
  connection, signer, 'my-db', 'vip', 'VIP Table',
  ['name'], 'user_id', [],
  { mint: tokenMintPubkey, amount: 100, gateType: iqlabs.contract.GateType.Token }
);

// With NFT collection gate (must hold any NFT from the collection)
await iqlabs.writer.createTable(
  connection, signer, 'my-db', 'holders', 'Holder Table',
  ['name'], 'user_id', [],
  { mint: collectionPubkey, gateType: iqlabs.contract.GateType.Collection }
);

writeRow()

Parameters connection: Solana RPC Connection
signer: Signer
dbRootId: database ID (Uint8Array or string)
tableSeed: table name (Uint8Array or string)
rowJson: JSON row data (string)
skipConfirmation: skip tx confirmation (boolean, default: false)
Returns Transaction signature (string)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

// Write the first row to create the table
await iqlabs.writer.writeRow(connection, signer, 'my-db', 'users', JSON.stringify({
  id: 1, name: 'Alice', email: 'alice@example.com'
}));

// Add another row to the same table
await iqlabs.writer.writeRow(connection, signer, 'my-db', 'users', JSON.stringify({
  id: 2, name: 'Bob', email: 'bob@example.com'
}));

readTableRows()

Parameters account: table PDA (PublicKey or string)
options: optional settings
Options limit: max number of rows to fetch
before: signature cursor for pagination
signatures: pre-collected signature array (skips RPC fetch if provided)
speed: rate limit profile ('light', 'medium', 'heavy', 'extreme')
Returns Array<Record<string, unknown>>

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

// Basic usage
const rows = await iqlabs.reader.readTableRows(tablePda, { limit: 50 });

// Cursor-based pagination
const olderRows = await iqlabs.reader.readTableRows(tablePda, { limit: 50, before: 'sig...' });

// With pre-collected signatures (skips signature fetching, decodes directly)
const sigs = await iqlabs.reader.collectSignatures(tablePda);
const targetIdx = sigs.indexOf('abc123');
const slice = sigs.slice(targetIdx - 25, targetIdx + 25);
const rows = await iqlabs.reader.readTableRows(tablePda, { signatures: slice });

collectSignatures()

Collects all (or up to maxSignatures) transaction signatures for an account. Lightweight — no transaction decoding, only signature strings. Useful for pagination: fetch the full signature list once, then slice and pass to readTableRows().

Parameters account: table PDA (PublicKey or string)
maxSignatures: max number of signatures to collect (optional, fetches all if omitted)
Returns string[] (signature strings)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

// Collect all signatures
const allSigs = await iqlabs.reader.collectSignatures(tablePda);

// Collect up to 3000 signatures
const sigs = await iqlabs.reader.collectSignatures(tablePda, 3000);

// Use with readTableRows to read from the middle
const targetIdx = sigs.indexOf('abc123');
const chunk = sigs.slice(targetIdx - 25, targetIdx + 25);
const rows = await iqlabs.reader.readTableRows(tablePda, { signatures: chunk });

getTablelistFromRoot()

Parameters connection: Solana RPC Connection
dbRootId: database ID (Uint8Array or string)
Returns { rootPda: PublicKey, creator: string | null, tableSeeds: string[], globalTableSeeds: string[] }

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

const result = await iqlabs.reader.getTablelistFromRoot(connection, 'my-db');
console.log('Creator:', result.creator);
console.log('Table seeds:', result.tableSeeds);

fetchInventoryTransactions()

Parameters publicKey: user public key (PublicKey)
limit: max count (number)
before: pagination cursor (optional, string)
Returns Transaction array

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

const myFiles = await iqlabs.reader.fetchInventoryTransactions(myPubkey, 20);
myFiles.forEach(tx => {
  let metadata: { data?: unknown } | null = null;
  try {
    metadata = JSON.parse(tx.metadata);
  } catch {
    metadata = null;
  }

  if (metadata && metadata.data !== undefined) {
    const inlineData = typeof metadata.data === 'string'
      ? metadata.data
      : JSON.stringify(metadata.data);
    console.log(`Inline data: ${inlineData}`);
  } else {
    console.log(`Signature: ${tx.signature}`);
  }
});

Encryption

deriveX25519Keypair()

Derive a deterministic X25519 keypair from a wallet signature. The same wallet always produces the same keypair.

Parameters signMessage: wallet sign function (msg: Uint8Array) => Promise<Uint8Array>
Returns { privKey: Uint8Array, pubKey: Uint8Array }

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

const { privKey, pubKey } = await iqlabs.crypto.deriveX25519Keypair(
  wallet.signMessage
);

dhEncrypt()

Parameters recipientPubHex: recipient's X25519 public key (hex string)
plaintext: data to encrypt (Uint8Array)
Returns { senderPub: string, iv: string, ciphertext: string } (all hex)

dhDecrypt()

Parameters privKey: recipient's private key (Uint8Array)
senderPubHex: sender's public key from encrypt result (hex string)
ivHex: IV from encrypt result (hex string)
ciphertextHex: ciphertext from encrypt result (hex string)
Returns Uint8Array (decrypted plaintext)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

// Encrypt
const encrypted = await iqlabs.crypto.dhEncrypt(recipientPubHex, new TextEncoder().encode('secret'));

// Decrypt (recipient side)
const decrypted = await iqlabs.crypto.dhDecrypt(
  recipientPrivKey, encrypted.senderPub, encrypted.iv, encrypted.ciphertext
);

passwordEncrypt()

Parameters password: password string
plaintext: data to encrypt (Uint8Array)
Returns { salt: string, iv: string, ciphertext: string } (all hex)

passwordDecrypt()

Parameters password: password string
saltHex: salt from encrypt result (hex string)
ivHex: IV from encrypt result (hex string)
ciphertextHex: ciphertext from encrypt result (hex string)
Returns Uint8Array (decrypted plaintext)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

const encrypted = await iqlabs.crypto.passwordEncrypt('my-password', new TextEncoder().encode('secret'));
const decrypted = await iqlabs.crypto.passwordDecrypt(
  'my-password', encrypted.salt, encrypted.iv, encrypted.ciphertext
);

multiEncrypt()

Parameters recipientPubHexes: recipient public keys (string[])
plaintext: data to encrypt (Uint8Array)
Returns { recipients: RecipientEntry[], iv: string, ciphertext: string }

multiDecrypt()

Parameters privKey: your private key (Uint8Array)
pubKeyHex: your public key (hex string)
encrypted: the MultiEncryptResult object
Returns Uint8Array (decrypted plaintext)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

// Encrypt for multiple recipients
const encrypted = await iqlabs.crypto.multiEncrypt(
  [alicePubHex, bobPubHex, carolPubHex],
  new TextEncoder().encode('group secret')
);

// Each recipient decrypts with their own key
const plaintext = await iqlabs.crypto.multiDecrypt(alicePrivKey, alicePubHex, encrypted);

Environment Settings

setRpcUrl()

Parameters url: Solana RPC URL (string)
Returns void

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

iqlabs.setRpcUrl('https://your-rpc.example.com');

getRpcUrl()

Returns the currently configured RPC URL.

Parameter Type Description
Returns string The current RPC URL

Example:

const url = iqlabs.getRpcUrl();
console.log(url); // https://api.mainnet-beta.solana.com

Helius Optimization

When the RPC URL points to a Helius endpoint (helius-rpc.com), the SDK automatically uses getTransactionsForAddress (gTFA) for reading session files. This fetches 100 full transactions per call instead of individual getTransaction calls.

Result: Large file reads are ~100x faster (e.g. 580KB file: 468s → 4.6s).

No code changes needed — just set a Helius RPC URL:

iqlabs.setRpcUrl('https://mainnet.helius-rpc.com/?api-key=YOUR_KEY');

// readCodeIn automatically uses gTFA when available
const { data, metadata } = await iqlabs.reader.readCodeIn(txSignature);

Falls back to standard sequential reads on any non-Helius RPC. Requires a paid Helius plan for gTFA access.


User Metadata

updateUserMetadata()

Parameters connection: Solana RPC Connection
signer: Signer
dbRootId: database ID (Uint8Array or string)
meta: metadata to store (Uint8Array or string)
Returns Transaction signature (string)

Example:

import iqlabs from '@iqlabs-official/solana-sdk';

await iqlabs.writer.updateUserMetadata(
  connection, signer, 'my-db',
  JSON.stringify({ name: 'Alice', bio: 'gm' })
);

Advanced Functions

These functions are advanced/internal, so this doc lists them only. If you are looking for any of the following functions, please see our API docs (in progress).

  • manageRowData() (writer)
  • readUserState() (reader)
  • readInventoryMetadata() (reader)
  • readUserInventoryCodeInFromTx() (reader)
  • getSessionPdaList() (reader)
  • deriveDmSeed() (utils/reader)
  • toSeedBytes() (utils)
  • hexToBytes() / bytesToHex() / validatePubKey() (crypto)

Additional Resources

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors