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.
Prerequisites
- The token has a deployed identity registry that the platform has indexed. A
token with no indexed identity registry returns
DALP-0634on both endpoints. - Replacing the expression requires the caller to hold the token's
governancerole. Reading the expression requires only read access to the token.
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
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:
[
{ "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
Reading returns the token's current expression exactly as stored.
const { data } = await client.token.complianceExpression.get({
params: { tokenAddress: "0x1234567890123456789012345678901234567890" },
});{
"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:
{
"data": {
"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.
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:
{
"transactionId": "0192a1b2-c3d4-7e8f-9a0b-1c2d3e4f5a6b",
"status": "QUEUED",
"statusUrl": "/api/v2/transaction-requests/0192a1b2-c3d4-7e8f-9a0b-1c2d3e4f5a6b"
}Sync - Prefer: wait=60:
{
"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.
await client.token.complianceExpression.update({
params: { tokenAddress: "0x1234567890123456789012345678901234567890" },
body: {
expression: [],
walletVerification: {
secretVerificationCode: "123456",
verificationType: "PINCODE",
},
},
});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
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 | 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.