Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

selcuk07/intentguard

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IntentGuard

CI npm crates.io License: MIT

Solana 2FA — Cryptographic intent verification for every transaction.

IntentGuard is an on-chain protocol that adds two-factor authentication to Solana transactions. Before executing any action through a dApp (browser), users first confirm their intent from a separate trusted device (mobile app, CLI, or hardware wallet). If the dApp is compromised and tries to alter transaction parameters, the on-chain hash verification fails and the transaction reverts.

The Problem

Solana transactions today have a single point of failure: the frontend.

  • A compromised dApp can show "Swap 10 USDC" while actually signing "Swap 10,000 USDC"
  • Wallet simulation helps, but if the frontend is hijacked, the simulation data can be spoofed too
  • Hardware wallets display raw hex — humans can't verify transaction parameters on a Ledger screen
  • Once you click "Approve", there's no going back

One compromised frontend = drained wallet.

The Solution

IntentGuard introduces a commit-reveal pattern with device separation:

+--------------------+                 +--------------------+
|   Trusted Device   |                 |    Browser/dApp    |
|  (Mobile / CLI)    |                 |   (Untrusted)      |
+--------------------+                 +--------------------+
|                    |                 |                    |
|  1. User sees:     |                 |                    |
|     "Swap 100 USDC |                 |                    |
|      for SOL on    |                 |                    |
|      Jupiter"      |                 |                    |
|                    |                 |                    |
|  2. Confirms ->    |                 |                    |
|     TX1: commit    |---- hash ---->  |  3. Detects commit |
|     intent hash    |   on-chain      |     on-chain       |
|                    |                 |                    |
|                    |                 |  4. Executes TX2:  |
|                    |                 |     swap + verify  |
|                    |                 |     intent         |
|                    |                 |                    |
|                    |                 |  Hash matches ->   |
|                    |                 |     TX succeeds    |
|                    |                 |                    |
|                    |                 |  Hash mismatch ->  |
|                    |                 |     TX reverts     |
+--------------------+                 +--------------------+

Even if the browser is fully compromised after step 2, the attacker cannot change the transaction parameters. The hash is already locked on-chain from the trusted device.

How It Works

1. Commit (Trusted Device -> On-chain)

User confirms intent parameters on their mobile app or CLI. The app computes a SHA-256 hash and sends a commit_intent transaction to Solana.

import { computeIntentHash } from 'intentguard-sdk';

// Hash whatever parameters the target dApp needs
const hash = computeIntentHash([
  jupiterProgramId.toBuffer(),
  userWallet.toBuffer(),
  inputMint.toBuffer(),
  outputMint.toBuffer(),
  amountIn.toArrayLike(Buffer, 'le', 8),
  minAmountOut.toArrayLike(Buffer, 'le', 8),
]);

// Send commit TX from trusted device
await program.methods
  .commitIntent(jupiterProgramId, hash, new BN(300)) // 5 min TTL
  .accounts({ ... })
  .rpc();

2. Verify (Browser -> On-chain)

The dApp detects the on-chain IntentCommit PDA and includes a verify_intent call in the same transaction as the target action. IntentGuard checks the hash and closes the PDA.

// Browser detects commit exists, adds verify instruction
await program.methods
  .verifyIntent(hash)
  .accounts({ ... })
  .rpc();

// If hash matches -> PDA closed, rent refunded, dApp proceeds
// If hash doesn't match -> TX reverts, funds are safe

3. Revoke (Optional)

User changed their mind? Revoke the commit from any device.

await program.methods
  .revokeIntent(appId)
  .accounts({ ... })
  .rpc();

Architecture

On-chain Program (~530 lines Rust)

Instruction Description
initialize One-time protocol setup (admin config)
commit_intent Lock intent hash on-chain (TX1 from trusted device)
verify_intent Verify hash match and close PDA (TX2 from dApp)
revoke_intent Cancel pending intent, refund rent
pause_protocol Admin: block new commits (emergency)
unpause_protocol Admin: resume commits
transfer_admin Admin: change authority
update_config Admin: tune spam protection (min_balance)
migrate_config Admin: safe realloc for config PDA upgrades

PDA Structure

IntentCommitseeds: [b"intent", user, app_id]

One active intent per user per app. Automatically closed on verification.

Field Type Description
user Pubkey Wallet that committed
app_id Pubkey Target program identifier
intent_hash [u8; 32] SHA-256 of intent parameters
committed_at i64 When committed
expires_at i64 When it expires
bump u8 PDA bump

GuardConfigseeds: [b"config"]

Global protocol state with admin controls, lifetime counters, and spam protection settings.

Field Type Description
admin Pubkey Protocol authority
is_paused bool Emergency pause flag
total_commits u64 Lifetime commit counter
total_verifies u64 Lifetime verify counter
min_balance u64 Minimum SOL balance to commit (spam protection)
bump u8 PDA bump

Security Properties

Attack Protection
Frontend compromise (after commit) Hash is locked on-chain — changing params breaks the hash
Replay attack PDA is closed after verification — can't reuse
Stale intent TTL enforced (30s-1h, default 5min)
Cross-app attack Per-app PDA isolation — Jupiter intent can't verify on Raydium
Account theft has_one = user constraint — only owner can verify/revoke
Spam / dust attacks Configurable min_balance (default 0.01 SOL), admin-tunable up to 1 SOL
Protocol compromise Emergency pause, admin transfer, rate limiting (1 intent per user per app)

Devnet Deployment

IntentGuard is live on Solana devnet:

Resource Address
Program 4etWfDJNHhjYdv7fuGe236GDPguwUXVk9WhbEpQsPix7
IDL Dvn2qXEn4cvPW4fGEwjJ723gcvSdfooS2AVyqmyZxRKW
Config PDA 6atm7ijvFwoRnDsJKz6yaYbKBMBuqvTXqHTtbNUieKCj

Integration Guide

Any Solana program can integrate IntentGuard in two ways:

Option A: Separate Verify Instruction

Add verify_intent as a separate instruction in the same transaction. No changes to your program needed.

const tx = new Transaction();
tx.add(intentGuardVerifyIx);  // Verify intent hash
tx.add(yourDappSwapIx);        // Your actual instruction
await sendTransaction(tx);

Option B: CPI Verification

Call IntentGuard via CPI from within your program for tighter integration.

use intentguard_cpi::{verify_intent_cpi, VerifyAccounts};

// In your program's instruction handler:
verify_intent_cpi(accounts, intent_hash)?;
// If we reach here, intent was verified
proceed_with_swap(...)?;

Hash Format

IntentGuard is hash-format agnostic. You define what goes into the hash based on your dApp's needs:

SHA-256(program_id + user + param1 + param2 + ...)

The only requirement: both the commit side (mobile/CLI) and verify side (browser) must compute the same hash from the same parameters.

Project Structure

intentguard/
├── programs/intent-guard/       # Anchor program (9 instructions, ~530 lines)
│   └── src/
│       ├── lib.rs               # Program entrypoint
│       ├── state.rs             # IntentCommit, GuardConfig
│       ├── errors.rs            # Error codes
│       └── instructions/        # Instruction handlers
│           ├── initialize.rs    # Protocol setup
│           ├── commit_intent.rs # Lock intent hash
│           ├── verify_intent.rs # Verify + close PDA
│           ├── revoke_intent.rs # Cancel intent
│           └── admin.rs         # Pause, unpause, transfer, config
├── packages/
│   ├── sdk/                     # TypeScript SDK (npm: intentguard-sdk)
│   │   └── src/
│   │       ├── client.ts        # computeIntentHash, getIntentCommit
│   │       ├── instructions.ts  # Instruction builders (no Anchor dep)
│   │       ├── pdas.ts          # PDA derivation helpers
│   │       ├── constants.ts     # Program ID, defaults
│   │       └── react.tsx        # <IntentGuardButton /> component
│   └── cpi/                     # Rust CPI crate (crates.io: intentguard-cpi)
│       └── src/lib.rs           # CPI helpers + PDA finders
├── cli/                         # CLI tool (commit, status, revoke)
│   └── src/commands/
├── app/                         # React Native mobile app (Expo)
│   └── src/
│       ├── screens/             # Scan, Confirm, Home
│       └── utils/
├── extension/                   # Chrome extension (Manifest V3)
│   └── src/                     # Popup, content script, background
├── examples/                    # Integration examples
│   ├── full-flow.ts             # Commit -> verify -> close
│   ├── protected-swap.ts        # Jupiter swap with IntentGuard
│   ├── protected-transfer.ts    # SPL token transfer with IntentGuard
│   └── cpi-integration.rs       # Rust CPI example
├── landing/                     # GitHub Pages site
│   ├── index.html               # Landing page
│   ├── dashboard.html           # Live devnet stats dashboard
│   └── api-docs/                # TypeDoc API reference
├── tests/
│   └── intent-guard.ts          # 29 integration tests
├── trident-tests/               # Trident fuzzing (8 flows, ~1M instructions)
│   └── fuzz_0/test_fuzz.rs
├── scripts/
│   └── devnet-demo.ts           # Live devnet demo
├── THREAT-MODEL.md              # 12 attack vectors analyzed
├── SECURITY.md                  # Bug bounty policy (up to $50K)
├── GRANT-APPLICATION.md         # Solana grant application
└── Anchor.toml

CLI — Ledger Hardware Wallet

The CLI supports signing with a Ledger hardware wallet via --ledger:

# Commit intent using Ledger
intentguard commit \
  --ledger \
  --app JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 \
  --action swap \
  --params '{"inputMint":"EPjFWdd5...","amount":"1000000"}' \
  --cluster devnet

# Check status
intentguard status --ledger --app JUP6LkbZ...

# Revoke
intentguard revoke --ledger --app JUP6LkbZ...

# Custom derivation path (default: 44'/501'/0'/0')
intentguard commit --ledger --derivation-path "44'/501'/1'/0'" ...

Requirements: Ledger device connected via USB with the Solana app open.

Development

Prerequisites

  • Rust 1.75+
  • Solana CLI 2.x
  • Anchor CLI 0.32.1
  • Node.js 20+

Build

# Build the program (requires WSL on Windows for BPF compilation)
anchor build

# Build with dev-testing feature (relaxed TTL + min_balance for tests)
anchor build -- --features dev-testing

Test

# Run all tests (29 tests)
anchor test

# Skip build if already compiled
anchor test --skip-build

# Run fuzz tests (requires nightly Rust)
cd trident-tests && cargo +nightly run --bin fuzz_0

Dependency Pins

Platform-tools ships rustc 1.79.0. The following pins are required:

cargo update -p indexmap --precise 2.11.4
cargo update -p proc-macro-crate@3.5.0 --precise 3.2.0

SDK

TypeScript SDK

npm install intentguard-sdk
import {
  computeIntentHash,
  getIntentCommit,
  findIntentCommitPda,
  findConfigPda,
  INTENT_GUARD_PROGRAM_ID,
  // Instruction builders (no Anchor dependency)
  createCommitIntentInstruction,
  createVerifyIntentInstruction,
  createRevokeIntentInstruction,
  createPauseProtocolInstruction,
  createUnpauseProtocolInstruction,
  createTransferAdminInstruction,
} from 'intentguard-sdk';

// React component
import { IntentGuardButton } from 'intentguard-sdk/react';

Rust CPI Crate

[dependencies]
intentguard-cpi = "0.2"
use intentguard_cpi::{
    commit_intent_cpi, verify_intent_cpi, revoke_intent_cpi,
    pause_protocol_cpi, unpause_protocol_cpi, transfer_admin_cpi,
    find_intent_commit_pda, find_config_pda,
};

Security

IntentGuard takes security seriously. See SECURITY.md for our bug bounty policy.

  • Threat model: 12 attack vectors analyzed — THREAT-MODEL.md
  • Fuzzing: Trident — 8 flows, 5K iterations, ~1M instructions, 0 violations
  • Tests: 29 integration tests covering all instructions and attack vectors
  • Admin controls: Emergency pause, admin transfer, configurable spam protection
  • Spam protection: Configurable min_balance (0.01 SOL default, max 1 SOL)
  • Rate limiting: 1 active intent per user per app (PDA init constraint)
  • Bug bounty: Up to $50K for critical vulnerabilities

Report vulnerabilities to security@intentguard.dev.

Live Dashboard

Real-time protocol stats are available at the IntentGuard Dashboard:

  • Total commits and verifies
  • Verify rate
  • Protocol pause status
  • Intent lookup by wallet

Roadmap

  • On-chain program (9 instructions, ~530 lines)
  • TypeScript SDK v0.2.0 (npm: intentguard-sdk)
  • Rust CPI crate v0.2.0 (crates.io: intentguard-cpi)
  • CLI commit tool
  • React Native mobile app (Expo)
  • Chrome browser extension
  • React <IntentGuardButton /> component
  • Devnet deployment + live demo
  • Test suite (29 tests + Trident fuzzing)
  • Threat model (12 attack vectors)
  • Bug bounty program (up to $50K)
  • Live dashboard + API docs
  • First integration: ACELaunch (IntentProof)
  • External audit
  • Mainnet launch

Why "2FA"?

The same principle as Google Authenticator:

Traditional 2FA IntentGuard
What Login confirmation Transaction confirmation
Where Separate device Separate device
How TOTP code On-chain hash commit
Protects against Password theft Frontend compromise
Verification Server checks code Program checks hash

The key insight: your browser is your password, your mobile is your authenticator.

License

MIT

About

IntentGuard — Solana 2FA protocol. Commit-reveal intent verification with device separation.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Morty Proxy This is a proxified and sanitized view of the page, visit original site.