Privy’s policy engine allows your application to restrict the actions that can be taken with server wallets.

Policies enable you to configure:

  • Transfer limits
  • Allow lists and deny lists of transfer recipients
  • Allow lists and deny lists of smart contracts and programs
  • Constraints around calldata that can be passed to smart contracts

This ensures that server wallets can only ever be used to take actions your application intends to take.

Concepts

Policies are defined by three core primitives: policies, rules, and conditions. At a high-level:

  • Policies are a list of rules that define the total set of actions that are allowed or denied for a server wallet.
  • Rules are a set of conditions, such that if a request satisfies all of the conditions in a rule, the policy engine executes the action (ALLOW or DENY) prescribed by the rule.
  • Conditions are boolean statements that the policy engine can evaluate RPC requests against.

You can create and manage policies through the Privy Dashboard, nodeJS SDK, or via the REST API.

Policies

A policy is composed from a list of rules for each RPC method that a wallet can execute that define what actions are allowed or denied for the wallet. DENY actions take precedence over ALLOW actions. If no rules resolve, the policy will default to DENY.

Policy objects have the following properties:

Policy evaluation

When your application makes an RPC request on a wallet that has a policy, the policy engine evaluates the rules that are associated with the requested RPC method.

For instance, if your application makes an 'eth_signTransaction' request, the policy engine will only evalaute rules associated with the 'eth_signTransaction' method in the policy.

The rules are evaluated as follows:

  1. If any rule evaluates to a DENY action, the policy engine will DENY the request.
  2. If any rule evaluates to an ALLOW action, and no rules evaluate to DENY, then the policy engine will ALLOW the request.

If the request does not satisfy any of the rules for the policy, the policy engine defaults to DENY the request.

This also applies to Solana transactions such that every Instruction in a Solana transaction is evaluated against the rules of the policy. Every instruction must evaluate to an ALLOW action for the transaction to be allowed.

If your application makes a request to a server wallet with RPC method X, and the policy’s rules contains no entry with a method corresponding to X, the engine will deny the request by default. If you’d like the policy engine to instead allow requests for RPC method X by default, we recommend setting up an “Allow all” Rule for that RPC method like so.

Rules

The nested Rule object within the policy’s rules array. A rule is composed of an set of boolean conditions and an action (ALLOW or DENY) that is taken if an RPC request satisfies all of the conditions in the rule. Rule objects have the following fields:

Each rule corresponds to an individual action that should be allowed or denied by a server wallet. For example, you might configure rules for a policy to:

  • ALLOW transfers of the native token to a set of allowlisted recipient addresses
  • DENY interactions with specific Ethereum smart contracts or Solana programs

Conditions

A condition is a boolean statement about a wallet request. When evaluating a wallet request against a rule, the policy engine checks whether the wallet request satisfies each of the boolean conditions in the rule. If all of the conditions are satisfied, the engine executes the action associated with the rule.

Conditions allow you to define specific action types that should be allowed or denied for a server wallet.

Conditions for certain sources may have additional parameters. For instance, ethereum_calldata conditions also require an abi parameter used to decode the calldata, and ethereum_typed_data_message conditions require a typed_data parameter to define the schema for the typed data message.

Field

Fields are attributes of a wallet request that can be parsed or interpreted from the wallet request. Examples of fields include the to parameter of an EVM transaction, the fee_payer parameter of a Solana transaction, or an spl_transfer_recipient field that is populated when the policy engine interprets a transaction.

Fields are derived from field sources, which surface data from the wallet request. Possible field sources are listed below.

Field sourceDescriptionExample fields
'ethereum_transaction'The verbatim Ethereum transaction object in an eth_signTransaction or eth_sendTransaction request.to, chain_id, value.
'ethereum_calldata'The decoded calldata in a smart contract interaction as the smart contract method’s parameters. Note that that 'ethereum_calldata' conditions must contain an abi parameter with the JSON ABI of the smart contractfunction_name, _to, _value (for a ERC20 interaction)
'ethereum_typed_data_domain'Attributes from the signing domain that will verify the signature.chainId, verifyingContract
'ethereum_typed_data_message'types and primary_type attributes of the TypedData JSON object defined in EIP-712.dot-separated path to value in message object, i.e. to.wallet
'solana_program_instruction'Solana program instruction from a signTransaction or signAndSendTransaction request.programId
'solana_system_program_instruction'Fields relevant to the Solana System Program and its Transfer instruction.instructionName, Transfer.to, Transfer.from, Transfer.lamports
'solana_token_program_instruction'Fields relevant to the SPL Token Program and its Transfer instruction.instructionName, Transfer.source, Transfer.destination, Transfer.authority, Transfer.amount

Operator

Operators are boolean operators used to compare fields and values. Operators include eq, neq, lt, lte, gt, gte, in.

Values

A condition compares a field using its boolean operator to a static value. As an example, if a condition determines whether an Ethereum transaction has specific recipient address X, the value for the condition is X.