CDP Wallets support Policies that enable developers to govern account and project behavior. Policies provide flexible configuration for enforcing controls based on transaction parameters such as destination address and transaction value.
A project-level policy will be evaluated first, followed by any account-level policies. Read more technical details on policy evaluation in the API Reference documentation.
Click the Create new policy button to access the JSON editor. The modal will contain a sample policy that you can edit, but you can also use some of the examples below.
Define the policy and click the Create button. If successful, you should see a “Policy created” message.
Refresh the page to see the new policy listed in the Policies dashboard:
Click the View button to edit or delete the policy.
Account level policies should be added to the account programmatically via the SDK.
Copy
Ask AI
import { CdpClient } from "@coinbase/cdp-sdk"; import dotenv from "dotenv"; dotenv.config(); const cdp = new CdpClient(); const account = await cdp.evm.createAccount(); const policyId = "" // Paste the policy ID created on portal. // Update the account to add the account policy. const updatedAccount = await cdp.evm.updateAccount({ address: account.address, update: { accountPolicy: policyId, } }) console.log("Updated account %s with policy: %s", updatedAccount.address, updatedAccount.policies);
The following example demonstrates a policy that allows signing transactions only to specific EVM addresses. Transactions to any address outside of this list will automatically be deleted by the policy engine.
The following example demonstrates a policy that rejects signing transactions to specific EVM addresses. Transactions with to field set to any address outside of this list will be accepted.
In the example above, assume a user sends a sign transaction request with a value of 4000000000000000000 wei (4 ETH) to the address 0x123:
The transaction will be rejected against the first rule, as the address is not in the allowlist. However, the criteria still is not met and the engine will evaluate the transaction against the second rule.
The transaction will be rejected against the second rule, as the value is greater than 2000000000000000000 wei (2 ETH).
In the above example, if a user sends a transaction with a value of 1500000000000000000 wei (1.5 ETH) to the address 0x123:
The transaction will be rejected against the first rule, as the value is greater than 1000000000000000000 wei. However, the criteria still is not met and the engine will continue evaluating the transaction against the second rule.
The transaction matches against the second rule, as the value is less than or equal to 2000000000000000000 wei AND the address is in the allowlist. The transaction will be accepted.
What's the difference?
The primary differences between these two examples are the rule order in which a transaction is evaluated.
The first example checks the allowlist first, and then the transaction limit
This option is more restrictive, as it requires all transactions go to allowlisted addresses first, regardless of their value.
The second example checks the transaction value first, then uses a combined rule to check both the transaction value and the allowlist
This option offers more granular control by allowing small transactions to be signed to any address, but restricts larger transactions to allowlisted addresses only.
The following example demonstrates how to guarantee any attempt to sign a message will conform to a specific template. When composing a regular expression in the match field, any valid re2 regular expression syntax will be accepted.
accept-sign-message-policy.json
Copy
Ask AI
{ "description": "Accept sign message policy", "scope": "project", "rules": [ { "action": "accept", "operation": "signEvmMessage", "criteria": [ { "type": "evmMessage", "match": "^I solemnly swear that I,(.*), am up to no good\.$" } ] } ]}
This policy restricts USDC transactions on the Base network to transfers of 10,000 tokens or less. It applies to both signing and sending transactions to the USDC contract address, using the ERC20 ABI to validate that only transfer function calls with a value parameter under the specified limit are permitted.
The example below demonstrates a policy to prevent fraud by rejecting any attempt to sign a hash (i.e., undefined or arbitrary input data) on behalf of an account.
The following example demonstrates a policy that prevents signing typed data for the zero address. This ensures that typed data signatures cannot be created for invalid or burn addresses.
This policy uses the verifying contract address from the EIP-712 domain to ensure that typed data signatures are not created for the zero address. You can extend this to create an allowlist by using the "in" operator with trusted contract addresses, or a denylist by using "not in" with untrusted addresses.
The following example demonstrates a more advanced policy that validates specific fields within typed data. This policy restricts an arbitrary Payment data type to a specific address, message content, and amount:
This policy uses the evmTypedDataField criterion to inspect the actual data being signed. The evmTypedDataField criterion supports conditions on numerical values, addresses and strings.
Difference between evmTypedDataVerifyingContract and evmTypedDataField
evmTypedDataVerifyingContract: Checks only the verifying contract address in the EIP-712 domain. This is simpler and useful for allowlisting/denylisting contracts.
evmTypedDataField: Allows inspection of the entire typed data structure including types and field values. This enables more complex validations like checking specific field values, ranges, or data types.
The following policy restricts Smart Account operations to USDC transactions on the Base network, with transfers of 10,000 tokens or less. It applies to both prepare and send operations to the USDC contract address, using the ERC20 ABI to validate that only transfer function calls with a value parameter under the specified limit are permitted.