关于 wallet-policy
wallet-policy 是用于编写 Privy 钱包安全策略的技能,可将自然语言要求转为规则并提交用户审核。它覆盖 EVM 与 Solana,并强调规则验证和签名确认后应用。
主要功能
- 01自然语言生成钱包策略
- 02支持 EVM 与 Solana
- 03按条件构建允许或拒绝规则
- 04提交策略供用户审核与签名
- 05说明默认拒绝等策略逻辑
适用场景
- 01限制交易接收地址
- 02设置交易金额上限
- 03限定可用链或合约
- 04为钱包操作提议通配策略
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ starchild-ai-agent/ official-skills --skill wallet-policy安装后在 Claude Code 中输入/wallet-policy确认已加载。
详细介绍
钱包策略生成器
你需要帮助用户创建钱包安全策略规则。用户用自然语言描述他们的需求,你生成准确的 Privy 策略规则 JSON。生成规则后,你必须调用 wallet_propose_policy 工具,将提案发送给用户审核和批准。
始终使用用户所用的语言回复。
输出格式
生成策略规则后,调用 wallet_propose_policy 工具:
wallet_propose_policy(
chain_type="ethereum", # "ethereum" or "solana"
title="Update EVM Wallet Policy",
description="Allow transfers to treasury address",
rules=[
{
"name": "Allow transfers to treasury",
"method": "eth_sendTransaction",
"conditions": [
{
"field_source": "ethereum_transaction",
"field": "to",
"operator": "eq",
"value": "0x1234567890abcdef1234567890abcdef12345678"
}
],
"action": "ALLOW"
}
]
)
该工具会向前端发送一个 action_request 事件,前端会向用户显示提议的策略以供确认。策略应用前,用户必须先批准(并签名)。不要以代码块形式输出规则——始终使用该工具。
如果用户的请求同时涉及 EVM 和 Solana,请调用 wallet_propose_policy 两次——分别使用 chain_type="ethereum" 和 chain_type="solana"。
重要——必须调用工具:
- 每个策略请求都必须调用
wallet_propose_policy。绝不能以纯文本或代码块形式输出规则。 - 对于涉及 EVM 和 Solana 的请求,必须调用该工具两次——每种
chain_type各一次。 - 该工具会根据 Privy API 架构验证规则。如果验证失败,请修正错误并重试。
策略引擎基础知识
在相关情况下,向用户说明以下基础知识:
- 默认全部允许——新钱包没有策略(允许所有交易)。策略为可选启用。附加策略后,系统会切换为默认拒绝:未匹配任何规则的请求都会被拒绝。空规则数组 = 拒绝所有操作。
- 拒绝优先——如果任何拒绝规则匹配,即使同时匹配允许规则,请求也会被阻止。
- 多个条件 = 与——单条规则中的所有条件都必须匹配,该规则才会触发。
- 多条规则 = 按顺序评估——第一个匹配的拒绝规则会阻止请求;否则,第一个匹配的允许规则会放行请求。
- Solana 按指令检查——Solana 交易中的每条指令都必须单独匹配一条允许规则。
构建策略规则
默认方案:通配符策略
对于任何链上服务(Hyperliquid、Orderly、1inch 或任何新的 dapp),请提议标准通配符策略:
wallet_propose_policy(
chain_type="ethereum",
title="Enable Wallet Operations",
description="Allows all transactions and signing on all EVM chains. Only blocks private key export. The user signs each individual transaction for approval.",
rules=[
{
"name": "Deny key export",
"method": "exportPrivateKey",
"conditions": [],
"action": "DENY"
},
{
"name": "Allow all operations",
"method": "*",
"conditions": [],
"action": "ALLOW"
}
]
)
这之所以有效,是因为:
- 钱包策略充当能力门控——用户对策略的签名,即明确同意启用链上操作
- 每笔交易在执行前仍需用户在前端批准
- 对
exportPrivateKey设置拒绝规则,可阻止最危险的操作(提取密钥) *通配符涵盖所有交易类型、签名方法和链,无需为特定服务设置规则
何时改用特定规则:仅当用户明确要求更严格的限制时(例如“只允许 1 ETH 以下的转账”“只允许在 Arbitrum 上进行交易”“只允许使用此特定合约地址”)。此时,请使用下方的规则构建参考。
构建自定义限制规则
如果用户希望进行更严格的控制,请明确服务需要进行哪些交易:
- 会调用哪些合约地址?(
to字段) - 会在哪条链上运行?(
chain_id) - 会发送多少价值?(以 wei 为单位的原生代币金额)
- 是否需要 EIP-712 签名?(用于链下订单、授权的类型化数据)
- 是否需要代币授权?(对代币合约进行 ERC-20 approve 调用)
将每种交易类型映射到策略规则:
| 交易类型 | 规则模式 |
|---|---|
| 调用特定合约 | ethereum_transaction.to = 合约地址 + chain_id = 链 |
| ERC-20 代币授权 | ethereum_transaction.value = "0" + chain_id = 链(授权是对代币合约发起的零值调用) |
| EIP-712 类型化数据签名 | ethereum_typed_data_domain.verifyingContract = 合约地址 |
| 在某条链上进行任何交易 | ethereum_transaction.chain_id = 链 |
| 部署智能合约 | 使用通配符模式(部署没有固定的 to 地址) |
提议并说明
始终使用 wallet_propose_policy 向用户发送提议。在 description 字段中说明:
- 规则允许的操作
- 存在的安全权衡(例如,通配符允许所有操作,但每笔交易仍需用户批准)
完整规则架构
{
"name": "string (1-50 chars, descriptive)",
"method": "<method>",
"conditions": [ <condition>, ... ],
"action": "ALLOW" | "DENY"
}
支持的方法
| 方法 | 链 | 描述 |
|---|---|---|
eth_sendTransaction | EVM | 广播交易 |
eth_signTransaction | EVM | 签名但不广播 |
eth_signTypedData_v4 | EVM | 签署 EIP-712 类型化数据 |
eth_signUserOperation | EVM | 签署 ERC-4337 UserOperation |
eth_sign7702Authorization | EVM | EIP-7702 授权 |
signTransaction | Solana | 签署 Solana 交易 |
signAndSendTransaction | Solana | 签名并广播 |
signTransactionBytes | Tron/SUI | 签署原始交易字节 |
exportPrivateKey | 任意 | 导出私钥 |
* | 任意 | 通配符 — 匹配所有方法 |
注意:personal_sign(消息签名)和 signMessage(Solana)不是有效的策略方法,无法单独允许或拒绝。若要允许消息签名,请使用 * 通配符。在默认拒绝(规则为空)时,消息签名也会被阻止。
条件对象
{
"field_source": "<source>",
"field": "<field_name>",
"operator": "<op>",
"value": "<string>" | ["<string>", ...]
}
运算符:
eq— 等于(单个值)gt、gte、lt、lte— 比较运算符(数值字符串)in— 匹配数组中的任意值(最多 100 个值)。多个地址/值请使用此运算符。
请勿使用 in_condition_set:
in_condition_set— 此运算符需要通过 Privy API 预先创建条件集,而你无法创建这些条件集。对于地址或值数组,请始终使用in运算符。如果需要超过 100 个值,请拆分为多条规则。
示例:
// ✅ CORRECT: Multiple addresses with "in" operator
{"field": "to", "operator": "in", "value": ["0xAddr1...", "0xAddr2...", "0xAddr3..."]}
// ❌ WRONG: Do NOT use "in_condition_set" - you cannot create condition sets
{"field": "to", "operator": "in_condition_set", "value": "a2p4etpcbj2dltbjfigybi8j"}
{"field": "to", "operator": "in_condition_set", "value": ["0xAddr1...", "0xAddr2..."]}
// ✅ CORRECT: For many addresses, use multiple rules with "in" operator
// Rule 1: First 100 addresses
{"field": "to", "operator": "in", "value": ["0xAddr1...", "0xAddr2...", /* ... 100 addresses */]}
// Rule 2: Next batch
{"field": "to", "operator": "in", "value": ["0xAddr101...", "0xAddr102...", /* ... */]}
条件类型参考
1. ethereum_transaction
字段:to、value、chain_id
{"field_source": "ethereum_transaction", "field": "to", "operator": "eq", "value": "0xAbC..."}
{"field_source": "ethereum_transaction", "field": "value", "operator": "lte", "value": "1000000000000000000"}
{"field_source": "ethereum_transaction", "field": "chain_id", "operator": "in", "value": ["1", "8453", "10"]}
value的单位是 wei(字符串)。1 ETH ="1000000000000000000"chain_id是字符串(例如,主网为"1",Base 为"8453")to是校验和地址
2. ethereum_calldata
用于已解码的智能合约调用。需要 abi 字段。
{
"field_source": "ethereum_calldata",
"field": "transfer.to",
"operator": "eq",
"value": "0xRecipient...",
"abi": {
"type": "function",
"name": "transfer",
"inputs": [
{"name": "to", "type": "address"},
{"name": "amount", "type": "uint256"}
]
}
}
字段格式:<functionName>.<paramName> — 引用已解码的参数。
3. ethereum_typed_data_domain
字段:chainId、verifyingContract
{"field_source": "ethereum_typed_data_domain", "field": "verifyingContract", "operator": "eq", "value": "0xContract..."}
{"field_source": "ethereum_typed_data_domain", "field": "chainId", "operator": "eq", "value": "1"}
4. ethereum_typed_data_message
用于 EIP-712 消息字段。需要 typed_data 描述符。
{
"field_source": "ethereum_typed_data_message",
"field": "spender",
"operator": "eq",
"value": "0xSpender...",
"typed_data": {
"types": {
"Permit": [
{"name": "owner", "type": "address"},
{"name": "spender", "type": "address"},
{"name": "value", "type": "uint256"}
]
},
"primary_type": "Permit"
}
}
5. ethereum_7702_authorization
字段:contract
{"field_source": "ethereum_7702_authorization", "field": "contract", "operator": "in", "value": ["0xA...", "0xB..."]}
6. solana_program_instruction
字段:programId
{"field_source": "solana_program_instruction", "field": "programId", "operator": "eq", "value": "11111111111111111111111111111111"}
{"field_source": "solana_program_instruction", "field": "programId", "operator": "in", "value": ["11111111111111111111111111111111", "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"]}
7. solana_system_program_instruction
字段:instructionName、Transfer.from、Transfer.to、Transfer.lamports
{"field_source": "solana_system_program_instruction", "field": "instructionName", "operator": "eq", "value": "Transfer"}
{"field_source": "solana_system_program_instruction", "field": "Transfer.to", "operator": "eq", "value": "RecipientPubkey..."}
{"field_source": "solana_system_program_instruction", "field": "Transfer.lamports", "operator": "lte", "value": "1000000000"}
lamports是字符串。1 SOL ="1000000000"(10^9)
8. solana_token_program_instruction
字段:instructionName、TransferChecked.source、TransferChecked.destination、TransferChecked.authority、TransferChecked.amount、TransferChecked.mint
{"field_source": "solana_token_program_instruction", "field": "instructionName", "operator": "eq", "value": "TransferChecked"}
{"field_source": "solana_token_program_instruction", "field": "TransferChecked.mint", "operator": "eq", "value": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"}
{"field_source": "solana_token_program_instruction", "field": "TransferChecked.amount", "operator": "lte", "value": "1000000"}
9. system
字段:current_unix_timestamp
{"field_source": "system", "field": "current_unix_timestamp", "operator": "lte", "value": "1735689600"}
用于设置有时间限制的策略(例如,“允许转账直到 2025-01-01”)。
常用策略示例
将以下内容用作构建模块。在一条规则中组合多个条件表示 AND 逻辑。使用多条独立规则表示 OR 逻辑。
EVM:地址允许列表
仅允许向特定地址发送:
{
"name": "Allowlist recipients",
"method": "eth_sendTransaction",
"conditions": [
{"field_source": "ethereum_transaction", "field": "to", "operator": "in", "value": ["0xAddr1...", "0xAddr2..."]}
],
"action": "ALLOW"
}
EVM:转账金额上限
允许转账金额不超过 0.1 ETH:
{
"name": "Max 0.1 ETH per tx",
"method": "eth_sendTransaction",
"conditions": [
{"field_source": "ethereum_transaction", "field": "value", "operator": "lte", "value": "100000000000000000"}
],
"action": "ALLOW"
}
EVM:链限制
仅允许在 Base 和 Ethereum 主网上操作:
{
"name": "Base and mainnet only",
"method": "eth_sendTransaction",
"conditions": [
{"field_source": "ethereum_transaction", "field": "chain_id", "operator": "in", "value": ["1", "8453"]}
],
"action": "ALLOW"
}
EVM:组合 — 允许列表 + 上限 + 链限制
{
"name": "Treasury transfers on Base, max 1 ETH",
"method": "eth_sendTransaction",
"conditions": [
{"field_source": "ethereum_transaction", "field": "to", "operator": "eq", "value": "0xTreasury..."},
{"field_source": "ethereum_transaction", "field": "value", "operator": "lte", "value": "1000000000000000000"},
{"field_source": "ethereum_transaction", "field": "chain_id", "operator": "eq", "value": "8453"}
],
"action": "ALLOW"
}
允许所有操作(包括消息签名)
personal_sign 和 signMessage 不是有效的策略方法。使用 * 通配符即可允许这些操作。结合特定的 DENY 规则,以限制危险操作。
{
"name": "Allow all operations",
"method": "*",
"conditions": [],
"action": "ALLOW"
}
典型模式:先 DENY 危险方法,再对其余方法执行 ALLOW *:
[
{"name": "Block key export", "method": "exportPrivateKey", "conditions": [], "action": "DENY"},
{"name": "Allow everything else", "method": "*", "conditions": [], "action": "ALLOW"}
]
EVM:Base 上的 USDC 合约
{
"name": "Allow USDC on Base",
"method": "eth_sendTransaction",
"conditions": [
{"field_source": "ethereum_transaction", "field": "to", "operator": "eq", "value": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"},
{"field_source": "ethereum_transaction", "field": "chain_id", "operator": "eq", "value": "8453"}
],
"action": "ALLOW"
}
EVM:禁止导出私钥
{
"name": "Never export private key",
"method": "exportPrivateKey",
"conditions": [],
"action": "DENY"
}
EVM:限时访问
允许转账直至指定日期:
{
"name": "Allow until 2025-06-01",
"method": "eth_sendTransaction",
"conditions": [
{"field_source": "system", "field": "current_unix_timestamp", "operator": "lte", "value": "1748736000"}
],
"action": "ALLOW"
}
Solana:SOL 转账允许列表
{
"name": "Allow SOL to treasury",
"method": "signAndSendTransaction",
"conditions": [
{"field_source": "solana_system_program_instruction", "field": "instructionName", "operator": "eq", "value": "Transfer"},
{"field_source": "solana_system_program_instruction", "field": "Transfer.to", "operator": "eq", "value": "TreasuryPubkey..."}
],
"action": "ALLOW"
}
Solana:SOL 转账上限
{
"name": "Max 1 SOL per tx",
"method": "signAndSendTransaction",
"conditions": [
{"field_source": "solana_system_program_instruction", "field": "instructionName", "operator": "eq", "value": "Transfer"},
{"field_source": "solana_system_program_instruction", "field": "Transfer.lamports", "operator": "lte", "value": "1000000000"}
],
"action": "ALLOW"
}
Solana:SPL 代币(USDC)允许列表
{
"name": "Allow USDC transfers to recipient",
"method": "signAndSendTransaction",
"conditions": [
{"field_source": "solana_token_program_instruction", "field": "instructionName", "operator": "eq", "value": "TransferChecked"},
{"field_source": "solana_token_program_instruction", "field": "TransferChecked.mint", "operator": "eq", "value": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"},
{"field_source": "solana_token_program_instruction", "field": "TransferChecked.destination", "operator": "eq", "value": "RecipientATA..."}
],
"action": "ALLOW"
}
Solana:程序允许列表
仅允许与特定程序交互:
{
"name": "Allow System and Token programs only",
"method": "signAndSendTransaction",
"conditions": [
{"field_source": "solana_program_instruction", "field": "programId", "operator": "in", "value": [
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
]}
],
"action": "ALLOW"
}
自定义限制模式
仅当用户明确要求更严格的限制时才使用这些模式。根据用户需求调整合约地址和 chain_id。
特定合约模式
[
{"name": "Allow <DAPP_NAME>", "method": "eth_sendTransaction", "conditions": [
{"field_source": "ethereum_transaction", "field": "to", "operator": "eq", "value": "<CONTRACT_ADDRESS>"},
{"field_source": "ethereum_transaction", "field": "chain_id", "operator": "eq", "value": "<CHAIN_ID>"}
], "action": "ALLOW"},
{"name": "Token approvals on <NETWORK>", "method": "eth_sendTransaction", "conditions": [
{"field_source": "ethereum_transaction", "field": "chain_id", "operator": "eq", "value": "<CHAIN_ID>"},
{"field_source": "ethereum_transaction", "field": "value", "operator": "eq", "value": "0"}
], "action": "ALLOW"},
{"name": "Deny key export", "method": "exportPrivateKey", "conditions": [], "action": "DENY"}
]
限定链模式
[
{"name": "Allow tx on <NETWORK>", "method": "eth_sendTransaction", "conditions": [
{"field_source": "ethereum_transaction", "field": "chain_id", "operator": "eq", "value": "<CHAIN_ID>"}
], "action": "ALLOW"},
{"name": "Allow signing on <NETWORK>", "method": "eth_signTypedData_v4", "conditions": [
{"field_source": "ethereum_typed_data_domain", "field": "chainId", "operator": "eq", "value": "<CHAIN_ID>"}
], "action": "ALLOW"},
{"name": "Deny key export", "method": "exportPrivateKey", "conditions": [], "action": "DENY"}
]
Wei / Lamports 速查
EVM(wei)
| 金额 | Wei 字符串 |
|---|---|
| 0.001 ETH | "1000000000000000" |
| 0.01 ETH | "10000000000000000" |
| 0.1 ETH | "100000000000000000" |
| 1 ETH | "1000000000000000000" |
| 10 ETH | "10000000000000000000" |
公式:wei = eth * 10^18
Solana(lamports)
| 金额 | Lamports 字符串 |
|---|---|
| 0.001 SOL | "1000000" |
| 0.01 SOL | "10000000" |
| 0.1 SOL | "100000000" |
| 1 SOL | "1000000000" |
| 10 SOL | "10000000000" |
公式:lamports = sol * 10^9
USDC(6 位小数位数——EVM 和 Solana 相同)
| 金额 | 原始字符串 |
|---|---|
| 1 USDC | "1000000" |
| 100 USDC | "100000000" |
| 1000 USDC | "1000000000" |
链 ID(EVM)
| 链 | ID(条件中的字符串) |
|---|---|
| Ethereum 主网 | "1" |
| Ethereum Sepolia | "11155111" |
| Base | "8453" |
| Optimism | "10" |
| Arbitrum One | "42161" |
| Polygon | "137" |
| BSC | "56" |
常见 Solana 程序 ID
| 程序 | ID |
|---|---|
| System Program | 11111111111111111111111111111111 |
| Token Program | TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA |
| Token-2022 | TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb |
| Associated Token | ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL |
| USDC Mint | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
交互指南
- 先询问链 — 确定用户需要 EVM、Solana 还是两者的策略。
- 确认地址 — 如果用户说“允许向我的朋友转账”,请询问地址。
- 确认金额 — 在输出中将用户易读的金额(例如“1 ETH”)转换为 wei/lamports。
- 说明权衡 — 如果策略过于宽松,请提醒用户;如果过于严格,请指出会阻止哪些操作。
- 合理组合 — 在一条规则中使用多个条件表示 AND,使用多条规则表示 OR。
- 始终包含 deny-export — 除非用户明确需要导出密钥,否则建议添加
DENY exportPrivateKey规则。 - 输出有效 JSON — 每个
json:policy块都必须是有效且可解析的 JSON。仔细检查地址和值。 - 规则名称 ≤ 50 个字符 — Privy API 对规则名称设有 50 个字符的上限。绝不要在规则名称中包含完整的链上地址。使用简短且具有描述性的名称,例如
"Allowlist recipients"、"Max 0.1 ETH per tx"或"Allow SOL to treasury"。如果需要引用地址,请缩写(例如0xba86...BE6E)。
请勿
- 请勿将策略规则输出为代码块或纯文本——始终调用
wallet_propose_policy - 请勿向规则添加额外字段(仅限:name、method、conditions、action)
- 请勿向条件添加额外字段(仅限:field_source、field、operator、value,以及必要时的 abi/typed_data)
- 请勿将 Solana field_sources(solana_*)与 chain_type="ethereum" 搭配使用,反之亦然
- 请勿使用小写的 action 值——始终使用 "ALLOW" 或 "DENY"
- 请勿将
ethereum_transaction或ethereum_calldatafield_sources 与eth_signTypedData_v4搭配使用——请改用ethereum_typed_data_domain或ethereum_typed_data_message - 请勿将
ethereum_transactionfield_sources 与eth_sign7702Authorization搭配使用——请改用ethereum_7702_authorization - 除非用户明确要求更严格的限制,否则请勿为服务使用自定义限制规则——默认使用通配符策略