SDK
ShainClient
Thin wrapper around @solana/web3.js that holds a Connection, a wallet, and a program id. Everything else is composable helpers.
Construct
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { ShainClient } from "@shain/sdk";
const client = new ShainClient({
connection: new Connection("https://api.devnet.solana.com", "confirmed"),
programId: new PublicKey("2T1Qs7f2hiy1sUQBWC7226xhXvCees97UfeqReRrnE66"),
wallet: Keypair.generate(), // or a wallet-adapter instance
commitment: "confirmed", // optional; default "confirmed"
});PDA helpers
| Method | Returns | Notes |
|---|---|---|
client.pdas(holder?) | PdaDerivationOutput | Config + treasury PDAs; session PDA if holder passed |
client.ata(owner, mint) | PublicKey | Associated Token Address |
client.walletPublicKey() | PublicKey | Resolves Keypair | WalletLike |
Fetchers
| Method | Returns | Notes |
|---|---|---|
fetchConfig() | Promise<ShainConfig | null> | Singleton config PDA |
fetchSession(holder?) | Promise<ShainSession | null> | Defaults to wallet.publicKey |
snapshotSession(holder?) | Promise<SessionSnapshot | null> | UI-ready projection |
predictExpiry() | Promise<number | null> | Reads config, returns now + duration |
Instruction builders
Every on-chain call has a build*Ix variant that returns a raw TransactionInstruction. Use these when you want to bundle Shain with other ixs (a DEX swap, an ATA create, etc.) in a single transaction.
| Method | Signature | When |
|---|---|---|
buildInitializeIx | (args) => TransactionInstruction | Deployment only |
buildStartSessionIx | ({shainMint, userTokenAccount}) => TransactionInstruction | Open a session |
buildGatedActionIx | ({tag?}) => TransactionInstruction | Gate any downstream call |
buildCloseSessionIx | ({user}) => TransactionInstruction | Post-expiry cleanup |
High-level helpers
Each builder has a one-shot counterpart that builds, signs and sends in one call:
const result = await client.startSession({
shainMint,
userTokenAccount: userAta,
});
// { signature, sessionPda, startedAt, expiresAt }
const hook = await client.gatedAction({ tag: 1n });
// { signature, tag, actionsCount }
const closed = await client.closeSession({ user: wallet.publicKey });
// { signature, refundedLamports }With wallet adapter
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { ShainClient } from "@shain/sdk";
import { Transaction } from "@solana/web3.js";
function useShain() {
const { connection } = useConnection();
const { publicKey, signTransaction } = useWallet();
return useMemo(() => {
if (!publicKey) return null;
return new ShainClient({
connection,
programId: DEFAULT_PROGRAM_ID,
wallet: { publicKey, signTransaction },
});
}, [connection, publicKey, signTransaction]);
}
async function openSession(client: ShainClient, mint: PublicKey, ata: PublicKey) {
const ix = client.buildStartSessionIx({
shainMint: mint,
userTokenAccount: ata,
});
const tx = new Transaction().add(ix);
tx.feePayer = client.walletPublicKey();
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
const signed = await signTransaction(tx);
return connection.sendRawTransaction(signed.serialize());
}