Skip links

Protocol Specification for Regulatory Actions: Message Formats, Validation Logic, and Cross-chain Coordination

TL;DR

  • Six regulatory actions (FREEZE, SEIZE, CONFISCATE, LIQUIDATE, RESTRICT, RECOVER) each possess unique state transition rules and reversibility conditions, standardized through OIP message formats
  • OSS four-stage validation pipeline filters all regulatory actions through Authority Verification → State Transition Check → Legal Basis Verification → Cross-chain Consistency
  • D-quencer priority system assigns CRITICAL (P0) priority to emergency regulatory actions, ensuring processing before standard transactions
  • Three-phase cross-chain broadcast protocol (PREPARE → COMMIT → FINALIZE) supports three execution strategies based on atomicity level: ALL_OR_NOTHING, GUARANTEED, and BEST_EFFORT
  • This specification transforms the philosophical foundation of enforceability into implementable technical standards, defining integration APIs for DeFi protocol developers

Introduction: From Philosophy to Protocol

In our previous exploration of enforceability as the third pillar of RCP, we philosophically examined why regulatory enforcement power is essential. We demonstrated that the fundamental contradiction of “how to implement centralized enforcement power in a decentralized system” could be resolved through the Selective Decentralization paradigm.

However, philosophical justification alone does not make systems operational. Protocol specification is required.

In our recent analysis of asset state management complexity, we introduced the Hierarchical Lock Status framework. We defined what states an asset can occupy and which transitions are valid. Now we must specify who can trigger these state transitions, how, and why.

This research fully specifies at the protocol level how six regulatory actions are encoded as OIP messages, validated by OSS, prioritized by D-quencer, and broadcast across chains.

“Protocol specification is the bridge between philosophy and implementation. Specification without principles yields directionless implementation; principles without specification remain unrealizable ideals.”

Taxonomy of Six Regulatory Actions

Action Characteristics Matrix

Building upon the Lock Status framework established in our asset state management research, each of the six regulatory actions possesses unique state transition rules. The following table summarizes the core characteristics of each action:

ActionPermitted Start StatesTarget StateReversibilityCross-chain Requirement
FREEZEAVAILABLE, RESERVEDRESTRICTEDtrueSynchronous broadcast
SEIZERESTRICTEDSEIZEDConditionalAtomic commit required
CONFISCATESEIZEDTERMINATEDfalseFinality proof required
LIQUIDATEAVAILABLE, RESTRICTED, SEIZEDTERMINATEDfalseMarket integration
RESTRICTAVAILABLERESTRICTEDtrueCondition propagation
RECOVERRESTRICTED, SEIZEDAVAILABLEN/AOwnership restoration

Enforcing the Escalation Chain

As argued in our enforceability analysis, the core of regulatory enforcement power lies in procedural legitimacy. Code must enforce legal procedure:

  • SEIZE presupposes FREEZE — assets cannot be seized without first being frozen
  • CONFISCATE presupposes SEIZE — assets cannot be confiscated without first being seized
  • RECOVER presupposes proof of fraudulent acquisition — legal basis for ownership restoration is required

This escalation chain is enforced during the State Transition Check stage of the OSS validation pipeline.

OIP Regulatory Action Message Format

Base Message Structure

In OIP v0.3, regulatory actions are defined as the REGULATORY_ACTION message type. Extending the base OIP message structure from our earlier protocol specification, regulatory-specific fields are added:

{
  "version": "0.3.0",
  "messageId": "uuid-v4",
  "messageType": "REGULATORY_ACTION",
  "timestamp": "ISO-8601",
  "sourceChainId": "oraclizer-l3",
  "signature": "ed25519-signature",
  
  "regulatoryPayload": {
    "actionType": "FREEZE|SEIZE|CONFISCATE|LIQUIDATE|RESTRICT|RECOVER",
    "targetAsset": {
      "assetId": "bytes32",
      "assetType": "ERC20|ERC721|ERC1155|BOND|STOCK",
      "currentStateHash": "bytes32"
    },
    "authority": {
      "authorityId": "bytes32",
      "authorityType": "NATIONAL|INTERNATIONAL|INDUSTRY|SELF_REGULATORY",
      "jurisdiction": ["ISO-3166-alpha-2"],
      "legalBasis": {
        "documentType": "COURT_ORDER|REGULATORY_DIRECTIVE|EMERGENCY_ORDER",
        "documentHash": "bytes32",
        "issuedAt": "ISO-8601",
        "validUntil": "ISO-8601|null"
      },
      "priorityLevel": "CRITICAL|HIGH|NORMAL"
    },
    "actionParameters": { },
    "evidence": {
      "documentHashes": ["bytes32"],
      "witnessSignatures": ["signature"],
      "externalReferences": ["uri"]
    }
  },
  
  "crossChainScope": {
    "targetChains": ["chainId"],
    "atomicityRequirement": "ALL_OR_NOTHING|GUARANTEED|BEST_EFFORT",
    "timeoutSeconds": 300,
    "fallbackPolicy": "RETRY|PARTIAL|ABORT"
  }
}

Action-Specific Parameter Details

Each regulatory action requires a unique parameter set in the actionParameters field:

FREEZE Parameters

{
  "freezeScope": "FULL|PARTIAL",
  "exemptOperations": ["VIEW", "DIVIDEND_CLAIM"],
  "expirationTime": "ISO-8601|null",
  "autoUnfreezeCondition": {
    "type": "TIME_BASED|CONDITION_BASED|MANUAL",
    "parameters": {}
  }
}

Key Design Decision: exemptOperations specifies operations permitted even during freeze. For example, dividend claim rights may be exercisable during a freeze. This is the protocol-level implementation of the “proportionality principle” discussed in our enforceability research.

SEIZE Parameters

{
  "custodyAddress": "ERC-3770-address",
  "ownershipRetained": true,
  "accessRestrictions": {
    "allowedOperations": [],
    "custodianPermissions": ["VIEW", "TRANSFER_TO_COURT"]
  },
  "releasePreconditions": {
    "type": "COURT_ORDER|APPEAL_PERIOD|SETTLEMENT",
    "parameters": {}
  }
}

Key Design Decision: ownershipRetained: true specifies that seizure is not ownership deprivation. Legally, ownership of seized assets remains with the original owner; only control is delegated to regulatory authority.

CONFISCATE Parameters

{
  "destinationAddress": "ERC-3770-address",
  "finalityProof": {
    "courtDecision": {
      "caseNumber": "string",
      "documentHash": "bytes32",
      "jurisdiction": "ISO-3166"
    },
    "appealDeadlinePassed": true,
    "appealWaiver": "bytes32|null"
  },
  "compensationMechanism": {
    "type": "NONE|PARTIAL|FULL",
    "parameters": {}
  }
}

Key Design Decision: finalityProof proves the legal finality of confiscation. If appealDeadlinePassed is false, OSS rejects this message. This mechanism resolves the tension between blockchain’s irreversibility and legal procedure’s reversibility.

LIQUIDATE Parameters

{
  "liquidationType": "MARKET_SALE|AUCTION|FIXED_PRICE",
  "minimumPrice": {
    "amount": "uint256",
    "currency": "ERC-3770-address",
    "priceOracle": "oracleId"
  },
  "proceedsDistribution": {
    "primaryCreditor": {
      "address": "ERC-3770-address",
      "percentage": 80
    },
    "remainderRecipient": {
      "address": "ERC-3770-address",
      "percentage": 20
    }
  },
  "deadline": "ISO-8601"
}

Key Design Decision: priceOracle references external price oracles for fair market price determination. This directly integrates with Oraclizer’s state synchronization capabilities, ensuring liquidation price fairness.

RESTRICT Parameters

{
  "restrictionType": "WHITELIST|BLACKLIST|THRESHOLD|GEOGRAPHIC",
  "allowedCounterparties": ["OCID"],
  "blockedCounterparties": ["OCID"],
  "transactionLimits": {
    "perTransaction": "uint256",
    "daily": "uint256",
    "monthly": "uint256"
  },
  "conditionExpression": "DSL-expression",
  "exceptions": [{
    "conditionType": "EMERGENCY|LEGAL_OBLIGATION",
    "authorizedBy": "authorityId"
  }]
}

Key Design Decision: conditionExpression expresses complex conditions in a domain-specific language (DSL). For example, expressions like "sender.kycLevel >= 2 AND receiver.jurisdiction NOT IN ['XX', 'YY']" are possible.

RECOVER Parameters

{
  "originalOwner": {
    "ocid": "OCID",
    "ownershipProof": {
      "type": "TRANSACTION_HISTORY|LEGAL_DOCUMENT|COURT_ORDER",
      "documentHash": "bytes32"
    }
  },
  "fraudulentHolder": {
    "ocid": "OCID",
    "fraudProof": {
      "type": "THEFT|SCAM|UNAUTHORIZED_TRANSFER",
      "documentHash": "bytes32"
    }
  },
  "recoveryBasis": {
    "legalFramework": "string",
    "courtOrder": "bytes32"
  },
  "compensationMechanism": {
    "toFraudulentHolder": false,
    "toIntermediaries": {
      "enabled": true,
      "parameters": {}
    }
  }
}

Key Design Decision: RECOVER, unlike other actions, has the character of “reverting” state. While this appears to conflict with blockchain’s immutability principle, it is justified under the Selective Immutability paradigm explored in our rollback mechanisms research.

OSS Validation Pipeline

Four-Stage Validation Process

The Oracle State Synchronizer (OSS) validates all incoming regulatory action messages through a four-stage pipeline:

Stage 1: Authority Verification

package oss

import (
    "context"
    "errors"
)

var (
    ErrAuthorityNotRegistered     = errors.New("AUTHORITY_NOT_REGISTERED")
    ErrJurisdictionMismatch       = errors.New("JURISDICTION_MISMATCH")
    ErrActionNotPermitted         = errors.New("ACTION_NOT_PERMITTED")
    ErrCriticalPriorityNotAllowed = errors.New("CRITICAL_PRIORITY_NOT_AUTHORIZED")
)

type AuthorityVerificationResult struct {
    Verified  bool
    Authority *RegisteredAuthority
}

func (v *Validator) VerifyAuthority(ctx context.Context, msg *RegulatoryActionMessage) (*AuthorityVerificationResult, error) {
    authority := msg.RegulatoryPayload.Authority
    
    // 1. Verify authorityId exists in Registry
    registeredAuthority, err := v.authorityRegistry.Get(ctx, authority.AuthorityID)
    if err != nil || registeredAuthority == nil {
        return nil, ErrAuthorityNotRegistered
    }
    
    // 2. Check jurisdiction scope
    targetJurisdiction, err := v.getAssetJurisdiction(ctx, msg.RegulatoryPayload.TargetAsset)
    if err != nil {
        return nil, err
    }
    
    if !containsJurisdiction(authority.Jurisdiction, targetJurisdiction) {
        return nil, ErrJurisdictionMismatch
    }
    
    // 3. Verify permissions for action type
    actionPermissions := registeredAuthority.Permissions[authority.AuthorityType]
    if !containsAction(actionPermissions, msg.RegulatoryPayload.ActionType) {
        return nil, ErrActionNotPermitted
    }
    
    // 4. Validate priority level
    if authority.PriorityLevel == PriorityCritical && !registeredAuthority.CanIssueCritical {
        return nil, ErrCriticalPriorityNotAllowed
    }
    
    return &AuthorityVerificationResult{
        Verified:  true,
        Authority: registeredAuthority,
    }, nil
}

Stage 2: State Transition Check

package oss

var (
    ErrStateHashMismatch           = errors.New("STATE_HASH_MISMATCH")
    ErrFreezeRequiredBeforeSeize   = errors.New("FREEZE_REQUIRED_BEFORE_SEIZE")
    ErrSeizeRequiredBeforeConfiscate = errors.New("SEIZE_REQUIRED_BEFORE_CONFISCATE")
    ErrInvalidStateTransition      = errors.New("INVALID_STATE_TRANSITION")
)

// ValidTransitions defines permitted starting states for each action
var ValidTransitions = map[ActionType][]LockStatus{
    ActionFreeze:     {StatusAvailable, StatusReserved},
    ActionSeize:      {StatusRestricted},  // Must be frozen first
    ActionConfiscate: {StatusSeized},       // Must be seized first
    ActionLiquidate:  {StatusAvailable, StatusRestricted, StatusSeized},
    ActionRestrict:   {StatusAvailable},
    ActionRecover:    {StatusRestricted, StatusSeized},
}

type StateTransitionResult struct {
    Valid        bool
    CurrentState *AssetState
}

func (v *Validator) CheckStateTransition(ctx context.Context, msg *RegulatoryActionMessage) (*StateTransitionResult, error) {
    actionType := msg.RegulatoryPayload.ActionType
    targetAsset := msg.RegulatoryPayload.TargetAsset
    
    // Query current state from RWA Registry
    currentState, err := v.rwaRegistry.GetState(ctx, targetAsset.AssetID)
    if err != nil {
        return nil, err
    }
    
    // Verify state hash match (concurrency control)
    if currentState.StateHash != targetAsset.CurrentStateHash {
        return nil, ErrStateHashMismatch
    }
    
    // Check valid transition
    validFromStates, exists := ValidTransitions[actionType]
    if !exists {
        return nil, ErrInvalidStateTransition
    }
    
    if !containsStatus(validFromStates, currentState.LockStatus) {
        // Check escalation requirements
        if actionType == ActionSeize && currentState.LockStatus == StatusAvailable {
            return nil, ErrFreezeRequiredBeforeSeize
        }
        if actionType == ActionConfiscate && currentState.LockStatus != StatusSeized {
            return nil, ErrSeizeRequiredBeforeConfiscate
        }
        return nil, ErrInvalidStateTransition
    }
    
    return &StateTransitionResult{
        Valid:        true,
        CurrentState: currentState,
    }, nil
}

Stage 3: Legal Basis Verification

package oss

import "time"

var (
    ErrInvalidLegalDocumentStructure = errors.New("INVALID_LEGAL_DOCUMENT_STRUCTURE")
    ErrEvidenceHashInvalid           = errors.New("EVIDENCE_HASH_INVALID")
    ErrLegalBasisExpired             = errors.New("LEGAL_BASIS_EXPIRED_OR_NOT_YET_VALID")
    ErrAppealPeriodNotExpired        = errors.New("APPEAL_PERIOD_NOT_EXPIRED")
)

type LegalBasisResult struct {
    Verified bool
}

func (v *Validator) VerifyLegalBasis(ctx context.Context, msg *RegulatoryActionMessage) (*LegalBasisResult, error) {
    legalBasis := msg.RegulatoryPayload.Authority.LegalBasis
    evidence := msg.RegulatoryPayload.Evidence
    
    // 1. Validate legal document structure
    if !v.isValidLegalDocument(legalBasis) {
        return nil, ErrInvalidLegalDocumentStructure
    }
    
    // 2. Verify evidence hash integrity
    for _, hash := range evidence.DocumentHashes {
        verified, err := v.verifyDocumentHash(ctx, hash)
        if err != nil || !verified {
            return nil, ErrEvidenceHashInvalid
        }
    }
    
    // 3. Check temporal validity
    now := time.Now()
    issuedAt := legalBasis.IssuedAt
    
    if now.Before(issuedAt) {
        return nil, ErrLegalBasisExpired
    }
    
    if legalBasis.ValidUntil != nil && now.After(*legalBasis.ValidUntil) {
        return nil, ErrLegalBasisExpired
    }
    
    // 4. Additional finality proof verification for confiscation
    if msg.RegulatoryPayload.ActionType == ActionConfiscate {
        finalityProof := msg.RegulatoryPayload.ActionParameters.(*ConfiscateParams).FinalityProof
        if !finalityProof.AppealDeadlinePassed {
            return nil, ErrAppealPeriodNotExpired
        }
    }
    
    return &LegalBasisResult{Verified: true}, nil
}

Stage 4: Cross-chain Consistency Check

package oss

import "sync"

var (
    ErrCrossChainStateConflict   = errors.New("CROSS_CHAIN_STATE_CONFLICT")
    ErrAtomicCommitNotSupported  = errors.New("ATOMIC_COMMIT_NOT_SUPPORTED")
)

type CrossChainConsistencyResult struct {
    Consistent  bool
    ChainStates map[string]*AssetState
}

func (v *Validator) CheckCrossChainConsistency(ctx context.Context, msg *RegulatoryActionMessage) (*CrossChainConsistencyResult, error) {
    crossChainScope := msg.CrossChainScope
    targetAsset := msg.RegulatoryPayload.TargetAsset
    
    // 1. Query current states from target chains (parallel)
    chainStates := make(map[string]*AssetState)
    var mu sync.Mutex
    var wg sync.WaitGroup
    errChan := make(chan error, len(crossChainScope.TargetChains))
    
    for _, chainID := range crossChainScope.TargetChains {
        wg.Add(1)
        go func(cid string) {
            defer wg.Done()
            state, err := v.crossChainBridge.QueryState(ctx, cid, targetAsset.AssetID)
            if err != nil {
                errChan <- err
                return
            }
            mu.Lock()
            chainStates[cid] = state
            mu.Unlock()
        }(chainID)
    }
    wg.Wait()
    close(errChan)
    
    if err := <-errChan; err != nil {
        return nil, err
    }
    
    // 2. Detect state conflicts
    stateConflicts := v.detectStateConflicts(chainStates)
    if len(stateConflicts) > 0 {
        resolved, err := v.attemptConflictResolution(ctx, stateConflicts)
        if err != nil || !resolved {
            return nil, ErrCrossChainStateConflict
        }
    }
    
    // 3. Verify atomicity feasibility
    if crossChainScope.AtomicityRequirement == AtomicityAllOrNothing {
        for _, chainID := range crossChainScope.TargetChains {
            bridgeStatus, err := v.crossChainBridge.GetStatus(ctx, chainID)
            if err != nil {
                return nil, err
            }
            if !bridgeStatus.SupportsAtomicCommit {
                return nil, fmt.Errorf("%w: chainId=%s", ErrAtomicCommitNotSupported, chainID)
            }
        }
    }
    
    // 4. Verify execution feasibility within timeout
    estimatedTime := v.estimateExecutionTime(crossChainScope.TargetChains)
    if estimatedTime > time.Duration(crossChainScope.TimeoutSeconds)*time.Second*8/10 {
        v.logger.Warn("Execution time may exceed timeout", 
            "estimatedTime", estimatedTime,
            "timeout", crossChainScope.TimeoutSeconds)
    }
    
    return &CrossChainConsistencyResult{
        Consistent:  true,
        ChainStates: chainStates,
    }, nil
}

D-quencer Priority Handling

Multi-Priority Queue Architecture

D-quencer processes regular transactions and regulatory actions distinctly. On top of the D-quencer consensus algorithm detailed in our core component documentation, a regulatory-specific priority system is added:

package dquencer

import (
    "container/heap"
    "sync"
)

type PriorityLevel int

const (
    PriorityCritical   PriorityLevel = iota // P0: Emergency regulatory actions
    PriorityRegulatory                       // P1: Standard regulatory actions
    PriorityHigh                             // P2: High priority regular transactions
    PriorityNormal                           // P3: Normal transactions
    PriorityLow                              // P4: Low priority
)

type RegulatoryPriorityQueue struct {
    queues              map[PriorityLevel]*MaxHeap
    regulatoryTxPerBlock int
    mu                  sync.RWMutex
}

func NewRegulatoryPriorityQueue() *RegulatoryPriorityQueue {
    rpq := &RegulatoryPriorityQueue{
        queues:              make(map[PriorityLevel]*MaxHeap),
        regulatoryTxPerBlock: 20,
    }
    
    for _, level := range []PriorityLevel{
        PriorityCritical, PriorityRegulatory, PriorityHigh, PriorityNormal, PriorityLow,
    } {
        rpq.queues[level] = NewMaxHeap()
    }
    
    return rpq
}

func (rpq *RegulatoryPriorityQueue) Enqueue(tx *Transaction) {
    rpq.mu.Lock()
    defer rpq.mu.Unlock()
    
    priority := rpq.determinePriority(tx)
    heap.Push(rpq.queues[priority], &HeapItem{
        Value:    tx,
        Priority: tx.Timestamp.UnixNano(),
    })
}

func (rpq *RegulatoryPriorityQueue) determinePriority(tx *Transaction) PriorityLevel {
    if tx.MessageType != MessageTypeRegulatoryAction {
        if tx.PriorityHint != nil {
            return *tx.PriorityHint
        }
        return PriorityNormal
    }
    
    authority := tx.RegulatoryPayload.Authority
    
    // CRITICAL: Emergency freeze, seize, confiscate
    if authority.PriorityLevel == "CRITICAL" ||
        authority.LegalBasis.DocumentType == DocumentTypeEmergencyOrder {
        return PriorityCritical
    }
    
    // REGULATORY: Standard regulatory actions
    return PriorityRegulatory
}

func (rpq *RegulatoryPriorityQueue) DequeueForBlock(blockCapacity int) []*Transaction {
    rpq.mu.Lock()
    defer rpq.mu.Unlock()
    
    selected := make([]*Transaction, 0, blockCapacity)
    regulatoryCount := 0
    
    // CRITICAL always processed first
    for rpq.queues[PriorityCritical].Len() > 0 && len(selected) < blockCapacity {
        item := heap.Pop(rpq.queues[PriorityCritical]).(*HeapItem)
        selected = append(selected, item.Value.(*Transaction))
        regulatoryCount++
    }
    
    // REGULATORY subject to per-block limit
    for rpq.queues[PriorityRegulatory].Len() > 0 &&
        regulatoryCount < rpq.regulatoryTxPerBlock &&
        len(selected) < blockCapacity {
        item := heap.Pop(rpq.queues[PriorityRegulatory]).(*HeapItem)
        selected = append(selected, item.Value.(*Transaction))
        regulatoryCount++
    }
    
    // Fill remaining capacity with regular transactions
    for _, priority := range []PriorityLevel{PriorityHigh, PriorityNormal, PriorityLow} {
        for rpq.queues[priority].Len() > 0 && len(selected) < blockCapacity {
            item := heap.Pop(rpq.queues[priority]).(*HeapItem)
            selected = append(selected, item.Value.(*Transaction))
        }
    }
    
    return selected
}

Scheduled Regulatory Action Processing

Some regulatory actions require scheduled execution rather than immediate execution. For example, when a court order takes effect on a specific date:

package dquencer

import (
    "context"
    "time"
)

type ScheduledActionStatus string

const (
    StatusPending  ScheduledActionStatus = "PENDING"
    StatusExecuted ScheduledActionStatus = "EXECUTED"
    StatusFailed   ScheduledActionStatus = "FAILED"
)

type ScheduledAction struct {
    ID            string
    Message       *RegulatoryActionMessage
    ExecutionTime time.Time
    Status        ScheduledActionStatus
    RetryPolicy   RetryPolicy
    RetryCount    int
}

type RetryPolicy struct {
    MaxRetries    int
    RetryInterval time.Duration
}

type ScheduledRegulatoryActionManager struct {
    dquencer         *DQuencer
    scheduledActions *TimerQueue
    notifier         Notifier
}

func NewScheduledManager(dq *DQuencer, notifier Notifier) *ScheduledRegulatoryActionManager {
    return &ScheduledRegulatoryActionManager{
        dquencer:         dq,
        scheduledActions: NewTimerQueue(),
        notifier:         notifier,
    }
}

func (m *ScheduledRegulatoryActionManager) ScheduleAction(
    msg *RegulatoryActionMessage,
    executionTime time.Time,
) (string, error) {
    
    scheduledAction := &ScheduledAction{
        ID:            generateID(),
        Message:       msg,
        ExecutionTime: executionTime,
        Status:        StatusPending,
        RetryPolicy: RetryPolicy{
            MaxRetries:    3,
            RetryInterval: time.Minute,
        },
    }
    
    m.scheduledActions.Insert(scheduledAction, executionTime)
    m.setExecutionTimer(scheduledAction)
    
    return scheduledAction.ID, nil
}

func (m *ScheduledRegulatoryActionManager) executeScheduledAction(
    ctx context.Context,
    action *ScheduledAction,
) {
    // Re-validate preconditions at execution time
    if err := m.validatePreconditions(ctx, action.Message); err != nil {
        if action.RetryCount < action.RetryPolicy.MaxRetries {
            action.RetryCount++
            time.AfterFunc(action.RetryPolicy.RetryInterval, func() {
                m.executeScheduledAction(ctx, action)
            })
            return
        }
        action.Status = StatusFailed
        m.notifier.NotifyExecutionFailure(action, err)
        return
    }
    
    // Inject into D-quencer with CRITICAL priority
    m.dquencer.InjectRegulatoryAction(action.Message, PriorityCritical)
    action.Status = StatusExecuted
}

Cross-chain Broadcast Protocol

Three-Phase Atomic Execution

Cross-chain regulatory actions render partial execution legally meaningless. For example, when seizing assets distributed across four chains, success on only three chains fails to achieve the regulatory objective.

Phase 1: PREPARE

package crosschain

import (
    "context"
    "sync"
    "time"
)

type PrepareStatus string

const (
    PrepareReady  PrepareStatus = "READY"
    PrepareFailed PrepareStatus = "PREPARE_FAILED"
)

type PrepareResult struct {
    ChainID       string
    Status        PrepareStatus
    ReservationID string
    Error         string
}

func (b *Broadcaster) PreparePhase(
    ctx context.Context,
    msg *RegulatoryActionMessage,
) ([]PrepareResult, error) {
    
    crossChainScope := msg.CrossChainScope
    regulatoryPayload := msg.RegulatoryPayload
    
    results := make([]PrepareResult, 0, len(crossChainScope.TargetChains))
    var mu sync.Mutex
    var wg sync.WaitGroup
    
    for _, chainID := range crossChainScope.TargetChains {
        wg.Add(1)
        go func(cid string) {
            defer wg.Done()
            
            result, err := b.bridge.SendPrepare(ctx, cid, &PrepareRequest{
                ActionType:  regulatoryPayload.ActionType,
                TargetAsset: regulatoryPayload.TargetAsset,
                StateReservation: StateReservation{
                    LockUntil:     time.Now().Add(time.Duration(crossChainScope.TimeoutSeconds) * time.Second),
                    ReservationID: generateReservationID(),
                },
            })
            
            mu.Lock()
            defer mu.Unlock()
            
            if err != nil {
                results = append(results, PrepareResult{
                    ChainID: cid,
                    Status:  PrepareFailed,
                    Error:   err.Error(),
                })
                return
            }
            
            results = append(results, PrepareResult{
                ChainID:       cid,
                Status:        PrepareReady,
                ReservationID: result.ReservationID,
            })
        }(chainID)
    }
    wg.Wait()
    
    // Check quorum
    readyCount := 0
    for _, r := range results {
        if r.Status == PrepareReady {
            readyCount++
        }
    }
    
    if crossChainScope.AtomicityRequirement == AtomicityAllOrNothing &&
        readyCount != len(crossChainScope.TargetChains) {
        // Cancel all reservations
        if err := b.rollbackPrepare(ctx, results); err != nil {
            b.logger.Error("Failed to rollback prepare", "error", err)
        }
        return nil, ErrPreparePhasesFailed
    }
    
    return results, nil
}

Phase 2: COMMIT

package crosschain

type CommitStatus string

const (
    CommitCommitted CommitStatus = "COMMITTED"
    CommitFailed    CommitStatus = "COMMIT_FAILED"
)

type CommitResult struct {
    ChainID     string
    Status      CommitStatus
    TxHash      string
    BlockNumber uint64
    Error       string
}

func (b *Broadcaster) CommitPhase(
    ctx context.Context,
    prepareResults []PrepareResult,
    msg *RegulatoryActionMessage,
) ([]CommitResult, error) {
    
    crossChainScope := msg.CrossChainScope
    regulatoryPayload := msg.RegulatoryPayload
    
    // Filter only READY chains
    readyChains := make([]PrepareResult, 0)
    for _, r := range prepareResults {
        if r.Status == PrepareReady {
            readyChains = append(readyChains, r)
        }
    }
    
    commitResults := make([]CommitResult, 0, len(readyChains))
    var mu sync.Mutex
    var wg sync.WaitGroup
    
    for _, prepared := range readyChains {
        wg.Add(1)
        go func(p PrepareResult) {
            defer wg.Done()
            
            signature, _ := b.signCommitMessage(p.ChainID, regulatoryPayload)
            result, err := b.bridge.SendCommit(ctx, p.ChainID, &CommitRequest{
                ReservationID:     p.ReservationID,
                RegulatoryPayload: regulatoryPayload,
                Signature:         signature,
            })
            
            mu.Lock()
            defer mu.Unlock()
            
            if err != nil {
                commitResults = append(commitResults, CommitResult{
                    ChainID: p.ChainID,
                    Status:  CommitFailed,
                    Error:   err.Error(),
                })
                return
            }
            
            commitResults = append(commitResults, CommitResult{
                ChainID:     p.ChainID,
                Status:      CommitCommitted,
                TxHash:      result.TxHash,
                BlockNumber: result.BlockNumber,
            })
        }(prepared)
    }
    wg.Wait()
    
    // Handle failures based on atomicity level
    failedCommits := make([]CommitResult, 0)
    for _, r := range commitResults {
        if r.Status == CommitFailed {
            failedCommits = append(failedCommits, r)
        }
    }
    
    if len(failedCommits) > 0 {
        return b.handleCommitFailures(ctx, commitResults, crossChainScope.AtomicityRequirement, msg)
    }
    
    return commitResults, nil
}

func (b *Broadcaster) handleCommitFailures(
    ctx context.Context,
    commitResults []CommitResult,
    atomicityLevel AtomicityRequirement,
    msg *RegulatoryActionMessage,
) ([]CommitResult, error) {
    
    switch atomicityLevel {
    case AtomicityBestEffort:
        // Keep successful chains, log failures
        succeeded := make([]CommitResult, 0)
        failed := make([]CommitResult, 0)
        for _, r := range commitResults {
            if r.Status == CommitCommitted {
                succeeded = append(succeeded, r)
            } else {
                failed = append(failed, r)
            }
        }
        b.logger.Warn("Partial commit success", 
            "succeeded", len(succeeded), 
            "failed", len(failed))
        return commitResults, nil
        
    case AtomicityGuaranteed:
        // Retry failed chains with exponential backoff
        for _, failed := range commitResults {
            if failed.Status == CommitFailed {
                go b.retryWithBackoff(ctx, failed.ChainID, msg, RetryConfig{
                    MaxRetries:   5,
                    InitialDelay: time.Second,
                    MaxDelay:     30 * time.Second,
                })
            }
        }
        return commitResults, nil
        
    case AtomicityAllOrNothing:
        // Rollback all chains
        successfulCommits := make([]CommitResult, 0)
        for _, r := range commitResults {
            if r.Status == CommitCommitted {
                successfulCommits = append(successfulCommits, r)
            }
        }
        if err := b.rollbackCommits(ctx, successfulCommits); err != nil {
            b.logger.Error("Rollback failed", "error", err)
        }
        return nil, ErrAtomicCommitFailed
    }
    
    return commitResults, nil
}

Phase 3: FINALIZE

package crosschain

type FinalizeResult struct {
    Status         string
    AggregateProof *CrossChainProof
    RegistryUpdate *RegistryUpdateResult
}

func (b *Broadcaster) FinalizePhase(
    ctx context.Context,
    commitResults []CommitResult,
    msg *RegulatoryActionMessage,
) (*FinalizeResult, error) {
    
    // 1. Generate aggregate cross-chain proof
    aggregateProof, err := b.generateCrossChainProof(commitResults)
    if err != nil {
        return nil, fmt.Errorf("failed to generate proof: %w", err)
    }
    
    // 2. Update RWA Registry on origin chain (Oraclizer L3)
    chainIDs := make([]string, 0, len(commitResults))
    txHashes := make([]string, 0, len(commitResults))
    for _, r := range commitResults {
        chainIDs = append(chainIDs, r.ChainID)
        txHashes = append(txHashes, r.TxHash)
    }
    
    registryUpdate, err := b.rwaRegistry.UpdateState(ctx, &RegistryUpdateRequest{
        AssetID:  msg.RegulatoryPayload.TargetAsset.AssetID,
        NewState: deriveNewState(msg.RegulatoryPayload.ActionType),
        CrossChainProof: aggregateProof,
        ExecutionDetails: ExecutionDetails{
            Timestamp:         time.Now(),
            AffectedChains:    chainIDs,
            TransactionHashes: txHashes,
        },
    })
    if err != nil {
        return nil, fmt.Errorf("failed to update registry: %w", err)
    }
    
    // 3. Emit event
    b.eventEmitter.Emit("REGULATORY_ACTION_FINALIZED", map[string]interface{}{
        "actionId":           msg.MessageID,
        "actionType":         msg.RegulatoryPayload.ActionType,
        "targetAsset":        msg.RegulatoryPayload.TargetAsset.AssetID,
        "authority":          msg.RegulatoryPayload.Authority.AuthorityID,
        "affectedChains":     len(commitResults),
        "aggregateProofHash": aggregateProof.Hash,
        "registryUpdateTx":   registryUpdate.TxHash,
    })
    
    return &FinalizeResult{
        Status:         "FINALIZED",
        AggregateProof: aggregateProof,
        RegistryUpdate: registryUpdate,
    }, nil
}

DeFi Protocol Integration Guide

Regulatory Event Subscription API

DeFi protocol developers can subscribe to Oraclizer’s regulatory events for automatic response:

package integration

import (
    "context"
    "log"
    
    oraclizer "github.com/oraclizer/sdk-go"
)

func SetupRegulatoryEventSubscription(ctx context.Context) error {
    // Initialize Oraclizer client
    client, err := oraclizer.NewClient(oraclizer.Config{
        Endpoint: "wss://api.oraclizer.io/v1",
        APIKey:   os.Getenv("ORACLIZER_API_KEY"),
    })
    if err != nil {
        return err
    }
    
    // Get list of managed assets
    managedAssets, err := getProtocolManagedAssets(ctx)
    if err != nil {
        return err
    }
    
    // Subscribe to regulatory events
    subscription, err := client.Subscribe(ctx, oraclizer.SubscriptionConfig{
        EventType: "REGULATORY_ACTION",
        AssetFilter: managedAssets,
        ActionTypes: []string{"FREEZE", "SEIZE", "CONFISCATE", "LIQUIDATE"},
    })
    if err != nil {
        return err
    }
    
    // Handle events
    go func() {
        for event := range subscription.Events() {
            handleRegulatoryAction(ctx, event)
        }
    }()
    
    return nil
}

func handleRegulatoryAction(ctx context.Context, event *oraclizer.RegulatoryEvent) {
    actionType := event.ActionType
    targetAsset := event.TargetAsset
    
    switch actionType {
    case "FREEZE":
        // Exclude from collateral valuation
        if err := collateralManager.MarkAsFrozen(ctx, targetAsset.AssetID); err != nil {
            log.Printf("Failed to mark asset as frozen: %v", err)
        }
        // Suspend liquidation for positions based on this collateral
        if err := liquidationEngine.SuspendForAsset(ctx, targetAsset.AssetID); err != nil {
            log.Printf("Failed to suspend liquidation: %v", err)
        }
        
    case "SEIZE":
        // Fully exclude from collateral
        if err := collateralManager.RemoveFromCollateral(ctx, targetAsset.AssetID); err != nil {
            log.Printf("Failed to remove from collateral: %v", err)
        }
        // Initiate forced liquidation for related positions
        if err := liquidationEngine.InitiateForAsset(ctx, targetAsset.AssetID); err != nil {
            log.Printf("Failed to initiate liquidation: %v", err)
        }
        
    case "LIQUIDATE":
        // Coordinate protocol liquidation with regulatory liquidation
        if err := coordinateWithRegulatoryLiquidation(ctx, event); err != nil {
            log.Printf("Failed to coordinate liquidation: %v", err)
        }
    }
}

Regulatory Status Query API

package integration

// Query current regulatory status of an asset
func QueryAssetRegulatoryStatus(ctx context.Context, client *oraclizer.Client, assetID string) (*RegulatoryStatus, error) {
    status, err := client.GetAssetRegulatoryStatus(ctx, oraclizer.StatusQuery{
        AssetID:         assetID,
        IncludeHistory:  true,
        CrossChainScope: []string{"ethereum", "arbitrum", "optimism"},
    })
    if err != nil {
        return nil, err
    }
    
    return status, nil
}

// Response structure example:
// {
//     AssetID: "0x742d35...",
//     CurrentStatus: {
//         LockStatus: "RESTRICTED",
//         ActiveActions: [{
//             ActionType: "FREEZE",
//             Authority:  "SEC",
//             Since:      "2024-03-15T10:30:00Z",
//             ExpiresAt:  nil,
//             ExemptOperations: ["VIEW"],
//         }],
//         LastUpdated: "2024-03-15T10:30:05Z",
//     },
//     CrossChainStatus: {
//         "ethereum": {Synced: true, Status: "RESTRICTED"},
//         "arbitrum": {Synced: true, Status: "RESTRICTED"},
//         "optimism": {Synced: true, Status: "RESTRICTED"},
//     },
//     History: [/* Past regulatory action history */],
// }

Important Note: Even if a DeFi protocol does not respond to regulatory events, transfers of the asset are already blocked at the Oraclizer L3 level. However, protocol-level measures (such as excluding from collateral valuation) must be explicitly implemented by each protocol.


Conclusion: Complete Protocolization of Enforceability

In this research, we transformed the philosophical foundation of enforceability into actually implementable protocol specification.

For each of the six regulatory actions:

  • OIP message formats were defined to clearly encode regulatory intent
  • The OSS validation pipeline systematically validates authority, state, legal basis, and cross-chain consistency
  • The D-quencer priority system guarantees emergency regulatory actions are processed without delay
  • Three-phase cross-chain broadcast technically prevents the legal meaninglessness of partial execution

Combined with our asset state management framework, Oraclizer now possesses both state definition (what) and state modification (how).

“When code enforces law, that code must reflect the procedural legitimacy of law. No CONFISCATE without SEIZE, no SEIZE without FREEZE. This is due process implemented as protocol.”

In upcoming research, we will explore cross-chain address systems and ERC-3770 integration, examining how standardized chain-specific address formats enable seamless regulatory action execution across heterogeneous blockchain environments.


References

  1. Ethereum Improvement Proposals. (2021). EIP-3770: Chain-specific addresses. https://eips.ethereum.org/EIPS/eip-3770
  2. Financial Stability Board. (2023). Global Regulatory Framework for Crypto-asset Activities. https://www.fsb.org/2023/07/high-level-recommendations-for-the-regulation-supervision-and-oversight-of-crypto-asset-activities-and-markets-final-report/
  3. FATF. (2021). Updated Guidance for a Risk-Based Approach for Virtual Assets and Virtual Asset Service Providers. https://www.fatf-gafi.org/en/publications/Fatfrecommendations/Guidance-rba-virtual-assets-2021.html

Read Next

Insurance and Recovery Economics: Preparing for Black Swan Events
Earlier designs cut node risk by 73%, but the unpredictable 27% needs different rules. This study fixes how a staking insurance pool is sized (15% of stake, not protected value), bootstrapped, and banded; why a reserve held in its own token collapses with it; and how session protection follows the sync-degree hierarchy when security breaks mid-session.
Oraclizer Core ⋅ May 29, 2026
Tokenized Securities Under the CLARITY Act: The Weight of Codification
The CLARITY Act tokenized securities clause settles a single proposition in statute: tokenization is a delivery method, not a new asset class. That one sentence codifies the regulatory status of tokenized securities in U.S. law for the first time and derives an entire infrastructure specification for boundaries the token crosses.
Oraclizer Core ⋅ May 23, 2026
Sync Degree Hierarchy: Classifying What Assets Demand from State Synchronization
Sync degree hierarchy turns sync requirement strength into a four-level classification axis for RWA assets. S₀ static through S₃ atomic state binding form a reduction relation where causal consistency separates S₁ from S₂. Existing oracles, structurally two independent channels, are capped at S₁ by definition. Regulatory action forces S₃.
Oraclizer Core ⋅ May 20, 2026
Why RWA Isn’t Real DeFi Collateral Yet: The Non-Atomicity of the Collateral Layer
Tokenized RWA-backed stablecoin supply reached $8.5B, yet only 12% operates inside DeFi. Aave Horizon's dual structure separates rather than solves regulatory state synchronization. Three conditions from cross-border securities trading transfer into the DeFi collateral layer, with a fourth condition added when the protocol becomes a regulatory subject.
Oraclizer Core ⋅ May 14, 2026