Skip to main content

Overview

Transactions in Agentic Wallet follow a complete lifecycle from creation through confirmation. All transactions are created via intents - high-level instructions that the platform translates into protocol-specific on-chain operations.

Transaction Lifecycle

Every transaction moves through these states:
1

pending

Transaction created and queued for processing
2

simulating

Transaction simulated on-chain to estimate costs and catch errors
3

policy_eval

Policy engine evaluates rules (spending limits, allowlists, etc.)
4

approval_gate

Transaction paused for manual approval (if required by policy)
5

signing

Wallet engine signs the transaction
6

submitting

Transaction submitted to Solana network
7

confirmed | failed

Final state after on-chain confirmation or failure

Creating Transactions

Basic Transfer (SOL)

npm run cli -- tx create \
  --wallet-id <walletId> \
  --type transfer_sol \
  --protocol system-program \
  --intent '{"destination":"<pubkey>","lamports":1000000}'

SPL Token Transfer

{
  "walletId": "<walletId>",
  "type": "transfer_spl",
  "protocol": "spl-token",
  "intent": {
    "destination": "<destination-pubkey>",
    "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000"
  }
}

Token Swap

{
  "walletId": "<walletId>",
  "type": "swap",
  "protocol": "jupiter",
  "intent": {
    "inputMint": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000",
    "slippageBps": 50
  }
}

Intent Structure

All transactions require these fields:
FieldTypeRequiredDescription
walletIdUUIDYesWallet performing the transaction
typestringYesTransaction type (see supported types below)
protocolstringYesProtocol adapter to use
intentobjectYesProtocol-specific intent payload
agentIdUUIDNoAgent executing this transaction
gaslessbooleanNoUse gasless transaction (if supported)
idempotencyKeystringNoPrevent duplicate executions

Supported Transaction Types

  • transfer_sol - Transfer native SOL
  • transfer_spl - Transfer SPL tokens
  • x402_pay - HTTP 402 payment flow
  • swap - Token swaps (Jupiter, Orca, Raydium)
  • stake - Stake SOL (Marinade)
  • unstake - Unstake SOL
  • lend_supply - Supply assets to lending (Solend)
  • lend_borrow - Borrow assets from lending
  • create_mint - Create new SPL token mint
  • mint_token - Mint tokens to address
  • create_escrow - Create new escrow
  • accept_escrow - Accept escrow as counterparty
  • release_escrow - Release funds to recipient
  • refund_escrow - Refund to creator
  • dispute_escrow - Initiate dispute
  • resolve_dispute - Resolve dispute
  • create_milestone_escrow - Multi-milestone escrow
  • release_milestone - Release specific milestone
  • query_balance - Check wallet balance
  • query_positions - Get DeFi positions
  • flash_loan_bundle - Flash loan operations
  • cpi_call - Cross-program invocation
  • custom_instruction_bundle - Custom instruction set
  • treasury_allocate - Treasury allocation
  • treasury_rebalance - Treasury rebalancing
  • paper_trade - Paper trading (simulation)

Polling for Confirmation

Transactions are processed asynchronously. Poll the transaction status:
npm run cli -- tx get <txId>
Response Structure:
{
  "status": "success",
  "data": {
    "id": "tx-uuid",
    "walletId": "wallet-uuid",
    "type": "transfer_sol",
    "protocol": "system-program",
    "status": "confirmed",
    "signature": "5j7s...",
    "intent": { ... },
    "createdAt": "2026-03-08T12:00:00.000Z",
    "confirmedAt": "2026-03-08T12:00:05.000Z"
  }
}

Idempotency Keys

Prevent duplicate transaction execution with idempotency keys:
const tx = await client.transaction.create({
  walletId: walletId,
  type: 'transfer_sol',
  protocol: 'system-program',
  idempotencyKey: 'payment-invoice-12345',
  intent: {
    destination: destinationPubkey,
    lamports: 1_000_000
  }
});
If you submit the same idempotencyKey again, the API returns the original transaction instead of creating a duplicate.

Approval Gate Workflow

If a policy requires approval, the transaction pauses at approval_gate:
1

Transaction Paused

Transaction reaches approval_gate status and waits for operator action.
2

Review Transaction

Retrieve pending approvals:
npm run cli -- tx pending --wallet-id <walletId>
3

Approve or Reject

npm run cli -- tx approve <txId>
# Or via API:
curl -X POST -H "x-api-key: dev-api-key" \
  http://localhost:3000/api/v1/transactions/<txId>/approve
4

Transaction Continues

After approval, transaction proceeds to signingsubmittingconfirmed.

Transaction Proofs

Every transaction generates cryptographic proof artifacts:
npm run cli -- tx proof <txId>
Response:
{
  "intentHash": "sha256-hash-of-intent",
  "policyHash": "sha256-hash-of-policy-eval",
  "simulationHash": "sha256-hash-of-simulation",
  "proofHash": "combined-proof-hash",
  "signature": "on-chain-signature",
  "timestamp": "2026-03-08T12:00:00.000Z"
}

Replay Data

Get full execution replay for auditing:
npm run cli -- tx replay <txId>
Returns complete transaction history including all state transitions and policy decisions.

Gasless Transactions

Enable gasless execution for supported protocols:
const tx = await client.transaction.create({
  walletId: walletId,
  type: 'swap',
  protocol: 'jupiter',
  gasless: true, // Route through Kora RPC
  intent: { ... }
});
Gasless execution requires KORA_RPC_URL configured and protocol must have gaslessEligible: true in risk config.

Real Examples from Source

From scripts/devnet-smoke.ts

import 'dotenv/config';
import { Connection, Keypair, PublicKey, SystemProgram, Transaction } from '@solana/web3.js';

const apiBase = 'http://localhost:3000';
const apiKey = 'dev-api-key';

// Create wallet
const createRes = await fetch(`${apiBase}/api/v1/wallets`, {
  method: 'POST',
  headers: { 'content-type': 'application/json', 'x-api-key': apiKey },
  body: JSON.stringify({ label: 'smoke-wallet' })
});

const wallet = await createRes.json();

// Execute transfer
const transferRes = await fetch(`${apiBase}/api/v1/transactions`, {
  method: 'POST',
  headers: { 'content-type': 'application/json', 'x-api-key': apiKey },
  body: JSON.stringify({
    walletId: wallet.data.id,
    type: 'transfer_sol',
    protocol: 'system-program',
    gasless: false,
    intent: {
      destination: destinationPubkey,
      lamports: 1_000_000
    }
  })
});

const tx = await transferRes.json();
console.log(`Transaction status: ${tx.data.status}`);

Next Steps

Setting Policies

Add spending limits and security rules to your transactions

Protocol Interactions

Execute DeFi operations across Jupiter, Marinade, Solend, and more

Build docs developers (and LLMs) love