@ael-protocol/sdk
v0.2.0
Published
AEL SDK - Intent-based trading execution for AI Agents on Base
Maintainers
Readme
@ael-protocol/sdk
AEL SDK - Intent-based trading execution for AI Agents on Base.
AEL (Agent Execution Layer) enables AI agents to execute on-chain trades through a simple intent-based API. Submit your trading intent, and Solvers compete to execute it at the best price.
Installation
npm install @ael-protocol/sdk viemQuick Start (6 Lines)
import { AEL, BASE_MAINNET, ETH_ADDRESS } from '@ael-protocol/sdk';
import { base } from 'viem/chains';
import { parseEther, parseUnits } from 'viem';
// Recommend using Alchemy or Infura RPC for production
const ael = new AEL({ privateKey: '0x...', routerAddress: BASE_MAINNET.AEL_ROUTER, chain: base, rpcUrl: process.env.BASE_RPC_URL || 'https://mainnet.base.org' });
const result = await ael.swap({ tokenIn: ETH_ADDRESS, tokenOut: BASE_MAINNET.USDC, amountIn: parseEther('0.1'), minAmountOut: parseUnits('200', 6) });
const status = await ael.waitForSettlement(result.intentHash);Contract Addresses
Base Mainnet (Chain ID: 8453)
| Contract | Address |
|----------|---------|
| Router | 0x85977BD37d8100F81566A1c6815047f5557bCDCB |
| SolverRegistry | 0xd14D394631C32Ea35fFF8407157C6867bCc8E946 |
| FeeVault | 0xF8E3646b03a83465D6DAE65edbF380C77feb5DE0 |
Base Sepolia (Chain ID: 84532)
| Contract | Address |
|----------|---------|
| Router | 0x83A260939cF1326E9aa94eF6c814F2Fd876535e8 |
| SolverRegistry | 0xC69A90904B44297af5fC7C554d7ca37612Ef01B3 |
| FeeVault | 0xAec32AbD0233a124B7D0A17055fB40a50442E088 |
API Reference
new AEL(config)
Create a new AEL instance.
interface AELConfig {
privateKey: `0x${string}`; // Agent's private key
routerAddress: `0x${string}`; // AEL Router address
chain: Chain; // viem chain object (base or baseSepolia)
rpcUrl: string; // RPC endpoint URL
}
// Recommend using Alchemy or Infura RPC for production
const ael = new AEL({
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
routerAddress: BASE_MAINNET.AEL_ROUTER,
chain: base,
rpcUrl: process.env.BASE_RPC_URL || 'https://mainnet.base.org',
});ael.swap(params): Promise<SwapResult>
Submit a swap intent. Handles EIP-712 signing and ERC20 approval automatically.
interface SwapParams {
tokenIn: `0x${string}`; // Input token (use ETH_ADDRESS for ETH)
tokenOut: `0x${string}`; // Output token address
amountIn: bigint; // Amount to swap (in wei)
minAmountOut: bigint; // Minimum output (slippage protection)
deadline?: bigint; // Optional deadline (default: 1 hour)
}
interface SwapResult {
intentHash: `0x${string}`; // Unique intent identifier
txHash: `0x${string}`; // Transaction hash
status: IntentStatus; // 'Pending'
}
// Example
const result = await ael.swap({
tokenIn: ETH_ADDRESS,
tokenOut: BASE_MAINNET.USDC,
amountIn: parseEther('0.1'),
minAmountOut: parseUnits('200', 6),
});ael.quote(tokenIn, tokenOut, amountIn): Promise<QuoteResult | null>
Get a price quote from Uniswap V3. Tries all fee tiers (0.05%, 0.3%, 1%) and returns the best.
interface QuoteResult {
amountOut: bigint; // Expected output amount
priceImpact: number; // Price impact percentage
fee: number; // Pool fee tier (500, 3000, or 10000)
}
const quote = await ael.quote(ETH_ADDRESS, BASE_MAINNET.USDC, parseEther('1'));
if (quote) {
console.log('Expected:', quote.amountOut, 'Fee tier:', quote.fee);
}ael.cancel(intentHash): Promise<Hash>
Cancel a pending intent and get refunded. Only works after 30-second lock period.
const txHash = await ael.cancel(intentHash);ael.getStatus(intentHash): Promise<IntentStatus>
Check the current status of an intent.
enum IntentStatus {
None = 0, // Intent doesn't exist
Pending = 1, // Waiting for Solver
Settled = 2, // Successfully executed
Refunded = 3, // Cancelled or failed
Expired = 4, // Deadline passed
}
const status = await ael.getStatus(intentHash);ael.waitForSettlement(intentHash, timeoutMs?): Promise<IntentStatus>
Poll until intent is settled, refunded, or expired. Default timeout: 60 seconds.
const finalStatus = await ael.waitForSettlement(intentHash, 120000);
if (finalStatus === IntentStatus.Settled) {
console.log('Trade executed!');
}ael.address
Get the agent's wallet address.
console.log('Agent:', ael.address);Constants
import { BASE_MAINNET, BASE_SEPOLIA, ETH_ADDRESS } from '@ael-protocol/sdk';
// Mainnet
BASE_MAINNET.AEL_ROUTER // Router contract
BASE_MAINNET.USDC // 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
BASE_MAINNET.WETH // 0x4200000000000000000000000000000000000006
// Testnet
BASE_SEPOLIA.AEL_ROUTER // Router contract
BASE_SEPOLIA.USDC // 0x036CbD53842c5426634e7929541eC2318f3dCF7e
// Native ETH
ETH_ADDRESS // 0x0000000000000000000000000000000000000000Intent Lifecycle
[Agent] submitIntent() --> [Pending] --> [Solver] settle() --> [Settled]
|
+--> [Agent] cancel() --> [Refunded]
|
+--> deadline passed --> [Expired]Fee Structure
- Protocol fee: 2 basis points (0.02%) on input token
- Fee distribution:
- 70% to Solver (execution reward)
- 20% to Protocol Treasury
- 10% to Governance Fund
Complete Example
import { AEL, BASE_MAINNET, ETH_ADDRESS, IntentStatus } from '@ael-protocol/sdk';
import { base } from 'viem/chains';
import { parseEther, parseUnits, formatUnits } from 'viem';
async function main() {
// Recommend using Alchemy or Infura RPC for production
const ael = new AEL({
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
routerAddress: BASE_MAINNET.AEL_ROUTER,
chain: base,
rpcUrl: process.env.BASE_RPC_URL || 'https://mainnet.base.org',
});
console.log('Agent:', ael.address);
// Get quote
const quote = await ael.quote(ETH_ADDRESS, BASE_MAINNET.USDC, parseEther('0.1'));
if (!quote) throw new Error('No liquidity');
console.log('Quote:', formatUnits(quote.amountOut, 6), 'USDC');
// Swap with 2% slippage
const minOut = quote.amountOut * 98n / 100n;
const result = await ael.swap({
tokenIn: ETH_ADDRESS,
tokenOut: BASE_MAINNET.USDC,
amountIn: parseEther('0.1'),
minAmountOut: minOut,
});
console.log('Intent:', result.intentHash);
// Wait for settlement
const status = await ael.waitForSettlement(result.intentHash, 60000);
console.log('Status:', IntentStatus[status]);
}
main().catch(console.error);Error Handling
try {
await ael.swap({...});
} catch (error) {
if (error.message.includes('DepositCapExceeded')) {
// Protocol deposit limit reached
} else if (error.message.includes('InsufficientOutput')) {
// Slippage protection triggered
} else if (error.message.includes('InvalidDeadline')) {
// Deadline too short or too long
}
}License
MIT
