Create a Policy
A policy is a set of rules that can block signing requests. Signing requests include blockchain transactions and requests to sign data, such as EIP-712 typed data. Each stored rule has a scope, conditions, and a BLOCK response. Enabled rules apply cumulatively: if any applicable rule matches, the request is denied.
If policy evaluation completes successfully and no applicable rule returns a BLOCK response, the request can proceed after UWaaS Wallet Manager (UWM) authenticates the caller, authorizes the wallet and key, and validates the signing request.
Define Rule Conditions
A rule combines conditions with all, any, and not. You can nest these groups to define a restriction:
allmatches when every child condition matches.anymatches when at least one child condition matches.notmatches when its child condition does not match.
Define condition groups inline. Named condition references are not supported for UWM signing rules.
A condition leaf specifies a fact, an operator, and a value. Use path to select a nested property from a fact. Higher priority values are evaluated first.
{
"fact": "to_address",
"operator": "in",
"value": ["<blocked-address>"]
}The in operator matches when the fact equals one of the listed values. Use all to combine this condition with an operation condition. Use any when one of several conditions can trigger the restriction.
Operators
| Operator | Use it when |
|---|---|
equal, notEqual |
A scalar fact must equal or differ from a value of the same type. |
in, notIn |
A scalar fact must appear or not appear in a list of values. |
contains, doesNotContain |
An array fact must contain or not contain a value. |
lessThan, lessThanEquals (lessThanInclusive)
|
A numeric fact must be lower than, or lower than or equal to, a numeric value. |
greaterThan, greaterThanEquals (greaterThanInclusive)
|
A numeric fact must be higher than, or higher than or equal to, a numeric value. |
Ordered comparisons on amount, amount_atomic, and native_value_atomic use exact decimal arithmetic on both /evaluate and /internal/v1/authorize.
Use decimal strings for atomic quantities and large thresholds. For example:
{ "fact": "amount_atomic", "operator": "greaterThanEquals", "value": "1000000000000000000" }UWM supplies amount_atomic in base units and does not convert it to token decimals. The amount fact is supported when supplied by a caller of /evaluate; UWM does not add it to the signing facts.
Decimal JSON numbers within the safe numeric range are accepted. Send larger numeric values as strings; larger numeric literals are rejected. The greaterThanInclusive and lessThanInclusive operator names remain supported. The equal and notEqual operators compare values by type. Other facts retain their existing comparison behavior.
Array Decorators
Prefix an operator with a decorator and a colon, such as someFact:equal. Decorators change how the operator handles arrays or its result.
| Decorator | Use it when |
|---|---|
someFact |
At least one item in an array fact matches. |
everyFact |
Every item in an array fact matches. |
someValue |
The fact matches at least one item in an array value. |
everyValue |
The fact matches every item in an array value. |
swap |
The comparison uses the value as the fact and the fact as the value. |
not |
The base operator result must be negated. |
For example, someFact:equal can match one token ID in the token_ids array provided for a decoded ERC-1155 batch call:
{
"fact": "token_ids",
"operator": "someFact:equal",
"value": "42"
}Use the not condition group for Boolean logic and the not: decorator to negate an individual operator. Condition and rule priorities set evaluation order. They do not allow one rule to override another matching BLOCK.
Set the Rule Scope
Set scopelevels and targets to specify which signing requests a rule covers. Every selected scope must match. Targets within one scope are alternatives.
| Scope | Required target | Use it for |
|---|---|---|
global |
None; specify by itself. |
A restriction that applies to every signing request. |
org |
targets.orgIds |
A restriction for one or more organizations. |
wallet |
targets.walletIds |
A restriction for one or more wallets. |
instance |
targets.instanceIds |
A restriction for one or more network instances. |
asset |
targets.assetIds |
Existing asset-scoped rules; retained for compatibility. |
scopelevels: ["org",
"wallet"] requires both the organization and wallet targets to match. A wallet-only rule does not have an implicit organization boundary. Use IDs returned by UWM, not display names.To restrict a contract method, match contract_address and function_selector in the conditions. Add the instance scope if the same method requires different restrictions on different networks. The asset scope is retained for existing rules; these conditions do not require it.
For targets.instanceIds, use the public instanceId shown by UWM's wallet or network API. This is the registered infra_instance_id, not the numeric database key or chain ID. Update older instance-scoped rules that use a database key; UWM now sends only the public instance identifier.
Match the Signing Request
Conditions can use only facts supplied for the request's operation. The operation fact is available for every signing request.
operation |
Additional facts |
|---|---|
native-transfer |
amount_atomic, to_address |
erc20-transfer |
amount_atomic, to_address, contract_address |
contract-deployment |
amount_atomic, init_code_hash |
contract-call |
contract_address, native_value_atomic, function_selector, calldata_hash |
eip712 |
primary_type, verifying_contract, typed_data |
UWM recognizes canonical ERC-20 transfer(address,uint256) calls with zero native value without token registration. UWM no longer reads capability.approved-token-contracts.
The erc20-transfer profile also provides native_value_atomic ("0"), function_selector ("0xa9059cbb"), and calldata_hash. These facts allow existing contract-call rules to retain their full restrictions.
An erc20-transfer operation is also a contract-call for operation conditions. Both rule types can match the same request, and any matching BLOCK denies it. This behavior applies to equal, notEqual, in, notIn, and nested Boolean conditions on both evaluation endpoints. Other facts retain their normal equality semantics.
The erc20-transfer operation matches transfer, not transferFrom or ERC-1155 methods. Always include the intended contract_address in token rules.
Canonical ERC-20 transferFrom, ERC-1155 safeTransferFrom, and ERC-1155 safeBatchTransferFrom calls provide additional contract-call facts:
| Call | Additional facts |
|---|---|
ERC-20 transferFrom |
owner_address, to_address, amount_atomic |
ERC-1155 safeTransferFrom |
owner_address, to_address, token_id, amount_atomic |
ERC-1155 safeBatchTransferFrom |
owner_address, to_address, parallel token_ids and amounts arrays
|
UWM decodes only calls with a supported canonical ABI layout. Other calls retain the generic contract-call facts.
owner_address is the source address in the call data, not the signing wallet. A selector identifies the call-data layout, not the deployed contract's behavior. ERC-20 and ERC-721 share the transferFrom selector, so apply amount conditions only to a contract known to implement ERC-20. Addresses and selectors are normalized to lowercase; use lowercase condition values. For batch calls, do not total amounts for different token IDs.
amount_atomic and native_value_atomic are decimal strings in base units; native value is in wei. EIP-712 integer values are also decimal strings. For EIP-712, typed_data contains the signed domain and message. A path is relative to that fact: use $.message.value for the message value and $.domain.chainId for the signed chain ID.
Wallet, organization, and network restrictions belong in the wallet, org, and instance scopes. Signer, gas, and nonce metadata are not condition facts. The asset scope target does not add an asset condition fact.
Before You Enable a Signing Rule
Use only the facts listed for the operation under Match the Signing Request. Include an operation condition when a rule uses operation-specific facts.
Saving a rule does not confirm that UWM can evaluate it during signing. For example, UWM does not supply a tier fact. A rule that checks whether tier equals gold can cause signing to fail with a generic 500 error.
If signing fails after you enable a rule, review its facts, conditions, and scope. Correct the rule, or ask an authorized administrator to disable it if it is an unintended placeholder. Disabling a required restriction removes its protection.
Before enabling the rule in production, enable it for the intended scope in a test context and verify that actual signing requests are allowed or blocked as intended when they are submitted. The /evaluate endpoint alone does not verify behavior during signing because it accepts user-supplied facts, which may differ from those supplied during signing.
Create a Rule
This example blocks native transfers to one address for one organization. Replace the example IDs and address with the values for your environment. The rule is disabled and will not block requests until you enable it. Review the scope and conditions before enabling the rule.
{
"name": "block-restricted-native-recipient",
"description": "Block native transfers to the restricted recipient",
"category": "transaction-policy",
"enabled": false,
"scopelevels": ["org"],
"targets": {
"orgIds": ["<organization-id>"]
},
"conditions": {
"all": [
{
"fact": "operation",
"operator": "equal",
"value": "native-transfer",
"priority": 100
},
{
"fact": "to_address",
"operator": "equal",
"value": "0x3333333333333333333333333333333333333333",
"priority": 1
}
]
},
"response": {
"type": "BLOCK",
"params": {
"reason": "restricted-recipient"
}
}
}Put the operation condition first and assign it a higher priority than operation-specific facts. During signing authorization, evaluation fails if it reads a missing fact; the request is not silently allowed.
The evaluation endpoints check rules against facts you submit. Live signing uses facts from UWM's validated request and scope targets from its resolved wallet. Use evaluation to inspect a condition, then confirm the result through the intended signing flow.