Skip links

Regulatory Actions

This page specifies the six OIP regulatory actions defined in OIP v0.5: FREEZE, SEIZE, CONFISCATE, LIQUIDATE, RESTRICT, and RECOVER. Each action carries distinct legal semantics, lock-state outcomes, and parameter requirements. The page also defines the Escalation Chain that the protocol enforces between FREEZE, SEIZE, and CONFISCATE, the Authority Hierarchy that gates CRITICAL priority, and the Scheduled Regulatory Action mechanism for time-deferred enforcement.

Regulatory actions are conveyed by REGULATORY_ACTION messages (see Message Protocol) and processed under the protocol’s state-transition rules. The six actions form the on-chain enforcement vocabulary of the Regulatory Compliance Protocol (RCP), with each action mapping to a specific legal instrument used by regulators in tokenized capital markets.

This specification uses the keywords MUST, MUST NOT, SHOULD, and MAY as defined in RFC 2119.


Action types and lock-state outcomes

OIP v0.5 enumerates the six regulatory actions in the RegulatoryActionType enum. Each action has a defined legal meaning, a defined PrimaryLockState outcome, and a defined reversibility property. Implementations MUST preserve these mappings; transitions that diverge from this table are non-conformant.

ActionLegal meaningPrimaryLockState outcomeReversibility
FREEZETemporary suspension of trading RESTRICTEDReversible (via RECOVER or release)
SEIZEForced custody under court order SEIZEDReversible (via RECOVER)
CONFISCATEPermanent removal of ownership TERMINATEDIrreversible
LIQUIDATEForced sale to settle obligations TERMINATEDIrreversible
RESTRICTConditional trading permitted RESTRICTEDReversible
RECOVERReturn of assets to original owner AVAILABLE (depending on prior state)(recovery is itself the reversal)

Three actions are reversible (FREEZE, SEIZE, RESTRICT), two are irreversible (CONFISCATE, LIQUIDATE), and one (RECOVER) is the explicit reversal mechanism for FREEZE and SEIZE. Irreversibility is enforced by transitioning the asset to TERMINATED, which is a final state under the state-transition matrix.

RegulatoryActionType enum

enum RegulatoryActionType {
  FREEZE     = "FREEZE",
  SEIZE      = "SEIZE",
  CONFISCATE = "CONFISCATE",
  LIQUIDATE  = "LIQUIDATE",
  RESTRICT   = "RESTRICT",
  RECOVER    = "RECOVER"
}

RegulatoryPayload structure

Every regulatory action is carried by a RegulatoryPayload embedded in a REGULATORY_ACTION message. The payload identifies the action, the target asset, the issuing authority, action-specific parameters, and supporting evidence.

interface RegulatoryPayload {
  actionType: RegulatoryActionType;
  targetAsset: {
    assetId: string;
    assetType: AssetType;
    currentStateHash: string;        // 0x-prefixed hex, used for idempotency
  };
  authority: AuthorityClaim;
  actionParameters: ActionParameters; // action-specific, see below
  evidence: Evidence;
}

interface AuthorityClaim {
  authorityId: string;
  authorityType: "GLOBAL" | "NATIONAL" | "INDUSTRY" | "SELF_REGULATORY";
  jurisdiction: string[];            // multiple jurisdictions supported
  legalBasis: LegalReference;
  priorityLevel: Priority;           // CRITICAL requires extra verification
}

interface Evidence {
  documentHashes: string[];          // 0x-prefixed hex
  witnessSignatures: string[];       // optional
  externalReferences: string[];      // URLs or DOIs
}

The actionParameters field carries the action-specific structure defined in the next section. Implementations MUST validate that actionParameters matches the schema indicated by actionType. A mismatched parameter shape is treated as malformed input and rejected during message-integrity validation (see Error Reference).

Action parameters

This section defines the parameter schema for each of the six actions. All time fields use ISO 8601 with timezone, all addresses use ERC-3770 shortName format, and all big numbers (amounts, prices) are encoded as decimal strings. See Data Model §2.7 for full type conventions.

FREEZE

FREEZE suspends trading on a target asset. The action supports both full freeze (all operations blocked) and partial freeze (specified operations exempted, e.g., dividend receipt remains permitted while transfers are blocked).

interface FreezeParameters {
  freezeScope: "FULL" | "PARTIAL";
  exemptOperations?: string[];       // required when freezeScope = "PARTIAL"
  expirationTime?: string;           // ISO 8601, automatic release time
  autoUnfreezeCondition?: string;    // Restricted DSL expression
  reason: string;                    // human-readable freeze reason
}

When freezeScope is "PARTIAL", exemptOperations MUST be present and non-empty. A representative exempt operation is "DIVIDEND_RECEIVE", allowing dividend collection while transfers remain blocked. The set of admissible operation identifiers is asset-class dependent and is not restricted by the protocol. The autoUnfreezeCondition field accepts a Restricted DSL expression (see Scheduled Regulatory Action) evaluated at the OSS State Root timestamp; the action releases automatically when the condition first evaluates to true.

Preconditions: the asset’s PrimaryLockState is AVAILABLE or RESERVED; the issuing authority holds FREEZE permission for the asset’s jurisdiction; the legalBasis is valid and not expired; no conflicting FREEZE is in progress; the asset is not TERMINATED.

Postconditions: PrimaryLockState becomes RESTRICTED; SecondaryLockState is set to UNDER_REVIEW (or as specified by the action); the RegulatoryContext is populated; CrossChainCoherence.status becomes SYNCING until all participating chains confirm; a LOCK_MANAGEMENT message is emitted to all participating chains; a primary-finality record is generated.

Errors: ACTION_NOT_PERMITTED when authority lacks the FREEZE permission; JURISDICTION_MISMATCH when authority and asset jurisdictions differ; LEGAL_BASIS_EXPIRED_OR_NOT_YET_VALID when the legal document is outside its validity window; INVALID_STATE_TRANSITION when applied to a state outside {AVAILABLE, RESERVED}.

SEIZE

SEIZE places the asset into forced custody while preserving the original owner’s title. This corresponds to the legal instrument used by courts when an asset must be held pending adjudication. Ownership is retained; control is transferred to the designated custody address.

interface SeizeParameters {
  custodyAddress: string;            // ERC-3770 format
  ownershipRetained: true;           // SEIZE preserves ownership (vs CONFISCATE)
  accessRestrictions: AccessRestriction[];
  releasePreconditions?: string[];   // Restricted DSL expressions
  legalBasis: LegalReference;        // court order or equivalent instrument
}

interface AccessRestriction {
  restrictedOperation: string;
  exception?: string;                // exempted authority (e.g., court-appointed administrator)
}

The ownershipRetained: true field is a literal-typed flag, not a boolean parameter. It encodes the structural distinction between SEIZE and CONFISCATE in the type system: SEIZE always preserves ownership, CONFISCATE always removes it. Implementations MUST reject any SeizeParameters where this flag is absent or set to a value other than true.

The legalBasis field is required and is logically distinct from the RegulatoryContext.legalBasis on the enclosing message. The payload-level legalBasis identifies the specific instrument authorizing this seizure (e.g., a court order with case number), while the message-level context identifies the regulatory framework under which the action operates.

Preconditions: PrimaryLockState equals RESTRICTED (a prior FREEZE exists in the escalation history); the issuing authority holds SEIZE permission; the SEIZE legalBasis is valid; the asset is not in COOLING_DOWN.

Postconditions: PrimaryLockState becomes SEIZED; SecondaryLockState becomes AWAITING_CLEARANCE (after the custodian is designated); custodyAddress is recorded in the RegulatoryContext; ownershipRetained remains true (distinguishing SEIZE from CONFISCATE); access restrictions are enforced.

Errors: FREEZE_REQUIRED_BEFORE_SEIZE when applied to an asset whose PrimaryLockState is not RESTRICTED; ACTION_NOT_PERMITTED when authority lacks SEIZE permission; INVALID_LEGAL_DOCUMENT_STRUCTURE when the legal-basis instrument is malformed; EVIDENCE_HASH_INVALID when supporting evidence hashes fail verification.

CONFISCATE

CONFISCATE permanently removes ownership and transfers the asset to a destination address. Because the action is irreversible, OIP v0.5 mandates that the appeal period MUST have expired before CONFISCATE can be executed.

interface ConfiscateParameters {
  destinationAddress: string;        // ERC-3770 format
  finalityProof: FinalityProof;      // proof that appeal period has expired
  compensationMechanism?: CompensationDetails;
  ownershipRetained: false;          // CONFISCATE removes ownership
}

interface FinalityProof {
  appealDeadlinePassed: true;        // MUST be true
  appealDeadlineRecord: string;      // 0x-prefixed hex (record of the deadline)
  governanceConfirmation?: string;   // optional governance confirmation
}

interface CompensationDetails {
  compensationAddress?: string;
  compensationAmount?: string;       // big number, decimal string
  compensationCondition?: string;
}

appealDeadlinePassed: true is a hard requirement. Any CONFISCATE message where this flag is false or absent MUST be rejected with APPEAL_PERIOD_NOT_EXPIRED. The appealDeadlineRecord hash links the action to the record of the deadline event, allowing auditors to verify that the prerequisite condition was indeed satisfied at the time of execution.

Preconditions: PrimaryLockState equals SEIZED (a prior SEIZE exists in the escalation history); the issuing authority holds CONFISCATE permission; finalityProof.appealDeadlinePassed equals true; destinationAddress is specified.

Postconditions: PrimaryLockState becomes TERMINATED; ownership is transferred to destinationAddress; the asset is permanently removed from circulation; if compensationMechanism is present, the compensation flow is initiated.

Errors: SEIZE_REQUIRED_BEFORE_CONFISCATE when applied to an asset not in SEIZED; APPEAL_PERIOD_NOT_EXPIRED when appealDeadlinePassed is missing or false; ACTION_NOT_PERMITTED when the authority lacks CONFISCATE permission; CRITICAL_PRIORITY_NOT_AUTHORIZED when the message carries CRITICAL priority without sufficient authority level.

LIQUIDATE

LIQUIDATE converts an asset to currency through one of three sale mechanisms and distributes the proceeds to designated recipients. Unlike FREEZE, SEIZE, and CONFISCATE, LIQUIDATE is outside the Escalation Chain and may be applied directly to assets in AVAILABLE, RESTRICTED, or SEIZED state.

interface LiquidateParameters {
  liquidationType: "MARKET_ORDER" | "AUCTION" | "FIXED_PRICE";
  minimumPrice?: PriceConstraint;    // floor price protection
  proceedsDistribution: ProceedsDistribution;
  deadline: string;                  // ISO 8601, completion deadline
  liquidationVenue?: string;         // venue identifier (e.g., DEX address)
}

interface PriceConstraint {
  priceOracle: string;               // price oracle identifier
  minimumPrice: string;              // big number, decimal string
  toleranceBps?: number;             // basis points (1bp = 0.01%)
}

interface ProceedsDistribution {
  recipients: ProceedsRecipient[];
  totalShare: number;                // MUST equal 100
}

interface ProceedsRecipient {
  recipientAddress: string;          // ERC-3770 format
  sharePercent: number;              // 0-100
  priority: number;                  // creditor priority for multi-claim cases
}

The sum of sharePercent across all recipients MUST equal totalShare, and totalShare MUST equal 100. The priority field orders distribution when liquidation proceeds are insufficient to satisfy all recipients fully (lower priority numbers are paid first). The minimumPrice floor, when present, prevents fire-sale liquidation; if the venue cannot meet the floor, the action MUST fail rather than execute below the constraint.

Preconditions: PrimaryLockState is one of {AVAILABLE, RESTRICTED, SEIZED}; the issuing authority holds LIQUIDATE permission; the legalBasis is valid; the recipient share total equals 100; if minimumPrice is set, the venue is capable of enforcing the floor.

Postconditions: the asset is sold through liquidationVenue under the chosen liquidationType; proceeds are distributed in priority order according to ProceedsDistribution; PrimaryLockState becomes TERMINATED; the liquidation event is recorded for audit.

Errors: INVALID_STATE_TRANSITION when applied outside {AVAILABLE, RESTRICTED, SEIZED}; ACTION_NOT_PERMITTED when the authority lacks LIQUIDATE permission; JURISDICTION_MISMATCH when the venue or recipients fall outside the authority’s permitted jurisdiction.

RESTRICT

RESTRICT is a conditional permission mechanism. Unlike FREEZE, which suspends operations entirely or by exemption list, RESTRICT permits operations only when a stated condition holds. It is the lighter-weight counterpart to FREEZE and does not satisfy the prerequisite for SEIZE.

interface RestrictParameters {
  restrictionType: "WHITELIST" | "BLACKLIST" | "THRESHOLD" | "GEOGRAPHIC";
  conditionExpression?: string;      // Restricted DSL expression
  exceptions?: string[];             // exempted parties or operations
  expirationTime?: string;           // ISO 8601, automatic release time
}
restrictionTypeSemanticsTypical use
WHITELISTOnly listed parties may transactRestricted offerings, accredited-investor pools
BLACKLISTAll parties except listed may transactSanctions list enforcement
THRESHOLDTrading allowed within volume or frequency limitsCooling-off periods, AML thresholds
GEOGRAPHICTrading allowed only within permitted jurisdictionsSecurities offerings by region

Preconditions: PrimaryLockState is one of {AVAILABLE, RESERVED}; the issuing authority holds RESTRICT permission; if conditionExpression is present, it parses as a valid Restricted DSL expression; if expirationTime is present, it is in the future relative to the OSS State Root timestamp.

Postconditions: PrimaryLockState becomes RESTRICTED; the restriction parameters are recorded in the RegulatoryContext; subsequent transfer attempts are evaluated against conditionExpression and exceptions. Note that RESTRICT reaching RESTRICTED does not satisfy the prerequisite for SEIZE; only a prior FREEZE does.

Errors: INVALID_STATE_TRANSITION when applied outside {AVAILABLE, RESERVED}; ACTION_NOT_PERMITTED when the authority lacks RESTRICT permission.

RECOVER

RECOVER returns assets to an original owner after fraud or theft has been established. The action references both the legitimate claimant (OwnershipClaim) and the fraudulent holder (FraudClaim), and may include a partial recovery amount or compensation to a good-faith third-party purchaser.

interface RecoverParameters {
  originalOwner: OwnershipClaim;
  fraudulentHolder: FraudClaim;
  recoveryBasis: LegalReference;
  recoveryAmount?: string;           // partial recovery, big number
  compensationToFraudulentHolder?: string; // protection for innocent purchasers
}

interface OwnershipClaim {
  ownerOCID: string;
  ownerAddress: string;              // ERC-3770 format
  ownershipProof: string;            // 0x-prefixed hex (ownership-proof hash)
}

interface FraudClaim {
  holderOCID?: string;
  holderAddress: string;             // ERC-3770 format
  fraudProof: string;                // 0x-prefixed hex (fraud-proof hash)
  fraudType: "THEFT" | "PHISHING" | "EXPLOIT" | "OTHER";
}

The compensationToFraudulentHolder field exists to protect good-faith purchasers who acquired the asset without knowledge of the underlying fraud. When the recovery is awarded against such a holder, the issuing authority MAY include compensation to balance the equities. The mechanism is permissive, not mandatory; whether compensation is owed is a matter of the underlying legal basis, not protocol policy.

Preconditions: PrimaryLockState is one of {RESTRICTED, SEIZED}; originalOwner.ownershipProof is valid; fraudulentHolder.fraudProof is valid; the recoveryBasis legal document is valid.

Postconditions: PrimaryLockState becomes AVAILABLE; ownership is transferred to originalOwner; the recovery event is recorded in the audit log; if compensationToFraudulentHolder is set, the corresponding compensation flow is initiated.

Errors: INVALID_STATE_TRANSITION when applied outside {RESTRICTED, SEIZED}; EVIDENCE_HASH_INVALID when ownership-proof or fraud-proof hashes fail verification; INVALID_LEGAL_DOCUMENT_STRUCTURE when recoveryBasis is malformed.

Escalation Chain enforcement

OIP v0.5 enforces a three-stage Escalation Chain at the protocol level: FREEZE must precede SEIZE, and SEIZE must precede CONFISCATE. The chain encodes the principle that the most severe regulatory measures are reachable only through the lighter ones, providing both procedural protection for asset holders and an audit trail for regulators.

Figure 1: Escalation Chain enforcement and rollback path

Enforcement rules

Implementations MUST enforce the following preconditions when validating a REGULATORY_ACTION message:

ActionRequired prior PrimaryLockStateError if violated
SEIZERESTRICTED (i.e., FREEZE previously applied)FREEZE_REQUIRED_BEFORE_SEIZE
CONFISCATESEIZED (i.e., SEIZE previously applied)SEIZE_REQUIRED_BEFORE_CONFISCATE

Actions outside the Escalation Chain

Three actions operate outside the chain and may be applied directly when the conditions below are met. They do not require any preceding action.

ActionPermitted entry statesNotes
LIQUIDATEAVAILABLE, RESTRICTED, SEIZEDDirect liquidation permitted with adequate authority and legal basis
RESTRICTAVAILABLE, RESERVEDLighter-weight conditional permission; does not satisfy SEIZE prerequisite
RECOVERRESTRICTED, SEIZEDReversal mechanism for FREEZE and SEIZE

The Escalation Chain is reflected in the State Transition Matrix and in the rollback hierarchy: rollbacks proceed in reverse order, returning the asset one step at a time toward AVAILABLE.

Action applicability matrix

The matrix below summarises which actions can be applied to which PrimaryLockState. Cells marked OK are valid entry conditions; cells marked not allowed trigger the indicated error. This view complements the State Transition Matrix, which lists outcomes; this matrix lists entry conditions.

Figure 3: Action applicability across PrimaryLockState values

Authority Hierarchy and CRITICAL gating

The Priority level CRITICAL triggers automatic escalation to ALL_OR_NOTHING atomicity across all chains in the asset’s scope (see Routing §4.3). Because the consequences of CRITICAL propagation are severe, OIP v0.5 restricts the right to issue CRITICAL regulatory actions to a governance-registered Authority Hierarchy.

Figure 2: Authority Hierarchy and CRITICAL grant scope by level

CRITICAL verification procedure

When header.routing.priority == CRITICAL is set on a REGULATORY_ACTION message, the receiving node MUST perform Authority Verification as part of the validation pipeline (Group 1-C in Validation). The procedure resolves the issuing authority, reads its hierarchy level, and confirms that the requested target scope is a subset of the authority’s permitted scope. Any failure in resolution, level lookup, or scope inclusion results in rejection.

// CRITICAL Authority Verification (Group 1-C)
//
// Returns Ok if the message is permitted to carry CRITICAL priority,
// Err with the appropriate error code otherwise.

type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };

function verifyCriticalAuthority(
  message: OIPMessage,
  registry: AuthorityRegistry
): Result<void, ErrorCode> {

  // Step 1: Confirm priority is CRITICAL.
  if (message.header.routing.priority !== Priority.CRITICAL) {
    return { ok: true, value: undefined };  // not subject to this check
  }

  // Step 2: Resolve authorityId.
  const authority = registry.lookup(message.payload.authority.authorityId);
  if (!authority) {
    return { ok: false, error: "AUTHORITY_NOT_REGISTERED" };
  }

  // Step 3: Read hierarchy level. Level 4 (SELF_REGULATORY) MUST NOT issue CRITICAL.
  if (authority.level === 4) {
    return { ok: false, error: "CRITICAL_PRIORITY_NOT_AUTHORIZED" };
  }

  // Step 4: Verify target scope inclusion.
  const targetChains  = message.targetScope.targetChains;
  const targetAssets  = message.targetScope.targetAssets;

  const chainsAllowed = isSubset(targetChains, authority.permittedChains);
  const assetsAllowed = isSubset(targetAssets, authority.permittedAssets);

  if (!chainsAllowed || !assetsAllowed) {
    return { ok: false, error: "CRITICAL_PRIORITY_NOT_AUTHORIZED" };
  }

  // Step 5: Verify jurisdiction match (Levels 2 and 3 only).
  if (authority.level === 2 || authority.level === 3) {
    if (!jurisdictionMatches(message.payload.authority.jurisdiction,
                             authority.jurisdictions)) {
      return { ok: false, error: "JURISDICTION_MISMATCH" };
    }
  }

  return { ok: true, value: undefined };
}

The procedure runs in Group 1-C alongside other read-only checks (precondition, state invariant, temporal constraint, first-pass proof verification). Because all checks at this stage are read-only, the verification can fast-fail without holding any preemptive lock, in line with the validation pipeline’s overall fail-fast principle.

Authority records (hierarchy level, permitted scope, verification keys) are registered through governance using the AUTHORITY_REGISTRATION subtype of the GOVERNANCE message. Registration requires a governance vote per the dynamic-routing-table mechanism. This procedure ensures that the right to issue CRITICAL regulatory actions is itself a publicly auditable on-chain act, not a privilege embedded in implementation.

Validation pipeline placement

Authority Verification, Legal Basis Verification, and CRITICAL gating sit within Group 1-C of the validation pipeline. The diagram below shows where each check operates relative to lock acquisition and cross-chain dispatch. Group 1 is read-only and fast-fail; only after it succeeds does the message acquire a preemptive lock and proceed to state modification.

Figure 4: Validation pipeline placement of Authority Verification within Group 1-C

Cross-chain propagation

Regulatory actions span all chains where the asset exists. The crossChainScope field on a REGULATORY_ACTION message determines which chains receive the action and how the cross-chain commitment is enforced.

interface CrossChainScope {
  targetChains: string[];              // ERC-3770 shortName list
  atomicity: AtomicityStrategy;        // BEST_EFFORT | GUARANTEED | ALL_OR_NOTHING
  timeoutSeconds: number;
  fallbackPolicy: "RETRY" | "PARTIAL" | "ABORT";
}

The choice of atomicity is constrained by the action’s irreversibility and by the message priority. The matrix below summarises the recommended pairing and the rules that the protocol enforces.

ActionRecommended atomicityCRITICAL priority effect
FREEZE / RESTRICTGUARANTEED (BEST_EFFORT permitted for non-financial assets)Forced to ALL_OR_NOTHING across all targeted chains
SEIZEGUARANTEEDForced to ALL_OR_NOTHING
CONFISCATEALL_OR_NOTHINGForced to ALL_OR_NOTHING (irreversibility requires uniform commitment)
LIQUIDATEALL_OR_NOTHINGForced to ALL_OR_NOTHING (proceeds distribution requires consistent state)
RECOVERGUARANTEEDForced to ALL_OR_NOTHING

The protocol applies priority-based atomicity escalation as defined in Routing §4.3. When priority == CRITICAL, atomicity is upgraded to ALL_OR_NOTHING regardless of the field value, and targetChains is implicitly extended to all chains in the asset’s scope. This prevents partial enforcement of high-severity actions.

The cross-chain dispatch follows the staged coordination protocol (PREPARE / COMMIT / FINALIZE) described in Cross-chain Protocol. For irreversible actions (CONFISCATE, LIQUIDATE), the COMMIT phase is the point of no return; failures after COMMIT trigger the rollback sequence on all participating chains.

Finality and effective time

OIP distinguishes two finality stages for cross-chain messages. Regulatory actions are subject to the same model and become enforceable at primary finality, not at secondary finality. This distinction matters in practice: trading on a frozen or seized asset is blocked from the moment the OSS State Root is finalised, well before the secondary finality on Base L2 is reached.

StageIssued atEffect on regulatory action
Primary finalityOSS State Root commitment (GKR proof issued)Action becomes enforceable. PrimaryLockState is updated; downstream consumers (RWA Registry, OracleMint) MUST observe the new state.
Secondary finalityfflonk → zkVerify → Base L2 settlementExternal settlement guarantee. The same action is now externally verifiable; no additional state change.

If primary finality is reached but secondary finality fails (for example, due to relayer outage), the OSS pending sync queue retries propagation while the primary record remains the source of truth (see Cross-chain Protocol §8.3). Implementations MUST NOT allow trading or transfer that contradicts a primary-finality regulatory state, even when secondary finality is still pending.

Scheduled Regulatory Action

Regulatory actions may be issued for immediate execution or for future automatic execution when stated conditions are met. Scheduled actions are carried by the optional scheduledExecution field on a REGULATORY_ACTION message.

interface ScheduledExecution {
  executeAt: string;                   // ISO 8601
  conditions?: string[];               // Restricted DSL preconditions
  cancellationPolicy: "AUTO_ON_CONDITION" | "MANUAL_ONLY";
  cancellationDeadline?: string;       // optional cancellation deadline
}

Processing flow

  1. The REGULATORY_ACTION message is issued with a scheduledExecution field.
  2. The OSS registers the scheduled action in its internal queue (implementation-defined).
  3. When executeAt is reached, all conditions are evaluated under Restricted DSL semantics.
  4. If all conditions hold, the action is executed using actionParameters as if issued at that moment.
  5. If conditions do not hold, behavior follows cancellationPolicy: AUTO_ON_CONDITION automatically cancels the action; MANUAL_ONLY defers to a governance decision.

Example scenarios

  • Automatic LIQUIDATE at maturity: executeAt equals the asset’s maturity time, with conditions: ["currentPrice < strikePrice"] applying liquidation only when the price condition is met.
  • Automatic CONFISCATE after appeal expiry: executeAt equals the appeal deadline, with conditions: ["appealStatus == 'EXPIRED'"] ensuring execution only after the appeal window has closed without challenge.

Restricted DSL

Conditions in scheduledExecution.conditions and in action parameters such as autoUnfreezeCondition use the Restricted DSL, a deliberately narrow expression language. v0.5 admits the following constructs:

  • Comparison operators: ==, !=, <, >, <=, >=
  • Logical operators: AND, OR, NOT
  • Variable references: assetState.field, currentTime, actionState.field
  • Literals: integers, strings, ISO 8601 timestamps, booleans

Arbitrary function calls, external queries, and loops are not part of v0.5 (deferred to v0.6 or later). The DSL is Turing-incomplete by design, eliminating the risk of unbounded computation during evaluation.

Determinism guarantees

Restricted DSL evaluation MUST yield identical results across all nodes processing the same OSS State Root. The following rules enforce determinism and MUST be implemented:

RuleSpecification
currentTime definitionThe block timestamp recorded in the OSS State Root at message-processing time, as agreed by D-quencer consensus. Local clocks MUST NOT be used.
Numeric typeSigned 64-bit integers only. Floating-point is forbidden because IEEE 754 implementations vary across runtimes.
Integer overflowAny arithmetic result outside the signed 64-bit range MUST cause explicit evaluation failure (treated as condition unmet). Silent wraparound is forbidden.
String comparisonUTF-8 byte lexicographic order, matching the assetId ordering rule in §2.5. Locale-dependent comparison is forbidden.
Timestamp comparisonISO 8601 strings MUST be normalized to UTC before comparison. "2026-04-25T14:30:00Z" equals "2026-04-25T23:30:00+09:00".
Evaluation orderLeft to right, with short-circuit semantics. AND stops at the first false; OR stops at the first true.
Missing variableReference to an absent field MUST cause evaluation failure. Comparison against null or undefined is forbidden.

Together, the language restrictions and the determinism rules ensure that scheduled-action evaluation is deterministic and idempotent: the same input always produces the same outcome, and re-evaluation of the same condition under the same State Root produces the same result.


Related Pages

References

  • RFC 2119: Key words for use in RFCs to indicate requirement levels
  • ERC-3770: Chain-specific addresses
  • ISO 8601: Date and time format

Table of Contents