IntentVM Developer Guide
IntentVM is Vexidus's declarative transaction engine. Instead of building low-level operations manually, developers describe what they want and the engine figures out the optimal execution path.
Quick Start
Using the Rust SDK
use vexidus_sdk::{IntentBuilder, parse_intent};
use vexidus_types::primitives::{Address, Amount, Timestamp};
// Option 1: Fluent builder
let (goal, constraints) = IntentBuilder::new()
.stake(Amount::from_vxs(1000), None)
.with_slippage(1)
.build()
.unwrap();
// Option 2: Natural language
let parsed = parse_intent("stake 1000 VXS").unwrap();
// Serialize for RPC submission
let json = IntentBuilder::new()
.swap(Address::ZERO, usdc_addr, Amount::from_vxs(100))
.to_json()
.unwrap();
Outcome-Based Intents (Builder API)
use vexidus_sdk::IntentBuilder;
// Acquire: "get me 10 SOL, max 200 USDC"
let (goal, constraints) = IntentBuilder::new()
.acquire("SOL", 10.0)
.with_max_cost("USDC", 200.0)
.build()
.unwrap();
// Liquidate: "sell everything for USDC, keep my VXS"
let (goal, constraints) = IntentBuilder::new()
.liquidate("USDC", 500.0)
.exclude(&["VXS"])
.build()
.unwrap();
// Rebalance portfolio
let (goal, constraints) = IntentBuilder::new()
.rebalance(&[("VXS", 50), ("ETH", 30), ("USDC", 20)])
.build()
.unwrap();
Using RPC Directly
# Submit an intent (natural language)
curl -s https://testnet.vexidus.io \
-d '{"jsonrpc":"2.0","method":"vex_submitIntent","params":["swap 100 VXS for USDC","SENDER_ADDRESS"],"id":1}' | jq .
# Preview for wallet confirmation (human-readable)
curl -s https://testnet.vexidus.io \
-d '{"jsonrpc":"2.0","method":"vex_previewIntent","params":["swap 100 USDC for VXS","SENDER_ADDRESS"],"id":1}' | jq .
# Simulate execution (detailed dry-run)
curl -s https://testnet.vexidus.io \
-d '{"jsonrpc":"2.0","method":"vex_simulateIntent","params":["swap 100 USDC for VXS","SENDER_ADDRESS"],"id":1}' | jq .
# Get price quote
curl -s https://testnet.vexidus.io \
-d '{"jsonrpc":"2.0","method":"vex_getPrice","params":["USDC","VXS"],"id":1}' | jq .
# Check intent status
curl -s https://testnet.vexidus.io \
-d '{"jsonrpc":"2.0","method":"vex_getIntentStatus","params":["VxhBUNDLE_HASH"],"id":1}' | jq .
Wallet Integration (Confirm-Before-Submit)
Wallets should follow a two-step flow for intent submission:
Step 1: Preview -- Call vex_previewIntent to get a human-readable confirmation:
{
"summary": "Swap 100 USDC -> ~1985.5 VXS (via USDC/VXS pool)",
"route_type": "direct",
"estimated_fee_vxs": "0.00042 VXS",
"price_impact": "0.3%",
"slippage_tolerance": "1%",
"balance_sufficient": true,
"warnings": []
}
Step 2: Submit -- If the user approves, call vex_submitIntent with the same intent string.
For auto-routed swaps, the preview shows the routing path:
{
"summary": "Swap 100 DAI -> ~4.2 SOL (via DAI -> VXS -> SOL)",
"route_type": "auto-routed (2 hops)",
"price_impact": "1.2%",
"warnings": ["Auto-routed through VXS. Slippage applied per leg."]
}
Supported Intent Patterns
Token Operations
| Pattern | Example | Goal Type |
|---|---|---|
| Swap | "swap 100 VXS for USDC" | Swap |
| Swap with slippage | "swap 50 ETH for VXS with 3% slippage" | Swap + constraints |
| Buy | "buy 100 VXS with USDC" | Swap (reversed) |
| Sell | "sell 50 ETH for USDC" | Swap |
| Convert | "convert 200 USDT to VXS" | Swap |
| Trade | "trade 100 SOL for VXS" | Swap |
| Multi-swap | "swap 10 USDC and 10 USDT for VXS" | Composite (2 swaps) |
Staking & Liquidity
| Pattern | Example | Goal Type |
|---|---|---|
| Stake | "stake 1000 VXS" | Stake |
| Stake with validator | "stake 500 VXS with validator Vx0abc..." | Stake |
| Provide liquidity | "add liquidity 100 VXS and 50 USDC" | ProvideLiquidity |
Transfers & Bridge
| Pattern | Example | Goal Type |
|---|---|---|
| Transfer | "send 100 VXS to Vx0abc..." | Transfer |
| Transfer (VNS) | "send 50 USDC to chris.vex" | Transfer |
| Pay | "pay 25 VXS to Vx0abc..." | Transfer |
| Bridge | "bridge 10 SOL from solana" | Bridge |
| Bridge + Swap | "bridge 10 SOL from solana and swap to VXS" | Composite |
Outcome-Based Intents
Specify what you want, not the steps. The planner reverse-engineers the execution.
| Pattern | Example | Goal Type |
|---|---|---|
| Acquire | "get me 10 SOL, max 200 USDC" | Acquire |
| Acquire (no limit) | "get me 5 ETH" | Acquire |
| Acquire (I need) | "I need 100 VXS, spending at most 50 USDC" | Acquire |
| Liquidate | "liquidate to 500 USDC" | Liquidate |
| Liquidate (keep) | "sell everything for USDC keeping VXS" | Liquidate |
| Liquidate (exclude) | "cash out to 1000 USDC excluding VXS and ETH" | Liquidate |
| Rebalance | "rebalance to 50% VXS, 30% USDC, 20% ETH" | Rebalance |
How Acquire works: The planner queries pool reserves, uses reverse AMM math to calculate the exact input amount needed to receive your target output, validates against your max cost constraint, and executes the swap. If the required cost exceeds your max, the intent is rejected before execution.
How Liquidate works: The planner queries your on-chain token holdings, excludes any tokens you want to keep, sorts remaining holdings by best swap rate to the target token, and greedily sells from best rate until your target amount is covered.
Portfolio Intelligence
| Pattern | Example | Goal Type |
|---|---|---|
| Allocate | "put 100 VXS split 60 stake 40 liquidity" | Allocate |
| DCA | "buy 10 VXS with USDC every day for 7 days" | Recurring |
| DCA (hourly) | "swap 5 USDC for VXS every hour for 24 hours" | Recurring |
| DCA (weekly) | "buy 100 VXS with USDC every week for 4 weeks" | Recurring |
Conditional & Limit Orders
| Pattern | Example | Goal Type |
|---|---|---|
| Price condition | "swap 100 USDC for VXS if price below 0.15" | Conditional |
| Limit buy | "limit buy 100 VXS at 0.12 USDC" | Conditional |
| Price above | "sell 50 VXS for USDC if price above 1.5" | Conditional |
Synthetic Assets (VSC-71)
| Pattern | Example | Goal Type |
|---|---|---|
| Mint synthetic | "buy 10 AAPL with USDC" | MintSynthetic |
| Mint index | "buy 5 SPY with USDC" | MintSynthetic |
| Long perpetual | "open 5x long ETH perp with 100 USDC" | OpenPosition |
| Short perpetual | "short BTC 3x with 200 USDC" | OpenPosition |
VSC-71 synthetic assets are a licensee interface. The Goal types are parsed and accepted by IntentVM, but oracle pricing and margin logic are not built into the base protocol. See the VSC-71 Integration Guide for how to implement.
VNS Registration
| Pattern | Example | Goal Type |
|---|---|---|
| Register name | "register chris.vex" | Custom (VNS) |
| Register (no suffix) | "register myname" | Custom (VNS) |
Inline Constraints
Constraints can be embedded directly in any intent string. The parser extracts them before processing the goal:
| Constraint | Syntax | Example |
|---|---|---|
| Slippage | "with N% slippage" | "swap 100 VXS for USDC with 2% slippage" |
| Deadline | "within N minutes", "deadline N seconds" | "swap 100 VXS for USDC within 5 minutes" |
| Max fee | "max fee N", "gas limit N", "fee cap N" | "stake 1000 VXS max fee 50000" |
Multiple constraints can be combined in a single intent:
"swap 100 USDC for VXS with 2% slippage within 5 minutes max fee 100000"
Multi-Language Support
The NL parser accepts intents in 7 languages. Non-English input is normalized to English equivalents before parsing. All intent types work in all languages -- swaps, transfers, staking, outcome-based intents, and constraints.
Supported Verbs
| Language | buy | sell | swap | send | stake |
|---|---|---|---|---|---|
| English | buy, get, purchase | sell, dump | swap, convert, trade | send, pay | stake, deposit |
| Spanish | comprar | vender | intercambiar, cambiar | enviar | apostar |
| Portuguese | comprar | venda | trocar | envie | -- |
| French | acheter | vendre | échanger | envoyer | -- |
| German | kaufen | verkaufen | tauschen | senden | -- |
| Italian | comprare | vendere | scambiare | inviare | -- |
| Japanese | 買う (kau) | 売る (uru) | 交換 (koukan) | 送る (okuru) | -- |
Connector Words
| Language | "with" | "for" | "to" | "every" |
|---|---|---|---|---|
| Spanish | con | por | para | cada |
| Portuguese | com | -- | -- | cada |
| French | avec | pour | -- | -- |
| German | mit | für | -- | -- |
| Italian | con | -- | -- | -- |
Examples by Language
# English
"buy 10 VXS with USDC" → Acquire (reverse-quotes ~1 USDC from pool)
"swap 100 USDC for VXS" → Swap (100 USDC input)
"get me 5 SOL max 200 USDC" → Acquire with cost cap
# Spanish
"comprar 10 VXS con USDC" → Acquire
"intercambiar 100 USDC por VXS" → Swap
"enviar 50 VXS para Vx0abc..." → Transfer
# Portuguese
"trocar 100 USDC por VXS" → Swap
"comprar 10 VXS com USDC" → Acquire
# French
"acheter 10 VXS avec USDC" → Acquire
"échanger 50 ETH pour VXS" → Swap
# German
"kaufen 10 VXS mit USDC" → Acquire
"tauschen 100 USDC für VXS" → Swap
# Italian
"comprare 10 VXS con USDC" → Acquire
"scambiare 100 USDC per VXS" → Swap
"buy" vs "swap" semantics: "buy 10 VXS with USDC" produces an Acquire intent -- the 10 refers to the desired output, and the planner reverse-calculates the required USDC input from pool reserves. "swap 100 USDC for VXS" produces a Swap -- the 100 is the input amount. This distinction applies in all languages.
Adding a Language
The normalizer is a simple string replacement pipeline. To add a new language, map verbs and connectors to their English equivalents in the normalizer. Longer forms must be listed before shorter ones to prevent partial matching (e.g., Italian "comprare" before Spanish "comprar").
Known Token Symbols
| Symbol | Token | Decimals | Mint Address |
|---|---|---|---|
| VXS | Native Vexidus | 9 | Address::ZERO |
| USDC | Bridged USDC | 6 | Blake3("ethereum_USDC") |
| USDT | Bridged USDT | 6 | Blake3("ethereum_USDT") |
| DAI | Bridged DAI | 18 | Blake3("ethereum_DAI") |
| SOL | Bridged SOL | 9 | Blake3("solana_SOL") |
| ETH/WETH | Bridged ETH | 18 | Blake3("ethereum_ETH") |
| BTC/WBTC | Bridged BTC | 8 | Blake3("ethereum_WBTC") |
| BNB | Bridged BNB | 18 | Blake3("bsc_BNB") |
Dynamic decimal resolution: The NL parser resolves each token's decimals from the on-chain token registry at parse time. For example, "swap 100 USDC for VXS" correctly uses 6 decimals for USDC (100 × 10^6) and 9 decimals for VXS. Custom tokens created via VexForge are also resolved dynamically.
RPC Methods
Intent Submission & Query
| Method | Params | Returns |
|---|---|---|
vex_submitIntent | [intent_string, sender_address] | Bundle hash |
vex_getExecutionPlan | [intent_string] | Execution steps, estimated gas, savings |
vex_getIntentStatus | [bundle_hash] | Status (pending/completed/failed), gas used |
Simulation & Preview
| Method | Params | Returns |
|---|---|---|
vex_simulateIntent | [intent_string, sender_address] | Dry-run result: operations, per-pool quotes, price impact (bps), balance checks, warnings |
vex_previewIntent | [intent_string, sender_address] | Human-readable confirmation: summary text, fee in VXS, price impact %, route type, warnings |
Price Queries
| Method | Params | Returns |
|---|---|---|
vex_getPrice | [from_symbol, to_symbol] | Spot price, TWAP, route type (direct or auto-routed) |
vex_quoteSwap | [from_token, to_token, amount_in] | Swap quote with estimated output |
Simulation Response Format
vex_simulateIntent returns detailed execution analysis:
{
"success": true,
"operations": [
{
"type": "Swap",
"from_token": "USDC",
"to_token": "VXS",
"amount_in": "100000000",
"estimated_out": "1985500000000",
"price_impact_bps": 30
}
],
"estimated_gas": 42000,
"total_price_impact_bps": 30,
"warnings": [],
"balance_check": {
"sufficient": true,
"required": "100000000",
"available": "500000000"
}
}
For auto-routed swaps, each leg is reported separately:
{
"operations": [
{
"type": "Swap (Leg 1)",
"from_token": "DAI",
"to_token": "VXS",
"price_impact_bps": 15
},
{
"type": "Swap (Leg 2)",
"from_token": "VXS",
"to_token": "SOL",
"price_impact_bps": 22
}
],
"total_price_impact_bps": 37,
"warnings": ["Auto-routed through VXS. Slippage applied per leg."]
}
Price Impact & Warnings
The simulation and preview endpoints include a warnings array. Common warnings:
| Warning | Meaning |
|---|---|
| "High price impact (>5%)" | Large order relative to pool size |
| "Auto-routed through VXS" | No direct pool, using intermediate token |
| "Price impact exceeds 25% -- execution will be rejected" | Order too large for available liquidity |
| "Insufficient balance" | Sender doesn't have enough tokens |
Architecture
User Input (NL or JSON, any supported language)
|
v
Multi-Language Normalizer
| maps non-English verbs to English equivalents
v
Constraint Extractor
| strips deadline, max_fee, slippage from text
v
NL Parser / JSON Deserializer
| pattern matching → Goal enum
v
IntentBuilder
| fluent API, builds Goal + Constraints
v
RPC: vex_previewIntent (wallet confirmation)
| summary, fee, price impact, warnings
v
RPC: vex_submitIntent
| builds intent bundle, submits to leader
v
Execution Engine
| decomposes Goal → native Operations
| auto-routing through intermediate pools
| price impact check (25% max per pool)
| constraint enforcement (deadline, fees, slippage)
v
Block Execution (atomic — all succeed or all revert)
Future: LLM Integration
The NL parser currently uses regex patterns. For more complex intents, integrate an LLM:
User: "Buy VXS with half my USDC and stake it with the highest-APY validator"
-> LLM extracts: Composite([
Swap { from: USDC, to: VXS, amount: 50% of balance },
Stake { token: VXS, amount: all, validator: highest_apy }
])
The Goal::Custom(String) variant is reserved for LLM-processed intents. Integration path:
- Client sends NL to LLM API (Grok, Claude, etc.)
- LLM returns structured Goal JSON
- Client submits structured JSON via
vex_submitIntent
Related Documentation
- IntentVM Architecture -- Deep dive into IntentVM design and provenance
- VSC-71 Integration Guide -- Synthetic assets for licensees
- Token Standards -- VexForge token operations that IntentVM composes
- SDK Guide -- BundleBuilder and WalletClient for programmatic access
- RPC Reference -- Full endpoint documentation