# Token compliance expression

Source: https://docs.settlemint.com/docs/api-reference/compliance/token-compliance-expression
Read and replace a token's on-chain compliance expression, the postfix rule that gates holder verification, through the DALP Platform API, SDK, and CLI.



Every DALP token carries one compliance expression on its identity registry. The
expression is the rule that decides whether an address may hold the token: when an
address passes the expression, the platform allows the transfer, and when it
fails, the platform rejects it. You read and replace that rule through the two
Platform API endpoints below.

The expression is a single value on the token's own identity registry. There is
no list, no pagination, and no inheritance chain. You read the whole expression
and you replace the whole expression.

An empty expression is a valid, deliberate state: it drops the claim-topic
requirement, but the identity registry still applies its own checks first. The
address must have a stored identity and must not be marked as lost. An empty
expression therefore admits any registered, active identity, not every address.
For the read-only view in the Console, see the token's
[Compliance tab](/docs/operators/asset-servicing/asset-detail-workspace).

## Prerequisites [#prerequisites]

* The token has a deployed identity registry that the platform has indexed. A
  token with no indexed identity registry returns `DALP-0634` on both endpoints.
* Replacing the expression requires the caller to hold the token's `governance`
  role. Reading the expression requires only read access to the token.

## Endpoints [#endpoints]

| Operation | SDK method                          | HTTP                                                      |
| --------- | ----------------------------------- | --------------------------------------------------------- |
| Read      | `token.complianceExpression.get`    | `GET /api/v2/tokens/{tokenAddress}/compliance-expression` |
| Replace   | `token.complianceExpression.update` | `PUT /api/v2/tokens/{tokenAddress}/compliance-expression` |

## The expression model [#the-expression-model]

A compliance expression is a postfix (reverse Polish notation) array of nodes.
Each node has a `nodeType` and a `value`:

| `nodeType` | Meaning | `value`                                                       |
| ---------- | ------- | ------------------------------------------------------------- |
| `0`        | TOPIC   | The claim-topic id an address must hold to satisfy this term. |
| `1`        | AND     | Combines the two preceding terms; both must pass.             |
| `2`        | OR      | Combines the two preceding terms; either may pass.            |
| `3`        | NOT     | Negates the preceding term.                                   |

Operator nodes (`AND`, `OR`, `NOT`) carry a `value` of `0`. A TOPIC node carries
the claim-topic id an address must hold.

Postfix ordering places each operator after its operands. The expression
"holds topic 1 AND holds topic 2" is:

```json
[
  { "nodeType": 0, "value": "1" },
  { "nodeType": 0, "value": "2" },
  { "nodeType": 1, "value": "0" }
]
```

`value` is a decimal string on both read and write so it can carry the full
on-chain `uint256` range without loss.

## Read the expression [#read-the-expression]

Reading returns the token's current expression exactly as stored.

```ts fixture=dalp-client group=token-compliance-expression
const { data } = await client.token.complianceExpression.get({
  params: { tokenAddress: "0x1234567890123456789012345678901234567890" },
});
```

```json
{
  "data": {
    "expression": [
      { "nodeType": 0, "value": "1" },
      { "nodeType": 0, "value": "2" },
      { "nodeType": 1, "value": "0" }
    ]
  }
}
```

An empty `expression` array means the token has no claim-topic requirement, so
any registered, active identity passes verification:

```json
{
  "data": {
    "expression": []
  }
}
```

## Replace the expression [#replace-the-expression]

Replacing submits the whole new expression and clears whatever was there before.
No add or remove operation exists; the array you send becomes the token's
complete expression.

By default the route queues the transaction asynchronously and returns a
status object you can poll. If you want the transaction hash inline, send
`Prefer: wait=60` (or any `wait=N` up to the platform limit) to switch to
synchronous mode.

```ts group=token-compliance-expression
const result = await client.token.complianceExpression.update({
  params: { tokenAddress: "0x1234567890123456789012345678901234567890" },
  body: {
    expression: [
      { nodeType: 0, value: "1" },
      { nodeType: 0, value: "2" },
      { nodeType: 1, value: "0" },
    ],
    walletVerification: {
      secretVerificationCode: "123456",
      verificationType: "PINCODE",
    },
  },
});
```

API-key sessions skip wallet verification (the API key itself is the
authentication). Omit `walletVerification` when you call this endpoint with an
API key; include it for normal user sessions.

Async (default) - no `Prefer` header or `Prefer: respond-async`:

```json
{
  "transactionId": "0192a1b2-c3d4-7e8f-9a0b-1c2d3e4f5a6b",
  "status": "QUEUED",
  "statusUrl": "/api/v2/transaction-requests/0192a1b2-c3d4-7e8f-9a0b-1c2d3e4f5a6b"
}
```

Sync - `Prefer: wait=60`:

```json
{
  "data": {
    "txHash": "0xabc1230000000000000000000000000000000000000000000000000000000000"
  },
  "meta": {
    "txHashes": ["0xabc1230000000000000000000000000000000000000000000000000000000000"]
  },
  "links": {
    "self": "/api/v2/tokens/0x1234567890123456789012345678901234567890/compliance-expression"
  }
}
```

To clear a token's identity-registry expression, submit an empty array.
This removes the registry-membership gate from the expression, so registered,
non-lost wallets pass that check. Other compliance modules still run as usual.

```ts group=token-compliance-expression
await client.token.complianceExpression.update({
  params: { tokenAddress: "0x1234567890123456789012345678901234567890" },
  body: {
    expression: [],
    walletVerification: {
      secretVerificationCode: "123456",
      verificationType: "PINCODE",
    },
  },
});
```

## Validation [#validation]

The platform validates a replacement before it submits the transaction, because
the on-chain registry stores the array without checking it. An expression that
passes these rules is well-formed; one that fails is rejected before any
transaction is queued.

| Rule              | Requirement                                                                                    |
| ----------------- | ---------------------------------------------------------------------------------------------- |
| Node count        | At most 32 nodes. The on-chain evaluator rejects a longer expression.                          |
| Postfix structure | A non-empty expression must be well-formed postfix: operands precede their operators.          |
| Node value range  | Every node `value` is from `0` to `2^256 - 1`. Values outside this range cannot be encoded.    |
| TOPIC value       | A TOPIC node's `value` (its claim-topic id) cannot be `0`. Claim-topic id `0` is always false. |
| Empty array       | Accepted. Clears the rule, so any registered, active identity passes.                          |

A malformed expression that bypasses validation would store on-chain and then
reject every later transfer of the token, so the platform checks each rule
before submitting.

## CLI equivalents [#cli-equivalents]

The DALP CLI exposes the same two operations for operator scripts:

| Task    | CLI command                                                                          |
| ------- | ------------------------------------------------------------------------------------ |
| Read    | `tokens compliance-expression get <tokenAddress>`                                    |
| Replace | `tokens compliance-expression update --address <tokenAddress> --expression '<json>'` |

Pass the postfix node array to `--expression` as JSON. An empty array (`[]`)
clears the expression.

## Error handling [#error-handling]

| Error       | What the platform observed                                                                | Caller response                                                                     |
| ----------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `DALP-0634` | The token has no indexed identity registry, so there is no expression to read or replace. | Confirm the token has a deployed identity registry and that indexing has caught up. |

A replacement also requires the token's `governance` role and a verified wallet.
A caller without that role receives the standard access error, and the
expression is not changed.

## Related [#related]

* [Asset detail workspace](/docs/operators/asset-servicing/asset-detail-workspace)
* [Claims and identity](/docs/architecture/concepts/claims-and-identity)
* [Participant compliance eligibility](/docs/api-reference/compliance/participant-compliance-eligibility)
* [Platform API error reference](/docs/api-reference/errors/platform-api-error-reference)
