Quick Start
Add 2FA to your Solana dApp in 5 minutes. No program changes required.
Step 1: Install the SDK
npm install intentguard-sdk @solana/web3.js
Step 2: Compute the Intent Hash
The intent hash is a SHA-256 digest of the action name and parameters. Both the mobile app and the dApp must compute the same hash for verification to succeed.
import { computeIntentHash } from 'intentguard-sdk';
// Hash the user's intended action
const hash = computeIntentHash('swap', {
inputMint: 'So11111111111111111111111111111111111111112',
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
amount: 1_000_000_000, // 1 SOL in lamports
slippage: 50, // 0.5% in bps
});
Important: The hash uses length-prefixed encoding to prevent concatenation ambiguity. Always use computeIntentHash() rather than manual hashing.
Step 3: Commit Intent (Mobile/Trusted Device)
On the trusted device (mobile app), the user confirms the action and commits the intent hash on-chain.
import { createCommitIntentInstruction } from 'intentguard-sdk';
import { Connection, Transaction } from '@solana/web3.js';
const connection = new Connection('https://api.devnet.solana.com');
const appId = new PublicKey('JUP6...'); // Target dApp program ID
const commitIx = createCommitIntentInstruction(
user.publicKey, // wallet
appId, // app identifier
hash, // intent hash
300, // TTL in seconds (5 min)
);
const tx = new Transaction().add(commitIx);
await sendAndConfirmTransaction(connection, tx, [user]);
Step 4: Verify + Execute (Browser/dApp)
The dApp detects the on-chain commit and prepends a verify instruction to the actual transaction.
import {
createVerifyIntentInstruction,
getIntentCommit,
} from 'intentguard-sdk';
// Check if intent has been committed
const commit = await getIntentCommit(connection, user.publicKey, appId);
if (!commit) throw new Error('No pending intent');
// Build verify instruction
const verifyIx = createVerifyIntentInstruction(user.publicKey, appId, hash);
// Build your normal swap/transfer instruction
const swapIx = buildSwapInstruction(params);
// Send atomically: verify MUST succeed for swap to execute
const tx = new Transaction().add(verifyIx).add(swapIx);
await sendAndConfirmTransaction(connection, tx, [user]);
Step 5: Handle Expiry & Revocation
If the user decides not to proceed, they can revoke the intent to reclaim rent:
import { createRevokeIntentInstruction } from 'intentguard-sdk';
const revokeIx = createRevokeIntentInstruction(user.publicKey, appId);
const tx = new Transaction().add(revokeIx);
await sendAndConfirmTransaction(connection, tx, [user]);
Expired intents (past TTL) will also fail verification automatically.
What Happens Under the Hood
| Step | Instruction | Accounts | Effect |
|---|---|---|---|
| Commit | commit_intent | 4 (intent PDA, config, user, system) | Creates IntentCommit PDA with hash + TTL |
| Verify | verify_intent | 4 (intent PDA, config, user, system) | Checks hash match, closes PDA, collects fee |
| Revoke | revoke_intent | 2 (intent PDA, user) | Closes PDA, refunds rent to user |
Next: SDK Reference for all available functions and parameters.