Examples

Learn by example: server-side creation, client validation, wallet integration.

Server-Side Creation

Create intent manifests on your server and serve them to clients. Use the HTTP helpers package for proper headers and status endpoints.

server.tstypescript
1{{COMMENT:// Node.js server creating an intent}}
2{{KEYWORD:import}} express {{KEYWORD:from}} {{STRING:"express"}};
3{{KEYWORD:import}} { createIntent, SOL_MINT } {{KEYWORD:from}} {{STRING:"@intentrail/sdk"}};
4{{KEYWORD:import}} { createExpressHandler } {{KEYWORD:from}} {{STRING:"@intentrail/http"}};
5
6{{KEYWORD:const}} app = express();
7{{KEYWORD:const}} intents = {{KEYWORD:new}} Map();
8
9{{COMMENT:// Create intent endpoint}}
10app.post({{STRING:"/api/intents"}}, express.json(), (req, res) => {
11 {{KEYWORD:const}} { walletPubkey, action, amount } = req.body;
12
13 {{KEYWORD:const}} intent = createIntent({
14 expires_at: {{KEYWORD:new}} Date(Date.now() + 15 * 60 * 1000).toISOString(),
15 network: {{STRING:"mainnet-beta"}},
16 action,
17 actor: { wallet_pubkey: walletPubkey },
18 constraints: {
19 max_spend: [{ mint: SOL_MINT, amount }],
20 min_receive: [],
21 allowed_programs: [],
22 forbidden_accounts: [],
23 },
24 preconditions: {
25 required_accounts: [],
26 token_accounts: [],
27 blockhash_ttl_seconds: 60,
28 },
29 metadata: {
30 dapp: { name: {{STRING:"My dApp"}}, url: {{STRING:"https:{{COMMENT://mydapp.com"}} },}}
31 human_summary: {{STRING:`${action} ${amount} lamports`}},
32 },
33 });
34
35 intents.set(intent.intent_id, intent);
36 res.json(intent);
37});
38
39{{COMMENT:// Serve intents with proper headers}}
40app.get({{STRING:"/api/intents/:id"}}, createExpressHandler({
41 getIntent: {{KEYWORD:async}} (id) => intents.get(id) || null,
42}));
43
44app.listen(3001);

Client-Side Validation

Fetch intents from a URL, verify they're valid, and generate a user-friendly summary for display in your UI or wallet.

client.tstypescript
1{{COMMENT:// Client-side intent validation and display}}
2{{KEYWORD:import}} { fetchIntent, verifyIntent, summarizeIntent, formatSummaryText } {{KEYWORD:from}} {{STRING:"@intentrail/sdk"}};
3
4{{KEYWORD:async}} {{KEYWORD:function}} handleIntent(intentUrl: string) {
5 {{COMMENT:// Fetch and validate}}
6 {{KEYWORD:const}} intent = {{KEYWORD:await}} fetchIntent(intentUrl);
7
8 {{COMMENT:// Verify (checks expiration, signatures {{KEYWORD:if}} present)}}
9 {{KEYWORD:const}} result = {{KEYWORD:await}} verifyIntent(intent, { skipSignatures: true });
10 {{KEYWORD:if}} (!result.ok) {
11 console.error({{STRING:"Invalid intent:"}}, result.errors);
12 {{KEYWORD:return}};
13 }
14
15 {{COMMENT:// Generate wallet-friendly summary}}
16 {{KEYWORD:const}} summary = summarizeIntent(intent);
17
18 {{COMMENT:// Display to user}}
19 console.log(formatSummaryText(summary));
20 {{COMMENT:// Output:}}
21 {{COMMENT:// 📋 Swap via Jupiter}}
22 {{COMMENT:// Swap 1 SOL {{KEYWORD:for}} at least 95 USDC}}
23 {{COMMENT://}}
24 {{COMMENT:// • Spend up to 1 SOL}}
25 {{COMMENT:// • Receive at least 95 USDC}}
26 {{COMMENT:// • Network: mainnet-beta}}
27 {{COMMENT://}}
28 {{COMMENT:// ℹ️ Unsigned intent - will require signature}}
29 {{COMMENT://}}
30 {{COMMENT:// ⏰ Expires: 1/15/2024, 10:45:00 AM}}
31
32 {{COMMENT:// Check {{KEYWORD:for}} risk flags}}
33 {{KEYWORD:for}} ({{KEYWORD:const}} flag of summary.riskFlags) {
34 {{KEYWORD:if}} (flag.level === {{STRING:"danger"}}) {
35 console.warn({{STRING:"⚠️"}}, flag.message);
36 }
37 }
38}

Wallet Integration

Sign intents using Solana wallet adapters. The SDK works with any wallet that supports message signing (signMessage).

wallet.tstypescript
1{{COMMENT:// Wallet integration: sign and verify}}
2{{KEYWORD:import}} { signIntent, verifyIntent, hasSignatureFrom } {{KEYWORD:from}} {{STRING:"@intentrail/sdk"}};
3
4{{KEYWORD:async}} {{KEYWORD:function}} signAndSubmit(intent, wallet) {
5 {{COMMENT:// Sign the intent}}
6 {{KEYWORD:const}} signed = {{KEYWORD:await}} signIntent(intent, {
7 publicKey: wallet.publicKey.toBase58(),
8 sign: (message) => wallet.signMessage(message),
9 });
10
11 {{COMMENT:// Verify our signature was added}}
12 {{KEYWORD:const}} hasSig = hasSignatureFrom(signed, wallet.publicKey.toBase58());
13 console.log({{STRING:"Signed by wallet:"}}, hasSig); {{COMMENT:// true}}
14
15 {{COMMENT:// Full verification}}
16 {{KEYWORD:const}} result = {{KEYWORD:await}} verifyIntent(signed, {
17 requiredSigners: [wallet.publicKey.toBase58()],
18 });
19
20 {{KEYWORD:if}} (result.ok) {
21 {{COMMENT:// Submit to transaction builder}}
22 {{KEYWORD:await}} submitToBuilder(signed);
23 }
24}

Constraint Enforcement

After executing a transaction, verify that the intent constraints were satisfied. Check max spend, min receive, and calculate slippage.

constraints.tstypescript
1{{COMMENT:// Enforce constraints after execution}}
2{{KEYWORD:import}} { enforceConstraints, calculateSlippage } {{KEYWORD:from}} {{STRING:"@intentrail/sdk"}};
3
4{{KEYWORD:async}} {{KEYWORD:function}} verifyExecution(intent, connection) {
5 {{COMMENT:// Get balances before and after}}
6 {{KEYWORD:const}} balancesBefore = {{KEYWORD:await}} getBalances(connection, intent.actor.wallet_pubkey);
7
8 {{COMMENT:// ... execute transaction ...}}
9
10 {{KEYWORD:const}} balancesAfter = {{KEYWORD:await}} getBalances(connection, intent.actor.wallet_pubkey);
11
12 {{COMMENT:// Check constraints}}
13 {{KEYWORD:const}} result = enforceConstraints(intent, {
14 balancesBefore,
15 balancesAfter,
16 accounts: [],
17 });
18
19 {{KEYWORD:if}} (!result.ok) {
20 {{KEYWORD:for}} ({{KEYWORD:const}} violation of result.violations) {
21 console.error({{STRING:`Constraint violated: ${violation.constraint}`}});
22 console.error({{STRING:` Expected: ${violation.expected}`}});
23 console.error({{STRING:` Actual: ${violation.actual}`}});
24 }
25 {{COMMENT:// Handle violation (e.g., revert, alert user)}}
26 }
27
28 {{COMMENT:// Check slippage}}
29 {{KEYWORD:const}} minReceive = intent.constraints.min_receive[0];
30 {{KEYWORD:const}} actualReceived = balancesAfter.find(b => b.mint === minReceive.mint)?.balance || {{STRING:"0"}};
31 {{KEYWORD:const}} slippage = calculateSlippage(minReceive.amount, actualReceived);
32 console.log({{STRING:`Slippage: ${(slippage * 100).toFixed(2)}%`}});
33}

Run the Examples

The monorepo includes runnable example applications:

# Clone and install
git clone https://github.com/intentrail/intentrail.git
cd intentrail && pnpm install
# Run all examples
pnpm dev
# Run specific example
pnpm --filter node-demo dev
pnpm --filter web-demo dev