fluid-wallet-agentkit
v1.7.0
Published
SDK for AI agents to interact with Fluid Wallet — payments, swaps, batch send, UAI identity, Pauli Keys, FADP, and SOR quotes
Maintainers
Readme
fluid-wallet-agentkit
The official SDK for AI agents to interact with Fluid Wallet.
Give your AI agent a crypto wallet — send payments, swap tokens, check balances, and pay other agents, all without exposing a seed phrase or private key.
What is Fluid Wallet?
Fluid Wallet is a self-custodial crypto wallet built on Base. It lets users create email-based wallets secured by a seed phrase and Google Authenticator (TOTP). Once an account is created, the owner can generate Agentic Keys — scoped API keys that allow AI agents to operate the wallet within set limits.
No seed phrase. No private key. Just a scoped API key your agent uses.
How It Works
User registers at fluidnative.com
↓
Creates an Agentic Key with scopes + spend limits
↓
Gives the key (fwag_...) to the AI agent
↓
Agent uses fluid-wallet-agentkit SDK to send, swap, pay
↓
Transactions above $100 → owner gets email approval request
All transactions → owner gets email notificationInstallation
npm install fluid-wallet-agentkitSetting Up — New Account
If you need a brand new Fluid Wallet account:
npx fluid-wallet registerThis wizard guides you through:
- Opening
https://fluidnative.comin a browser - Registering with email + password
- Saving the 12-word seed phrase (shown once, must be written down)
- Scanning Google Authenticator QR code
- Creating an Agentic Key in the dashboard
- Verifying identity in the terminal
Note: The seed phrase and OTP steps require a human present at the browser. The agent handles the terminal steps.
Setting Up — Existing Account
If you already have a Fluid Wallet account:
npx fluid-wallet setupEnter your email, password, seed phrase, and OTP when prompted. Your agent key is saved to .env automatically.
Check Agent Status
npx fluid-wallet statusFramework Integration
OpenAI SDK
import OpenAI from "openai";
import { FluidAgent, toOpenAITools, runOpenAIToolCall } from "fluid-wallet-agentkit";
const agent = new FluidAgent({ apiKey: process.env.FLUID_AGENT_KEY! });
const client = new OpenAI();
const response = await client.chat.completions.create({
model: "gpt-4o",
tools: toOpenAITools(agent), // ← drop-in
messages: [{ role: "user", content: "What's my wallet balance?" }],
});
// Execute whichever tool OpenAI chose
for (const call of response.choices[0].message.tool_calls ?? []) {
const result = await runOpenAIToolCall(agent, call);
console.log(result);
}Anthropic Claude SDK
import Anthropic from "@anthropic-ai/sdk";
import { FluidAgent, toAnthropicTools, runAnthropicToolCall } from "fluid-wallet-agentkit";
const agent = new FluidAgent({ apiKey: process.env.FLUID_AGENT_KEY! });
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 1024,
tools: toAnthropicTools(agent), // ← drop-in
messages: [{ role: "user", content: "Send 0.01 ETH to 0xABC..." }],
});
for (const block of response.content) {
if (block.type === "tool_use") {
const result = await runAnthropicToolCall(agent, block);
console.log(result);
}
}Vercel AI SDK
import { generateText, jsonSchema } from "ai";
import { openai } from "@ai-sdk/openai";
import { FluidAgent, toVercelAITools } from "fluid-wallet-agentkit";
const agent = new FluidAgent({ apiKey: process.env.FLUID_AGENT_KEY! });
const { text } = await generateText({
model: openai("gpt-4o"),
tools: toVercelAITools(agent, jsonSchema), // ← drop-in
prompt: "Swap 0.1 ETH to USDC and tell me the result.",
});LangChain / LangGraph
import { ChatOpenAI } from "@langchain/openai";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
import { FluidAgent, toLangChainTools } from "fluid-wallet-agentkit";
const agent = new FluidAgent({ apiKey: process.env.FLUID_AGENT_KEY! });
// Wrap into LangChain DynamicStructuredTool objects
const tools = toLangChainTools(agent).map(
(t) =>
new DynamicStructuredTool({
name: t.name,
description: t.description,
schema: z.object({}).passthrough(),
func: t.func,
})
);
// Use with createReactAgent, AgentExecutor, etc.Raw tools (any framework)
import { FluidAgent, getFluidTools } from "fluid-wallet-agentkit";
const agent = new FluidAgent({ apiKey: process.env.FLUID_AGENT_KEY! });
const tools = getFluidTools(agent);
// Each tool has: name, description, inputSchema (JSON Schema), run(args)
for (const tool of tools) {
console.log(tool.name, tool.description);
}
// Execute any tool by name
const result = await tools
.find(t => t.name === "fluid_balance")!
.run({});
console.log(result); // {"walletAddress":"0x...","balances":[...]}Available Tools
| Tool | Scope required | Description |
|---|---|---|
| fluid_me | any | Identity: email, wallet address, key name, scopes |
| fluid_balance | read | On-chain balances in crypto and USD |
| fluid_history | read | Recent transaction history |
| fluid_resolve | read | Resolve email → wallet address |
| fluid_quote_swap | read | Price quote for a swap (no execution) |
| fluid_estimate_gas | read | Gas cost estimate for a send |
| fluid_send | pay | Send ETH or tokens on-chain |
| fluid_swap | swap | Swap tokens via Fluid SOR |
| fluid_agent_pay | agentpay | Pay another Fluid user by email |
Usage
Initialize
import { FluidAgent } from 'fluid-wallet-agentkit';
const agent = new FluidAgent({
apiKey: process.env.FLUID_AGENT_KEY, // fwag_...
});Get Wallet Identity
const me = await agent.me();
console.log(me.email); // owner email
console.log(me.walletAddress); // Base wallet address
console.log(me.scopes); // ['read', 'pay', 'swap', 'agentpay']Check Balance
const identity = await agent.identity;
// Use the API directly for balance
const r = await fetch('https://fluidnative.com/v1/agents/balance', {
headers: { 'X-Agent-Key': process.env.FLUID_AGENT_KEY }
});
const balance = await r.json();
console.log(balance);Send a Payment
const result = await agent.payments.send({
to: '0xRecipientAddress', // wallet address
amount: '0.01', // amount as string
token: 'ETH', // ETH, USDC, USDT, etc.
chain: 'base', // base | ethereum
});
console.log(result.txHash);
console.log(result.explorerUrl);If the amount is above your per-transaction limit ($100 by default): The request returns
202 pending_approval. The wallet owner receives an email with Approve / Reject buttons. Your agent should poll the approval status endpoint.
// Handle approval flow
if (result.status === 'pending_approval') {
console.log('Waiting for owner approval...');
console.log('Poll:', result.pollUrl);
// Poll every 5 seconds
const pollApproval = async (token: string) => {
while (true) {
const r = await fetch(`https://fluidnative.com/api/agent-approval-status/${token}`);
const status = await r.json();
if (status.status === 'approved') return true;
if (status.status === 'rejected') throw new Error('Transaction rejected by owner');
if (status.status === 'expired') throw new Error('Approval request expired');
await new Promise(resolve => setTimeout(resolve, 5000));
}
};
await pollApproval(result.approvalToken);
// Re-submit the transaction after approval
}Swap Tokens
// Get a price quote first (no execution)
const quote = await agent.payments.quoteSwap({
fromToken: 'ETH',
toToken: 'USDC',
amount: '0.1',
});
console.log(quote);
// Execute the swap
const swap = await agent.payments.swap({
fromToken: 'ETH',
toToken: 'USDC',
amount: '0.1',
slippage: '0.5', // optional, default 0.5%
});
console.log(swap.txHash);Pay Another Fluid User by Email
const result = await agent.payments.agentPay({
toEmail: '[email protected]',
amount: '10',
token: 'USDC',
memo: 'Payment for services', // optional
});Resolve Email → Wallet Address
const identity = await agent.identity.resolve('[email protected]');
console.log(identity.walletAddress); // 0x...
console.log(identity.username); // their Fluid usernameTransaction History
const history = await agent.identity.history(20); // last 20 txsEstimate Gas
const gas = await agent.payments.estimateGas({
to: '0xRecipientAddress',
amount: '0.01',
token: 'ETH',
chain: 'base',
});
console.log(gas.estimatedGasUsd); // "$0.01-0.05"Spend Limits & Approvals
Every Agentic Key has two limits set by the wallet owner:
| Limit | Default | Behavior | |---|---|---| | Per-transaction limit | $100 USD | Transactions above this require owner email approval | | Daily spend cap | $1000 USD | Hard daily limit — blocked if exceeded |
Approval flow:
- Agent sends request → server checks USD value
- If above per-tx limit →
202response withapprovalToken - Owner receives email with Approve / Reject buttons
- Agent polls
GET /api/agent-approval-status/:token - Owner approves → agent re-submits transaction
The owner also receives an email notification for every transaction above $100, regardless of approval status.
Agentic Key Scopes
| Scope | What it allows |
|---|---|
| read | Balance, history, price quotes, gas estimates |
| pay | Send ETH or ERC-20 tokens on-chain |
| swap | Execute token swaps via Fluid SOR |
| agentpay | Pay another Fluid user by their email |
Keys that lack a required scope return 403 Forbidden.
Direct API (without SDK)
All endpoints require: X-Agent-Key: fwag_...
Base URL: https://fluidnative.com
# Identity
GET /v1/agents/me
GET /v1/agents/balance
GET /v1/agents/history?limit=20
GET /v1/agents/identity/[email protected]
# Payments
POST /v1/agents/send
POST /v1/agents/swap
POST /v1/agents/agent-pay
POST /v1/agents/quote-swap
POST /v1/agents/estimate-gas
# Approvals
GET /api/agent-approval-status/:tokenExample with curl:
curl https://fluidnative.com/v1/agents/me \
-H "X-Agent-Key: fwag_your_key_here"Full Example — Autonomous Payment Agent
import { FluidAgent } from 'fluid-wallet-agentkit';
const agent = new FluidAgent({ apiKey: process.env.FLUID_AGENT_KEY! });
async function payForService(recipientEmail: string, usdAmount: string) {
// 1. Verify identity
const me = await agent.me();
console.log(`Agent wallet: ${me.walletAddress}`);
// 2. Check recipient
const recipient = await agent.identity.resolve(recipientEmail);
console.log(`Paying: ${recipient.walletAddress}`);
// 3. Send payment
const result = await agent.payments.agentPay({
toEmail: recipientEmail,
amount: usdAmount,
token: 'USDC',
});
// 4. Handle approval if needed
if ((result as any).status === 'pending_approval') {
console.log('Waiting for owner approval...');
const token = (result as any).approvalToken;
let approved = false;
while (!approved) {
await new Promise(r => setTimeout(r, 5000));
const s = await fetch(`https://fluidnative.com/api/agent-approval-status/${token}`);
const { status } = await s.json();
if (status === 'approved') approved = true;
else if (status === 'rejected') throw new Error('Payment rejected by owner');
else if (status === 'expired') throw new Error('Approval expired');
}
// Re-submit after approval
return payForService(recipientEmail, usdAmount);
}
console.log(`Payment sent! TX: ${(result as any).txHash}`);
return result;
}
payForService('[email protected]', '25');Security
| Concern | How it's handled |
|---|---|
| Seed phrase | Never stored, never sent to SDK — zeroed immediately after CLI verification |
| Private key | Never exposed — server-side signing only |
| API key | Store in .env only — never hardcode or log |
| Key creation | Browser-only — cannot be created via CLI or API |
| Spend limits | Owner sets per-tx and daily limits at key creation |
| Approval flow | Transactions above limit require owner email approval |
| Notifications | Owner receives email for every transaction above $100 |
Environment Variables
FLUID_AGENT_KEY=fwag_... # your agentic key (required)
FLUID_BASE_URL=https://fluidnative.com # optional, defaults to productionSupported Chains
| Chain | Network | Native Token |
|---|---|---|
| base | Base mainnet | ETH |
| ethereum | Ethereum mainnet | ETH |
| solana | Solana mainnet | SOL |
| injective | Injective mainnet | INJ |
Links
- Website: https://fluidnative.com
- Create Agentic Key: https://fluidnative.com/agentic-keys
- Agent API: https://fluidnative.com/.well-known/agent.json
- MCP descriptor: https://fluidnative.com/.well-known/mcp.json
- npm: https://www.npmjs.com/package/fluid-wallet-agentkit
- GitHub: https://github.com/fluidbase9/fluid-wallet-agentkit
License
MIT © Fluid Wallet
