Documentation Index Fetch the complete documentation index at: https://cobo.com/products/agentic-wallet/manual/llms.txt
Use this file to discover all available pages before exploring further.
Every pact submission includes two top-level JSON arrays:
{
"completion_conditions" : [ ... ],
"policies" : [ ... ]
}
Completion conditions define when the pact automatically ends — time elapsed, transactions executed, or amount spent. The pact is revoked as soon as any one condition is met.
Policies define what the agent is allowed to do while the pact is active — which chains, tokens, contracts, or message types are permitted, and what limits apply.
Completion conditions
Completion conditions determine when a pact automatically ends. At least one is required. The pact completes when any condition is satisfied, after which access is revoked immediately. Types cannot be duplicated within a pact.
Type Threshold Description tx_countstring (integer) Complete after N successful transactions — e.g. "1" for a one-time operation amount_spentstring (decimal) Complete after cumulative token amount reaches this — e.g. "1000" for 1000 USDC amount_spent_usdstring (decimal) Complete after cumulative USD spend reaches this — e.g. "500" time_elapsedstring (seconds) Complete after N seconds from pact activation — e.g. "2592000" for 30 days
[
{ "type" : "tx_count" , "threshold" : "12" },
{ "type" : "time_elapsed" , "threshold" : "7776000" }
]
This pact ends after 12 transactions or 90 days, whichever comes first.
Policies
Policies are the rules that constrain what an agent can do within a pact. Every operation the runtime submits is evaluated against the policies you define.
How the engine works
The policy engine evaluates every operation against all applicable policies and outputs one of three decisions: allow , require_approval , or deny .
Evaluation order (within a policy)
Match when conditions — if not matched, the policy is skipped
Check deny_if — if hit, deny immediately
Check review_if / always_review — if hit, pause for owner approval
Otherwise, allow
Default-deny semantics
Pact-level policies use fail-closed semantics: if the operation does not match any policy’s when conditions, it is automatically denied. Every operation the agent needs to perform must be explicitly covered by a policy.
Final decision
When multiple policies apply:
Any deny → deny
No deny, but any review triggered → require_approval
Otherwise → allow
Policy structure
Each policy in the policies array has this shape:
{
"name" : "<human-readable name>" ,
"type" : "transfer | contract_call | message_sign" ,
"rules" : {
"effect" : "allow" ,
"when" : { ... },
"deny_if" : { ... },
"review_if" : { ... },
"always_review" : true | false
}
}
Field Required Description nameYes Human-readable label for this policy typeYes Operation type: transfer, contract_call, or message_sign rules.effectYes Always "allow" for pact-level policies rules.whenYes (unless always_review: true) Allowlist conditions — which chains, tokens, or contracts are permitted rules.deny_ifNo Hard-block conditions — operations that exceed these limits are denied rules.review_ifNo Soft-block conditions — operations exceeding these thresholds pause for owner approval rules.always_reviewNo When true, every matched operation requires owner approval
Constraints:
deny_if takes priority over review_if / always_review
deny effect policies cannot have review_if or always_review
allow + review_if requires a non-empty when
allow requires either a non-empty when or always_review: true
Transfer policies
Use "type": "transfer" to control token transfers.
when — allowlist conditions
All fields are AND conditions. All specified fields must match.
Field Type Description chain_instring[]Restrict to specific chains, e.g. ["BASE_ETH", "ETH"] token_inChainTokenRef[]Restrict to specific tokens — [{"chain_id": "BASE_ETH", "token_id": "BASE_USDC"}] destination_address_inChainAddressRef[]Restrict to specific destination addresses — [{"chain_id": "BASE_ETH", "address": "0x..."}]
deny_if — hard-block limits
Field Type Description amount_gtstring (decimal) Deny if a single transfer’s token amount exceeds this amount_usd_gtstring (decimal) Deny if a single transfer’s USD value exceeds this usage_limits.rolling_1hobject Rolling 1-hour window limits usage_limits.rolling_24hobject Rolling 24-hour window limits usage_limits.rolling_7dobject Rolling 7-day window limits usage_limits.rolling_30dobject Rolling 30-day window limits
Each rolling window supports: amount_gt, amount_usd_gt, tx_count_gt.
review_if — approval thresholds
Supports the same fields as when (chain_in, token_in, destination_address_in), plus:
Field Type Description amount_gtstring (decimal) Require approval if token amount exceeds this amount_usd_gtstring (decimal) Require approval if USD value exceeds this
Examples
Allowlist by chain and token
Spend cap with approval threshold
Rolling window limits
Always require approval
{
"name" : "usdc-on-base" ,
"type" : "transfer" ,
"rules" : {
"effect" : "allow" ,
"when" : {
"chain_in" : [ "BASE_ETH" ],
"token_in" : [{ "chain_id" : "BASE_ETH" , "token_id" : "BASE_USDC" }]
}
}
}
Contract call policies
Use "type": "contract_call" to control smart contract interactions. EVM and Solana use different target fields.
when — allowlist conditions (EVM)
Field Type Description chain_instring[]Restrict to specific chains target_inContractTargetRef[]Allowlist by contract address and optionally function selector — [{"chain_id": "SETH", "contract_addr": "0x...", "function_id": "0x38ed1739"}]. Omit function_id to allow all functions on the contract. params_matchParamMatchRule[]Match on decoded calldata parameters (EVM only — requires function_abis)
when — allowlist conditions (Solana)
Field Type Description chain_instring[]Restrict to specific chains program_inProgramRef[]Allow if the transaction involves any of the listed programs program_all_inProgramRef[]Allow only if the transaction involves all of the listed programs
params_match rule
Used to match on decoded function parameters. Requires function_abis to be set.
Field Type Description param_namestring Parameter name as defined in the ABI opstring eq, neq, in, not_in, gt, gte, lt, ltevalueany Value to compare against
params_match is only supported on EVM chains. Multiple rules are AND conditions.
function_abis
Required when using params_match. Provide the ABI fragment for each function selector you reference:
"function_abis" : [
{
"type" : "function" ,
"selector" : "0x38ed1739" ,
"inputs" : [
{ "name" : "amountIn" , "type" : "uint256" },
{ "name" : "recipient" , "type" : "address" }
]
}
]
deny_if — hard-block limits
Field Type Description amount_gtstring Deny if the operation’s native value exceeds this amount_usd_gtstring Deny if the USD value exceeds this usage_limitsobject Same rolling window structure as transfer (rolling_1h, rolling_24h, rolling_7d, rolling_30d), each supporting amount_gt, amount_usd_gt, tx_count_gt
review_if — approval thresholds
Supports the same fields as when (chain_in, target_in, program_in, params_match), plus amount_gt and amount_usd_gt.
Examples
EVM contract allowlist
Function selector + param matching
Solana program allowlist
{
"name" : "uniswap-swap" ,
"type" : "contract_call" ,
"rules" : {
"effect" : "allow" ,
"when" : {
"chain_in" : [ "BASE_ETH" ],
"target_in" : [{ "chain_id" : "BASE_ETH" , "contract_addr" : "0x2626664c2603336E57B271c5C0b26F421741e481" }]
},
"deny_if" : {
"usage_limits" : { "rolling_24h" : { "tx_count_gt" : 5 }}
}
}
}
Message sign policies
Use "type": "message_sign" to control EIP-712 typed-data signing. There are no amount_gt / amount_usd_gt fields — rate limits use request_count_gt instead.
when — allowlist conditions
Field Type Description chain_instring[]Restrict to specific chains primary_type_instring[]Match on the EIP-712 primaryType field, e.g. ["PermitSingle", "PermitBatch"] source_address_inChainAddressRef[]Restrict to specific signing addresses. EVM: case-insensitive. Solana: case-sensitive. domain_matchMatchRule[]Match on EIP-712 domain fields message_matchMatchRule[]Match on EIP-712 message fields
All when fields are AND conditions.
Path syntax for domain_match and message_match
Use dot notation to address nested fields:
Syntax Meaning Example .Nested field details.spender[N]Array index (0-based) path[0].tokenIn*All array elements items.*.token.lengthArray length transfers.length
Wildcard semantics — for multi-value paths like items.*.token:
eq, in, gt, gte, lt, lte: matches if any element satisfies the condition
neq, not_in: matches only if all elements satisfy the condition
Supported operators: eq, neq, in, not_in, gt, gte, lt, lte
Path resolution failures
When a path cannot be resolved, the rule does not match:
Situation Result Intermediate field missing or null No match * applied to a non-arrayNo match [N] index out of boundsNo match .length applied to a non-arrayNo match Empty array + eq, in, gt, gte, lt, lte false (no match)Empty array + neq, not_in true (matches)
deny_if — rate limits
Field Type Description usage_limits.rolling_1h.request_count_gtinteger Deny if signing requests in the past hour exceed this usage_limits.rolling_24h.request_count_gtinteger Deny if signing requests in the past 24h exceed this usage_limits.rolling_7d.request_count_gtinteger Deny if signing requests in the past 7 days exceed this usage_limits.rolling_30d.request_count_gtinteger Deny if signing requests in the past 30 days exceed this
review_if — approval thresholds
Supports the same fields as when (chain_in, primary_type_in, source_address_in, domain_match, message_match).
Chain ID validation
For EVM chains, the engine checks that the request chain_id matches domain.chainId in the typed data. A mismatch results in an immediate deny with reason eip712_domain_chain_id_mismatch.
Examples
Permit2 — restrict spender and token
Always require approval
Limit batch size
{
"name" : "permit2-allowlist" ,
"type" : "message_sign" ,
"rules" : {
"effect" : "allow" ,
"when" : {
"chain_in" : [ "SETH" ],
"primary_type_in" : [ "PermitSingle" , "PermitBatch" ],
"domain_match" : [
{ "param_name" : "name" , "op" : "eq" , "value" : "Permit2" },
{ "param_name" : "verifyingContract" , "op" : "eq" , "value" : "0x000000000022d473030f116ddee9f6b43ac78ba3" }
],
"message_match" : [
{ "param_name" : "details.spender" , "op" : "in" , "value" : [ "0xabc..." , "0xdef..." ]},
{ "param_name" : "details.token" , "op" : "in" , "value" : [ "0x111..." , "0x222..." ]}
]
},
"review_if" : {
"message_match" : [
{ "param_name" : "details.amount" , "op" : "gt" , "value" : "1000000000000000000" }
]
},
"deny_if" : {
"usage_limits" : {
"rolling_1h" : { "request_count_gt" : 10 },
"rolling_24h" : { "request_count_gt" : 100 }
}
}
}
}
Amount units
amount_gt, amount_spent, and related fields use the token’s transfer unit — the same unit passed when submitting a transfer:
"1.5" for USDC means 1.5 USDC (not 1,500,000 micro-USDC)
"0.01" for ETH means 0.01 ETH (not wei)
USD-based conditions (amount_usd_gt, amount_spent_usd) only apply to tokens with available price data. For tokens without price data, use token-denominated limits (amount_gt, amount_spent) instead.