Wallets and signing
GraveMint accepts a small signer interface, so you can use your application's existing wallet library. The SDK itself does not require a chain SDK.
Transaction submission
Your wallet signs the transaction returned by prepare. Send those signed bytes to execute; GraveMint validates, submits and confirms the transaction.
Keep submission in this flow. A transactionHash is rejected with CLIENT_BROADCAST_NOT_ALLOWED. Signed bytes that change the prepared transaction's instructions or accounts are rejected with TX_MODIFIED.
The interface
import type { TransactionSigner } from '@solanadeads/gravemint';
// TransactionSigner accepts and returns base64-encoded transactions.
// signTransaction(base64Transaction: string): Promise<string>
// signAllTransactions?(base64Transactions: string[]): Promise<string[]>signAllTransactions is optional. When provided, the SDK can request approval for a batch together. Otherwise, it signs each transaction separately.
Solana wallet-adapter
Use this adapter inside a component or hook with a connected wallet. It supports versioned and legacy transactions. Browser builds also need a Buffer implementation, such as the buffer package.
import { Buffer } from 'buffer';
import { Transaction, VersionedTransaction } from '@solana/web3.js';
import { useWallet } from '@solana/wallet-adapter-react';
import type { TransactionSigner } from '@solanadeads/gravemint';
export function useMintSigner(): TransactionSigner {
const { signTransaction } = useWallet();
return {
async signTransaction(base64) {
if (!signTransaction) throw new Error('Connect a wallet that supports signing.');
const bytes = Buffer.from(base64, 'base64');
let transaction: Transaction | VersionedTransaction;
try {
transaction = VersionedTransaction.deserialize(bytes);
} catch {
transaction = Transaction.from(bytes);
}
const signed = await signTransaction(transaction);
const serialized = signed instanceof Transaction
? signed.serialize({ requireAllSignatures: false })
: signed.serialize();
return Buffer.from(serialized).toString('base64');
},
};
}Privy and embedded wallets
Adapt your provider's Solana signing method to the same base64 input/output interface. Use a sign-only method; the provider must return the signed transaction for GraveMint to submit.
Batch mints
A quantity above one uses several transactions and sessions. The SDK's mint() method coordinates them and returns per-transaction results. A partial batch can return without throwing, so inspect the results before reporting completion.
const result = await gm.mint.mint({ collectionId, phaseId, walletAddress, quantity, signer });
if (result.results) {
for (const transaction of result.results) {
if (transaction.pending) {
// Keep transaction.sessionId and check the wallet before retrying.
} else if (!transaction.success) {
// Handle transaction.errorCode and display transaction.error.
}
}
}For direct executeBatch() calls, success: true means at least one transaction succeeded. Read results, successfulTransactions and failedTransactions to determine the full outcome.
The full flow
For a single mint, the manual flow is:
const prepared = await gm.mint.prepare({ collectionId, phaseId, walletAddress, quantity: 1 });
const transaction = prepared.transactions?.[0]?.transaction;
const sessionId = prepared.sessions?.[0]?.sessionId;
if (!transaction || !sessionId) throw new Error('No transaction was prepared.');
const signedTransaction = await signer.signTransaction(transaction);
const result = await gm.mint.execute({ sessionId, signedTransaction });Preparation returns arrays even for a quantity of one. For larger quantities, sign each transaction and pair it with its corresponding session for executeBatch(), or use mint():
const result = await gm.mint.mint({ collectionId, phaseId, walletAddress, quantity: 1, signer });Sessions expire
Preparation reserves supply with a short-lived lock. Call it when the collector is ready to mint, rather than to obtain a price for page display. Use the prepared response's expiresInMs for the signing countdown.
A confirmed SESSION_EXPIRED response requires a new preparation. Keep expiry separate from an uncertain submission outcome: MintOutcomeUnknownError (OUTCOME_UNKNOWN) includes sessionIds for tracking a mint that may still complete. Retain those IDs, check the wallet and do not automatically mint again. Execute calls are not retried automatically by default.
Chains
The v1 mint flow supports Solana. CHAIN_NOT_SUPPORTED_BY_SURFACE identifies a collection outside that flow; CHAIN_DISABLED identifies a disabled chain. Use capabilities.supportedBySurface before preparation and offer capabilities.mintUrl when available.
