Suspected Bug: Clarity 4 To Pre-Clarity 4 Contract Fails

Summary

A Clarity 4 contract deployed after SIP-033/034 activation (Bitcoin block 923,222) cannot execute contract-call? to a contract deployed before the Clarity 4 epoch. Every call — including plain read-only calls with no as-contract? — fails at the VM level with ContractCallExpectName before any contract logic executes. The VM cannot resolve the target contract reference when the call originates from a Clarity 4 contract.

This is not an authorization error, not an as-contract? issue, and not a parameter mismatch. The target contract is fully functional when called directly from a wallet.

How to Reproduce

Deploy two identical minimal contracts to mainnet — one as Clarity 2, one as Clarity 4:

;; Deploy this exact code twice:
;; Once as Clarity 2 (contract name: test-crossepoch-c2)
;; Once as Clarity 4 (contract name: test-crossepoch-c4)

(define-public (test-read (name (buff 48)))
(ok (contract-call?
'SP2QEZ06AGJ3RKJPBV14SY1V5BBFNAW33D96YPGZF.BNS-V2
get-bns-info
name
0x627463)))

Call test-read on both contracts with any name registered in the .btc namespace (e.g. 0x74657374 for “test”, or any known registered name — the name buffer should contain only the name, not the namespace).

Expected behavior: Both return the BNS info tuple for the name.

Predicted behavior based on mainnet evidence: The Clarity 2 contract succeeds. The Clarity 4 contract fails with ContractCallExpectName at the VM level — no contract logic executes.

The target function (get-bns-info) is a define-read-only on BNS-V2. It takes a name buffer and a namespace buffer and returns a map lookup. There is no authorization check, no write, no asset transfer. The failure is purely in cross-epoch contract reference resolution.

Evidence from Mainnet

Three transactions demonstrate the issue in a real-world scenario where a Clarity 4 manager contract calls BNS-V2 (a pre-Clarity 4 contract):

Transaction 1 — Write call with as-contract?: Clarity 4 contract calls BNS-V2.name-claim-fast via as-contract?. Result: ContractCallExpectName, write count 0. Initial hypothesis was as-contract? compatibility.

Transaction 2 — Read-only call, NO as-contract?: Same Clarity 4 contract calls BNS-V2.get-bns-info via plain contract-call?. Result: ContractCallExpectName. This eliminates as-contract? as the cause — the VM fails on a plain contract-call? to a read-only function with no authorization checks.

Transaction 3 — Direct wallet call to BNS-V2: Same wallet calls BNS-V2.name-claim-fast directly (no intermediary contract). Result: (err u102) — a proper contract-level error (ERR-NOT-AUTHORIZED). BNS-V2 executes correctly, evaluates its logic, and returns a meaningful error. The issue is exclusively in cross-epoch contract-call resolution.

Transaction hashes available on request.

Root Cause Analysis

The Clarity VM appears unable to resolve contract principal references when contract-call? originates from a Clarity 4 contract and targets a contract deployed before the Clarity 4 epoch. The error ContractCallExpectName fires before any contract logic is evaluated — this is a VM-level name resolution failure, not a contract execution error.

Key observations:

  • The target contract (BNS-V2) works correctly when called directly from a wallet (Transaction 3)

  • The failure occurs on plain contract-call?as-contract? is not required to trigger it (Transaction 2)

  • The failure occurs on read-only functions with no authorization checks — this is not a permissions issue

  • The calling contract compiles and deploys without errors — the contract reference is syntactically valid

Impact

Any Clarity 4 → pre-Clarity 4 interaction is potentially broken

This affects any Clarity 4 contract that needs to call any pre-Clarity 4 contract. The most severe cases are managed namespaces on BNS-V2, because:

  1. BNS-V2 requires all managed namespace operations to come from the namespace-manager contract via contract-caller checks

  2. If the manager contract was deployed as Clarity 4, it cannot call any BNS-V2 function

  3. The mng-manager-transfer function (to transfer the manager role to a working contract) also requires contract-caller == manager — creating a circular lockout

  4. BNS-V2 has no deployer override, no emergency function, and no alternative authorization path for launched namespaces

This results in a permanent, irrecoverable lockout of the namespace. No names can be minted, transferred, burned, listed, or managed. The manager cannot be transferred to a new contract. There is no on-chain escape route.

Broader ecosystem risk

Any DeFi protocol, DAO, or application that deployed a Clarity 4 contract as a manager or controller for a pre-Clarity 4 system is potentially affected. The bug is silent until the first cross-epoch contract-call? is attempted.

Relevant Precedent

SIP-023: The Stacks 2.2 epoch introduced a bug that broke trait semantics in contract-calls, deviating from the behavior established in SIP-015 / Stacks 2.1. SIP-023 was ratified as an emergency fix, creating the Stacks 2.3 epoch to restore correct trait argument handling. That bug similarly affected cross-epoch contract interoperability and required a consensus-level fix.

Requested Resolution

  1. VM fix: Patch the Clarity VM to correctly resolve contract references when contract-call? crosses epoch boundaries

  2. State intervention for affected namespaces: For BNS-V2 managed namespaces that are permanently locked due to this bug, reassign the namespace-manager to the namespace-import principal (or a designated proxy contract) via coordinated state modification, so operators can recover control once the VM is patched