Policies provide fine-grained control over what operations accounts can perform. You can restrict transactions by network, address, value, message content, and more. Policies can be applied at the project level (affecting all accounts) or at the account level (affecting specific accounts).
Policy Scopes
- Project policies: Apply to all accounts in your project
- Account policies: Apply to specific individual accounts
Creating a Policy
Define policy rules
Create a policy with rules for different operations:import { CdpClient } from "@coinbase/cdp-sdk";
const cdp = new CdpClient();
const policy = await cdp.policies.createPolicy({
policy: {
scope: "account",
description: "EVM Transaction Allowlist",
rules: [
{
action: "accept",
operation: "sendEvmTransaction",
criteria: [
{
type: "evmNetwork",
networks: ["base-sepolia", "base"],
operator: "in"
}
]
},
{
action: "accept",
operation: "signEvmTransaction",
criteria: [
{
type: "ethValue",
ethValue: "1000000000000000000", // 1 ETH in wei
operator: "<="
},
{
type: "evmAddress",
addresses: ["0x1234567890123456789012345678901234567890"],
operator: "in"
}
]
}
]
}
});
console.log(`Created policy: ${policy.id}`);
from cdp import CdpClient
from cdp.policies.types import (
CreatePolicyOptions,
EthValueCriterion,
EvmAddressCriterion,
EvmNetworkCriterion,
SendEvmTransactionRule,
SignEvmTransactionRule,
)
async with CdpClient() as cdp:
policy = await cdp.policies.create_policy(
policy=CreatePolicyOptions(
scope="account",
description="EVM Transaction Allowlist",
rules=[
SendEvmTransactionRule(
action="accept",
criteria=[
EvmNetworkCriterion(
networks=["base-sepolia", "base"],
operator="in",
),
],
),
SignEvmTransactionRule(
action="accept",
criteria=[
EthValueCriterion(
ethValue="1000000000000000000",
operator="<=",
),
EvmAddressCriterion(
addresses=["0x1234567890123456789012345678901234567890"],
operator="in",
),
],
),
],
)
)
print(f"Created policy: {policy.id}")
Apply policy to an account
Apply the policy when creating an account:const account = await cdp.evm.createAccount({
name: "RestrictedAccount",
accountPolicy: policy.id
});
account = await cdp.evm.create_account(
name="RestrictedAccount",
account_policy=policy.id
)
Or apply to an existing account:const updated = await cdp.evm.updateAccount({
address: account.address,
accountPolicy: policy.id
});
from cdp.update_account_types import UpdateAccountOptions
updated = await cdp.evm.update_account(
address=account.address,
options=UpdateAccountOptions(account_policy=policy.id)
)
Policy Operations
Policies can control the following operations:
EVM Operations
- sendEvmTransaction: Sending transactions via CDP
- signEvmTransaction: Signing transaction objects
- signEvmHash: Signing raw hashes
- signEvmMessage: Signing EIP-191 messages
- signEvmTypedData: Signing EIP-712 typed data
- sendEvmUserOperation: Sending ERC-4337 user operations
Solana Operations
- signSolanaTransaction: Signing Solana transactions
- signSolanaMessage: Signing Solana messages
Policy Criteria
EVM Network Criterion
Restrict operations to specific networks:
{
type: "evmNetwork",
networks: ["base", "base-sepolia", "ethereum"],
operator: "in" // or "not in"
}
EvmNetworkCriterion(
networks=["base", "base-sepolia", "ethereum"],
operator="in" # or "not in"
)
EVM Address Criterion
Restrict operations to specific addresses:
{
type: "evmAddress",
addresses: [
"0x1234567890123456789012345678901234567890",
"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
],
operator: "in" // or "not in"
}
EvmAddressCriterion(
addresses=[
"0x1234567890123456789012345678901234567890",
"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
],
operator="in" # or "not in"
)
ETH Value Criterion
Limit transaction values:
{
type: "ethValue",
ethValue: "1000000000000000000", // 1 ETH in wei
operator: "<=" // or "<", ">", ">=", "==", "!="
}
EthValueCriterion(
ethValue="1000000000000000000", # 1 ETH in wei
operator="<=" # or "<", ">", ">=", "==", "!="
)
EVM Message Criterion
Restrict messages by regex pattern:
{
type: "evmMessage",
match: "^Welcome.*" // Regex pattern
}
EvmMessageCriterion(
match="^Welcome.*" # Regex pattern
)
Solana Address Criterion
Restrict Solana operations to specific addresses:
{
type: "solanaAddress",
addresses: ["9aE4FvpEqMj3K4cZKXXCHwDr9FQZyH2yZ8xF5Cz7T3v2"],
operator: "in"
}
SolanaAddressCriterion(
addresses=["9aE4FvpEqMj3K4cZKXXCHwDr9FQZyH2yZ8xF5Cz7T3v2"],
operator="in"
)
Common Policy Examples
Spend Limit Policy
Limit daily spending:
const policy = await cdp.policies.createPolicy({
policy: {
scope: "account",
description: "Daily Spend Limit",
rules: [
{
action: "accept",
operation: "signEvmTransaction",
criteria: [
{
type: "ethValue",
ethValue: "100000000000000000", // 0.1 ETH
operator: "<="
}
]
},
{
action: "reject",
operation: "signEvmTransaction",
criteria: [
{
type: "ethValue",
ethValue: "100000000000000000",
operator: ">"
}
]
}
]
}
});
Address Allowlist
Only allow transactions to specific addresses:
const policy = await cdp.policies.createPolicy({
policy: {
scope: "account",
description: "Approved Recipients Only",
rules: [
{
action: "accept",
operation: "signEvmTransaction",
criteria: [
{
type: "evmAddress",
addresses: [
"0xApprovedAddress1...",
"0xApprovedAddress2...",
"0xApprovedAddress3..."
],
operator: "in"
}
]
},
{
action: "reject",
operation: "signEvmTransaction",
criteria: [
{
type: "evmAddress",
addresses: [
"0xApprovedAddress1...",
"0xApprovedAddress2...",
"0xApprovedAddress3..."
],
operator: "not in"
}
]
}
]
}
});
Network Restriction
Only allow operations on testnet:
const policy = await cdp.policies.createPolicy({
policy: {
scope: "project",
description: "Testnet Only",
rules: [
{
action: "accept",
operation: "sendEvmTransaction",
criteria: [
{
type: "evmNetwork",
networks: [
"base-sepolia",
"ethereum-sepolia",
"optimism-sepolia"
],
operator: "in"
}
]
},
{
action: "reject",
operation: "sendEvmTransaction",
criteria: [
{
type: "evmNetwork",
networks: ["base", "ethereum", "optimism"],
operator: "in"
}
]
}
]
}
});
Updating Policies
Update an existing policy:
const updatedPolicy = await cdp.policies.updatePolicy({
id: policy.id,
policy: {
description: "Updated Policy Description",
rules: [
{
action: "accept",
operation: "signEvmTransaction",
criteria: [
{
type: "ethValue",
ethValue: "2000000000000000000", // Updated to 2 ETH
operator: "<="
}
]
}
]
}
});
console.log(`Updated policy: ${updatedPolicy.id}`);
from cdp.policies.types import (
UpdatePolicyOptions,
SignEvmTransactionRule,
EthValueCriterion,
)
updated_policy = await cdp.policies.update_policy(
id=policy.id,
policy=UpdatePolicyOptions(
description="Updated Policy Description",
rules=[
SignEvmTransactionRule(
action="accept",
criteria=[
EthValueCriterion(
ethValue="2000000000000000000", # Updated to 2 ETH
operator="<=",
),
],
),
],
),
)
print(f"Updated policy: {updated_policy.id}")
Listing Policies
List All Policies
const response = await cdp.policies.listPolicies({
pageSize: 50,
pageToken: "optional-token"
});
for (const policy of response.policies) {
console.log(`${policy.id}: ${policy.description}`);
}
response = await cdp.policies.list_policies(
page_size=50,
page_token="optional-token"
)
for policy in response.policies:
print(f"{policy.id}: {policy.description}")
List Account Policies
const response = await cdp.policies.listAccountPolicies({
scope: "account"
});
response = await cdp.policies.list_policies(scope="account")
List Project Policies
const response = await cdp.policies.listProjectPolicies({
scope: "project"
});
response = await cdp.policies.list_policies(scope="project")
Getting a Policy by ID
const policy = await cdp.policies.getPolicyById({
id: "pol_abc123..."
});
console.log(`Policy: ${policy.description}`);
console.log(`Scope: ${policy.scope}`);
console.log(`Rules: ${JSON.stringify(policy.rules, null, 2)}`);
policy = await cdp.policies.get_policy_by_id(id="pol_abc123...")
print(f"Policy: {policy.description}")
print(f"Scope: {policy.scope}")
print(f"Rules: {policy.rules}")
Deleting Policies
await cdp.policies.deletePolicy({
id: policy.id
});
console.log("Policy deleted");
await cdp.policies.delete_policy(id=policy.id)
print("Policy deleted")
Deleting a policy does not automatically remove it from accounts. Update accounts to remove the policy first.
Removing Policies from Accounts
const updated = await cdp.evm.updateAccount({
address: account.address,
accountPolicy: null // Remove policy
});
from cdp.update_account_types import UpdateAccountOptions
updated = await cdp.evm.update_account(
address=account.address,
options=UpdateAccountOptions(account_policy=None) # Remove policy
)
Policy Enforcement
When a policy is violated:
- The API returns a
403 Forbidden error
- The error message indicates which policy rule was violated
- The operation is not executed
Example error handling:
try {
await account.transfer({
to: "0x...",
amount: 10000000000000000000n, // 10 ETH
token: "eth",
network: "base"
});
} catch (error: any) {
if (error.status === 403) {
console.log("Transaction blocked by policy:", error.message);
}
throw error;
}
try:
await account.transfer(
to="0x...",
amount=10000000000000000000, # 10 ETH
token="eth",
network="base"
)
except Exception as error:
if hasattr(error, "status") and error.status == 403:
print(f"Transaction blocked by policy: {error}")
raise
Best Practices
- Start with account policies: Use account-level policies for testing before applying project-wide
- Use descriptive names: Make policy descriptions clear and specific
- Test policies thoroughly: Verify policies work as expected before production use
- Combine criteria carefully: Multiple criteria within a rule are AND conditions
- Order matters: Rules are evaluated in order; first matching rule determines the action
- Monitor policy violations: Track policy rejections to identify issues
Troubleshooting
Policy Not Applied
Verify the policy is attached to the account:
const account = await cdp.evm.getAccount({ address: "0x..." });
console.log(`Policies: ${account.policies}`);
Unexpected Policy Rejection
Check the policy rules and criteria:
const policy = await cdp.policies.getPolicyById({ id: "pol_..." });
console.log(JSON.stringify(policy.rules, null, 2));
Policy Update Not Taking Effect
Policy updates are immediate but may require re-fetching the account object.
Next Steps