This document provides detailed analysis of core code implementations in the AI Smart Wallet project.
本文档详细分析 AI Smart Wallet 项目的核心代码实现。
The Intent Parser converts natural language commands into blockchain transaction parameters.
意图解析器将自然语言命令转换为区块链交易参数。
// frontend/lib/intentParser.ts
/**
* 解析后的意图结构
* Parsed intent structure
*/
export interface ParsedIntent {
target: `0x${string}` // 交易目标地址 | Transaction target
value: bigint // ETH 数量 (wei) | ETH amount in wei
data: `0x${string}` // 调用数据 | Calldata
description: string // 意图描述 | Intent description
suggestedModule?: `0x${string}` // 建议的策略模块 | Suggested module
}
/**
* 意图模式匹配规则
* Intent pattern matching rules
*/
interface IntentPattern {
type: IntentType
patterns: RegExp[]
extract: (match: RegExpMatchArray, input: string) => Partial<ParsedIntent> | null
}The parser uses regex patterns to identify intent types:
解析器使用正则表达式模式识别意图类型:
/**
* ETH 转账模式
* Supports formats:
* - "转账 0.1 ETH 到 0x123..."
* - "发送 1 ETH 给 0x456..."
* - "transfer 0.5 ETH to 0x789..."
* - "send 2 ETH to 0xabc..."
*/
const transferPattern: IntentPattern = {
type: 'transfer',
patterns: [
/(?:转账|发送|transfer|send)\s*([\d.]+)\s*(?:ETH|eth|ether)\s*(?:到|给|to)\s*(0x[a-fA-F0-9]{40})/i,
],
extract: (match) => {
const amount = match[1] // 捕获组1: 金额
const target = match[2] // 捕获组2: 地址
if (!amount || !target) return null
if (!isAddress(target)) return null // 验证地址格式
try {
const value = parseEther(amount) // 转换为 wei
return {
target: target as `0x${string}`,
value,
data: '0x' as `0x${string}`,
description: `转账 ${amount} ETH 到 ${target}`,
}
} catch {
return null // 金额解析失败
}
},
}export function parseIntent(intent: string): IntentParseResult {
// 1. 输入验证 | Input validation
if (!intent || typeof intent !== 'string') {
return { success: false, error: '意图不能为空' }
}
const trimmedIntent = intent.trim()
if (trimmedIntent.length === 0) {
return { success: false, error: '意图不能为空' }
}
// 2. 遍历所有模式 | Iterate through all patterns
for (const pattern of intentPatterns) {
for (const regex of pattern.patterns) {
const match = trimmedIntent.match(regex)
if (match) {
// 3. 提取意图数据 | Extract intent data
const extracted = pattern.extract(match, trimmedIntent)
if (extracted && extracted.target && extracted.description) {
return {
success: true,
intent: {
target: extracted.target,
value: extracted.value ?? BigInt(0),
data: extracted.data ?? '0x' as `0x${string}`,
description: extracted.description,
suggestedModule: extracted.suggestedModule,
},
}
}
}
}
}
// 4. 无法解析 | Unable to parse
return {
success: false,
error: '无法解析意图。支持的格式:\n- 转账 [数量] ETH 到 [地址]\n- 调用 [合约地址]',
}
}┌─────────────────┐
│ User Input │ "转账 0.1 ETH 到 0x1234..."
└────────┬────────┘
│
▼
┌─────────────────┐
│ Input Validate │ Check: non-empty string
└────────┬────────┘
│
▼
┌─────────────────┐
│ Pattern Match │ Match against regex patterns
└────────┬────────┘
│
┌────┴────┐
│ Match? │
└────┬────┘
Yes │ No
▼ ▼
┌───────┐ ┌───────┐
│Extract│ │ Error │
└───┬───┘ └───────┘
│
▼
┌─────────────────┐
│ Validate Data │ isAddress(), parseEther()
└────────┬────────┘
│
▼
┌─────────────────┐
│ ParsedIntent │ { target, value, data, description }
└─────────────────┘
// circuits/strategy.circom
template DailyLimitStrategy() {
// ============================================
// 私有输入 (Private Inputs) - 不公开
// ============================================
signal input dailyLimit; // 每日限额
signal input whitelist[5]; // 白名单地址
signal input salt; // 随机盐值
signal input whitelistEnabled; // 白名单开关
// ============================================
// 公开输入 (Public Inputs) - 链上可见
// ============================================
signal input commitment; // 策略承诺值
signal input txValue; // 交易金额
signal input txTarget; // 交易目标
signal input dailySpent; // 当日已花费
// ============================================
// 输出 (Output)
// ============================================
signal output valid; // 验证结果
}// 使用 Poseidon 哈希生成承诺值
// Generate commitment using Poseidon hash
component hasher = Poseidon(8);
hasher.inputs[0] <== dailyLimit;
hasher.inputs[1] <== whitelist[0];
hasher.inputs[2] <== whitelist[1];
hasher.inputs[3] <== whitelist[2];
hasher.inputs[4] <== whitelist[3];
hasher.inputs[5] <== whitelist[4];
hasher.inputs[6] <== salt;
hasher.inputs[7] <== whitelistEnabled;
// 约束:计算的哈希必须等于公开的承诺值
// Constraint: computed hash must equal public commitment
signal commitmentMatch;
commitmentMatch <== hasher.out - commitment;
commitmentMatch === 0; // 强制相等 | Force equalityWhy Poseidon? | 为什么用 Poseidon?
- ZK-friendly hash function | ZK 友好的哈希函数
- ~300 constraints vs ~25,000 for SHA256 | 约 300 个约束 vs SHA256 的约 25,000 个
- Native field arithmetic | 原生域运算
// 计算总花费 | Calculate total spending
signal totalSpending;
totalSpending <== dailySpent + txValue;
// 比较器:检查是否在限额内
// Comparator: check if within limit
component limitCheck = LessEqThan(252); // 252-bit 比较
limitCheck.in[0] <== totalSpending;
limitCheck.in[1] <== dailyLimit;
signal withinLimit;
withinLimit <== limitCheck.out; // 1 if within, 0 if exceededMathematical Representation | 数学表示:
withinLimit = 1 iff dailySpent + txValue ≤ dailyLimit
// 检查目标是否在白名单中
// Check if target is in whitelist
component isEqual[5];
signal matches[5];
for (var i = 0; i < 5; i++) {
isEqual[i] = IsEqual();
isEqual[i].in[0] <== txTarget;
isEqual[i].in[1] <== whitelist[i];
matches[i] <== isEqual[i].out; // 1 if match, 0 otherwise
}
// OR 所有匹配结果 | OR all matches
// inWhitelist = matches[0] ∨ matches[1] ∨ ... ∨ matches[4]
signal orResult[4];
component or1 = OR();
or1.a <== matches[0];
or1.b <== matches[1];
orResult[0] <== or1.out;
// ... (继续 OR 链)
signal inWhitelist;
inWhitelist <== orResult[3];
// 条件检查:如果白名单禁用则跳过
// Conditional: bypass if whitelist disabled
signal whitelistValid;
signal whitelistEnabledTimesInWhitelist;
whitelistEnabledTimesInWhitelist <== whitelistEnabled * inWhitelist;
whitelistValid <== (1 - whitelistEnabled) + whitelistEnabledTimesInWhitelist;Logic Table | 逻辑表:
| whitelistEnabled | inWhitelist | whitelistValid |
|---|---|---|
| 0 | 0 | 1 (bypass) |
| 0 | 1 | 1 (bypass) |
| 1 | 0 | 0 (reject) |
| 1 | 1 | 1 (accept) |
// 两个条件都必须满足
// Both conditions must pass
valid <== withinLimit * whitelistValid;Property-based testing verifies that properties hold for ALL valid inputs, not just specific examples.
属性测试验证属性对所有有效输入都成立,而不仅仅是特定示例。
// frontend/lib/intentParser.property.test.ts
import { describe, it, expect } from 'vitest'
import * as fc from 'fast-check'
import { parseIntent, isValidParsedIntent } from './intentParser'
describe('Intent Parser Properties', () => {
// Property 1: 有效转账意图总是能被解析
// Valid transfer intents are always parseable
it('should parse valid transfer intents', () => {
fc.assert(
fc.property(
// 生成器:有效的 ETH 金额和地址
// Generator: valid ETH amounts and addresses
fc.float({ min: 0.001, max: 1000, noNaN: true }),
fc.hexaString({ minLength: 40, maxLength: 40 }),
(amount, addressHex) => {
const address = `0x${addressHex}`
const intent = `transfer ${amount} ETH to ${address}`
const result = parseIntent(intent)
// 属性:解析成功且目标地址正确
// Property: parse succeeds and target is correct
expect(result.success).toBe(true)
expect(result.intent?.target.toLowerCase()).toBe(address.toLowerCase())
}
),
{ numRuns: 100 } // 运行 100 次随机测试
)
})
// Property 2: 空输入总是返回错误
// Empty inputs always return error
it('should reject empty inputs', () => {
fc.assert(
fc.property(
fc.constantFrom('', ' ', '\n', '\t'),
(emptyInput) => {
const result = parseIntent(emptyInput)
expect(result.success).toBe(false)
expect(result.error).toBeDefined()
}
)
)
})
// Property 3: 解析结果的不变量
// Invariants of parsed results
it('should maintain parsed intent invariants', () => {
fc.assert(
fc.property(
fc.float({ min: 0.001, max: 1000, noNaN: true }),
fc.hexaString({ minLength: 40, maxLength: 40 }),
(amount, addressHex) => {
const address = `0x${addressHex}`
const intent = `send ${amount} ETH to ${address}`
const result = parseIntent(intent)
if (result.success && result.intent) {
// 不变量:value 是 bigint
expect(typeof result.intent.value).toBe('bigint')
// 不变量:value >= 0
expect(result.intent.value >= 0n).toBe(true)
// 不变量:data 以 0x 开头
expect(result.intent.data.startsWith('0x')).toBe(true)
// 不变量:description 非空
expect(result.intent.description.length).toBeGreaterThan(0)
}
}
)
)
})
})// test/SmartWalletV2.property.test.cjs
const fc = require('fast-check')
const { expect } = require('chai')
describe('SmartWalletV2 Properties', function() {
// Property: 守护者添加后状态一致
// Guardian addition maintains state consistency
it('guardian addition is consistent', async function() {
await fc.assert(
fc.asyncProperty(
fc.array(fc.hexaString({ minLength: 40, maxLength: 40 }), { minLength: 1, maxLength: 5 }),
async (guardianHexes) => {
const guardians = guardianHexes.map(h => `0x${h}`)
// 添加所有守护者
for (const guardian of guardians) {
await wallet.addGuardian(guardian)
}
// 属性:所有添加的守护者都应该是守护者
for (const guardian of guardians) {
const isGuardian = await wallet.isGuardian(guardian)
expect(isGuardian).to.be.true
}
// 属性:守护者列表长度正确
const list = await wallet.getGuardians()
expect(list.length).to.equal(guardians.length)
}
),
{ numRuns: 50 }
)
})
// Property: 恢复阈值约束
// Recovery threshold constraints
it('threshold cannot exceed guardian count', async function() {
await fc.assert(
fc.asyncProperty(
fc.integer({ min: 1, max: 10 }),
fc.integer({ min: 1, max: 10 }),
async (guardianCount, threshold) => {
// 添加守护者
for (let i = 0; i < guardianCount; i++) {
await wallet.addGuardian(ethers.Wallet.createRandom().address)
}
if (threshold > guardianCount) {
// 属性:阈值超过守护者数量应该失败
await expect(
wallet.setRecoveryThreshold(threshold)
).to.be.revertedWith('Threshold exceeds guardian count')
} else {
// 属性:有效阈值应该成功
await wallet.setRecoveryThreshold(threshold)
const currentThreshold = await wallet.getRecoveryThreshold()
expect(currentThreshold).to.equal(threshold)
}
}
)
)
})
})// contracts/interfaces/IStrategyModule.sol
interface IStrategyModule {
/**
* @notice 检查交易是否被允许
* @param caller 调用者地址
* @param target 目标地址
* @param value ETH 数量
* @param data 调用数据
* @return allowed 是否允许
*/
function check(
address caller,
address target,
uint256 value,
bytes calldata data
) external view returns (bool allowed);
/**
* @notice 返回模块名称
*/
function name() external view returns (string memory);
}function installModule(
uint256 moduleType, // 模块类型 (ERC-7579 定义)
address module, // 模块地址
bytes calldata initData // 初始化数据
) external onlyOwner {
require(module != address(0), "Invalid module address");
// 1. 注册模块
modules[module] = true;
// 2. 调用模块初始化(如果有)
if (initData.length > 0) {
(bool success,) = module.call(initData);
require(success, "Module init failed");
}
// 3. 发出事件
emit ModuleInstalled(moduleType, module);
}function executeWithModule(
address target,
uint256 value,
bytes calldata data,
address module
) external returns (bytes memory result) {
// 1. 授权检查
require(msg.sender == owner || agents[msg.sender], "Not authorized");
// 2. 模块激活检查
require(modules[module], "Module not active");
// 3. 余额检查
require(address(this).balance >= value, "Insufficient balance");
// 4. 模块策略检查 ⭐
bool allowed = IStrategyModule(module).check(msg.sender, target, value, data);
require(allowed, "Module check failed");
// 5. 执行交易
bool success;
(success, result) = target.call{value: value}(data);
// 6. 发出事件
emit Execution(target, value, data, success);
return result;
} ┌─────────────────┐
│ INACTIVE │
│ (No Recovery) │
└────────┬────────┘
│
│ initiateRecovery()
│ [guardian calls]
▼
┌─────────────────┐
│ ACTIVE │◄────────────┐
│ (Collecting │ │
│ Supports) │─────────────┤
└────────┬────────┘ │
│ │
┌─────────────────┼─────────────────┐ │
│ │ │ │
│ cancelRecovery()│ supportRecovery() │
│ [owner calls] │ [guardian calls] │
│ │ │
▼ ▼ │
┌──────────┐ ┌─────────────────┐ │
│ INACTIVE │ │ supportCount++ │────────────┘
└──────────┘ └────────┬────────┘
│
│ [supportCount >= threshold]
│
▼
┌─────────────────┐
│ executeRecovery│
│ [anyone calls] │
└────────┬────────┘
│
│ [within 7 days]
▼
┌─────────────────┐
│ COMPLETED │
│ (Owner Changed) │
└─────────────────┘
| Current State | Action | Condition | Next State |
|---|---|---|---|
| INACTIVE | initiateRecovery | isGuardian | ACTIVE |
| ACTIVE | supportRecovery | isGuardian, !alreadySupported | ACTIVE |
| ACTIVE | executeRecovery | supportCount >= threshold, !expired | COMPLETED |
| ACTIVE | cancelRecovery | isOwner | INACTIVE |
| ACTIVE | expireRecovery | timestamp > initiatedAt + 7 days | INACTIVE |
This codebase demonstrates several advanced patterns:
本代码库展示了几个高级模式:
-
Intent-Centric Design | 意图驱动设计
- Natural language → Transaction parameters
- 自然语言 → 交易参数
-
Zero-Knowledge Privacy | 零知识隐私
- Hide strategy details while proving compliance
- 隐藏策略细节同时证明合规
-
Modular Architecture | 模块化架构
- ERC-7579 compatible pluggable modules
- ERC-7579 兼容的可插拔模块
-
Property-Based Testing | 属性测试
- Verify invariants across all inputs
- 验证所有输入的不变量
-
Social Recovery | 社交恢复
- Guardian-based ownership recovery
- 基于守护者的所有权恢复