> For the complete documentation index, see [llms.txt](https://docs.creditcoin.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.creditcoin.org/usc/dapp-builder-infrastructure/universal-smart-contracts.md).

# Universal Smart Contracts

{% hint style="danger" %}
Please note that all information and code snippets provided in this section are for educational purposes only and not to be directly deployed in production.
{% endhint %}

## What is the Universal Smart Contract

**Universal Smart Contracts** (USC) act as an adapter which extends existing smart contracts with cross-chain capabilities, allowing contracts to verify data from external blockchains provided via the **Creditcoin Decentralized Oracle**.

Unlike traditional omnichain or cross-chain solutions that focus narrowly on token transfers or specific assets, USC provides a **general-purpose execution layer**. This enables contracts to act on externally verified data *without needing to rewrite core logic*. By adopting USC into their tech stack, developers can transform their contracts into *universal* components powered by seamless cross-chain data, allowing for novel patterns of interoperability across multiple blockchains.

## USC Contract Architecture

USC contracts verify cross-chain proofs and execute business logic. **DApp Business Logic Contracts** are contracts deployed on Creditcoin that contain the DApp's state and business logic. In the example implementation (`SimpleMinterUSC`), the business logic (ERC20 token minting) is integrated directly into the USC contract itself. While, this combined pattern works well for simple use cases, for more complex DApps, developers can separate concerns by deploying distinct contracts: a USC contract that handles the core USC responsibilities and separate business logic contracts that the USC contract calls after verification succeeds. Both patterns are valid; the choice depends on the complexity and requirements of the DApp. Business logic contracts are considered part of the USC architecture since they execute based on verified cross-chain data provided by the USC contract.

## How USC Works

USC contracts verify cross-chain transaction data using the **Native Query Verifier Precompile** (address `0x0FD2`), a built-in runtime component that provides synchronous verification of Merkle and continuity proofs.  USC contracts integrate with it by calling its `verify()`  (or alternatively `verifyAndEmit()` ) function directly to verify proofs before processing cross-chain data. Once verified, USC contracts extract transaction and event data directly from the verified transaction bytes and execute DApp-specific business logic.

**Key characteristics:**

* **Synchronous verification**: Proofs are verified in the same transaction, no async processing
* **Direct data extraction**: Transaction and event data is extracted directly from verified transaction bytes
* **Replay protection**: USC contracts implement mechanisms to prevent duplicate processing
* **Native-speed execution**: The precompile runs as native Rust code for optimal performance

{% hint style="danger" %}
The native verifier precompile ***does not*** validate if a transaction was successful or not. It only validates if a transaction is included in a block and that block is really a part of the confirmed source chain. Therefore, USC enabled dApp contracts **MUST** check the "status" field of the transaction to ensure security  `0x1` → ✅ **Success**
{% endhint %}

## Core USC Contract Pattern

A typical USC contract follows this pattern:

1. **Receives proofs and transaction data** from an off-chain worker
2. **Implements replay protection** to prevent duplicate processing
3. **Calls the Native Query Verifier Precompile** to verify proofs synchronously
4. **Extracts transaction/event data** from verified transaction bytes
5. **Executes business logic** based on the verified data

### Example USC Contract

See [`USCMinter.sol`](https://github.com/gluwa/usc-testnet-bridge-examples/blob/main/contracts/sol/USCMinter.sol)  for a complete USC implementation. The contract:

* Receives proofs and transaction data from offchain worker
* Implements replay protection using a `processedQueries` mapping
* Uses the Native Query Verifier Precompile to verify proofs
* Validates transaction type and receipt status (must be successful)
* Extracts event data from verified transaction bytes using `EvmV1Decoder`
* Executes business logic (ERC20 token minting) within the same contract that mints tokens once a burn event is verified from the source chain

**Key function signature:**

```solidity
function mintFromQuery(
    uint64 chainKey,
    uint64 blockHeight,
    bytes calldata encodedTransaction,
    bytes32 merkleRoot,
    INativeQueryVerifier.MerkleProofEntry[] calldata siblings,
    bytes32 lowerEndpointDigest,
    bytes32[] calldata continuityRoots
) external returns (bool success)
```

### DApp Business Logic Contracts

DApp Business Logic Contracts are smart contracts deployed on Creditcoin that contain the DApp's state and business logic. They are considered part of the USC architecture because they execute based on verified cross-chain data provided by USC contracts.

In the example implementation (`SimpleMinterUSC`), the business logic is integrated directly into the USC contract. The contract:

* Stores DApp state (e.g., token balances via ERC20)
* Implements DApp-specific logic (e.g., minting tokens)
* Executes business logic immediately after verifying cross-chain proofs and validating transaction contents
* Validates inputs and updates state accordingly

### Transaction Data Extraction

After verification succeeds, USC contracts extract transaction and event data from the `encodedTransaction` bytes as part of the transaction content validation process. The transaction encoding follows a deterministic format that includes:

* **Transaction fields**: Type, chain ID, nonce, from address, to address, value, etc.
* **Receipt fields**: Status, gas used, logs (events)
* **Event data**: Topics and data from transaction receipt logs

USC contracts can use libraries like `EvmV1Decoder` to selectively extract specific events or transaction fields only needed for their business logic. This selective extraction allows USC contracts to efficiently validate specific events or transaction fields needed for their business logic without decoding the entire transaction structure.

### Query Processing Flow

When an oracle query worker provides proof data for a source chain transaction:

1. **Worker generates proofs** using the Proof Generation API server
2. **Worker calls USC contract** with proofs and encoded transaction data
3. **USC contract verifies proofs** synchronously using the Native Query Verifier Precompile
4. **USC contract extracts data** from verified transaction bytes
5. **USC contract executes business logic** immediately in the same transaction

All of this happens synchronously in a single transaction—there is no async query processing or result storage.

### USC Contract Implementation Example

The following sections break down a complete USC contract implementation based on [`USCMinter.sol`](https://github.com/gluwa/usc-testnet-bridge-examples/blob/main/contracts/sol/USCMinter.sol)&#x20;

{% hint style="danger" %}
Since the creation of this article, the USCMinter was updated to better reflect a production ready design. The minter responsibilities were split off into several contracts handling portions of the bridge token minting process. The code here, though not fit for production, more simply and succinctly demonstrates USC design. So it remains unchanged.
{% endhint %}

#### Contract Structure

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {EvmV1Decoder} from "./EvmV1Decoder.sol";

contract SimpleMinterUSC is ERC20 {
    INativeQueryVerifier public immutable VERIFIER;
    mapping(bytes32 => bool) public processedQueries;
    
    // ... rest of contract
}
```

**Key components:**

* **Inherits from ERC20**: The contract uses the combined pattern—it's both a USC (verifies proofs) and a business logic contract (`ERC20` token with minting logic)
* **VERIFIER**: Immutable reference to the Native Query Verifier Precompile at address `0x0FD2`
* **processedQueries**: Mapping for replay protection, preventing duplicate processing of the same transaction

#### Main Entry Point: mintFromQuery

```solidity
function mintFromQuery(
    uint64 chainKey,
    uint64 blockHeight,
    bytes calldata encodedTransaction,
    bytes32 merkleRoot,
    INativeQueryVerifier.MerkleProofEntry[] calldata siblings,
    bytes32 lowerEndpointDigest,
    bytes32[] calldata continuityRoots
) external returns (bool success) {
    // Calculate transaction index from merkle proof path
    uint256 transactionIndex = _calculateTransactionIndex(siblings);
    
    // Check if the query has already been processed
    bytes32 txKey;
    {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, chainKey)
            mstore(add(ptr, 32), shl(192, blockHeight))
            mstore(add(ptr, 40), transactionIndex)
            txKey := keccak256(ptr, 72)
        }
        require(!processedQueries[txKey], "Query already processed");
    }
    
    // First we verify the proof
    bool verified = _verifyProof(
        chainKey, blockHeight, encodedTransaction, merkleRoot, siblings, 
        lowerEndpointDigest, continuityRoots
    );
    require(verified, "Verification failed");
    
    // Mark the query as processed
    processedQueries[txKey] = true;
    
    // Next we validate the transaction contents
    (bool valid, address burntFrom, uint256 burntValue) = _validateTransactionContents(encodedTransaction);
    require(valid, "Transaction contents validation failed");
    
    // Execute business logic (mint tokens) corresponding to the burn on the source chain
    _mint(burntFrom, burntValue);
    
    emit TokensMinted(address(this), burntFrom, burntValue, txKey);
    
    return true;
}
```

**Description:**

* **Parameters**: Receives all proof components and transaction data from the off-chain worker
* **Transaction Index Calculation**: Calculates the transaction index from the Merkle proof path using `_calculateTransactionIndex()`
* **Transaction Key Generation**: Creates a unique key from `chainKey`, `blockHeight`, and `transactionIndex` using assembly for gas efficiency
* **Replay Protection**: Checks if this transaction has already been processed
* **Proof Verification**: Calls `_verifyProof()` to verify the Merkle and continuity proofs synchronously
* **State Update (replay protection)**: Marks the transaction as processed in `processedQueries` mapping
* **Transaction Content Validation**: Validates the transaction contents by checking transaction type and receipt status.
* **Business Logic Execution:** If validation passes, executes business logic (minting tokens)
* **Event Emission**: Emits `TokensMinted` event with the transaction details

#### Constructor and Initialization

```solidity
constructor() ERC20("Mintable (TEST)", "TEST") {
    // Get the precompile instance using the helper library
    VERIFIER = NativeQueryVerifierLib.getVerifier();
}
```

**Description:**

* Initializes the ERC20 token with name and symbol
* Sets the `VERIFIER` immutable variable to the precompile instance
* The precompile address is constant and always available

#### Replay Protection

```solidity
mapping(bytes32 => bool) public processedQueries;
```

**Description:**

* **processedQueries**: Maps transaction keys to boolean values to track processed transactions

#### Proof Verification

```solidity
function _verifyProof(
    uint64 chainKey,
    uint64 blockHeight,
    bytes calldata encodedTransaction,
    bytes32 merkleRoot,
    INativeQueryVerifier.MerkleProofEntry[] calldata siblings,
    bytes32 lowerEndpointDigest,
    bytes32[] calldata continuityRoots
) internal view returns (bool verified) {
    INativeQueryVerifier.MerkleProof memory merkleProof =
        INativeQueryVerifier.MerkleProof({root: merkleRoot, siblings: siblings});
    
    INativeQueryVerifier.ContinuityProof memory continuityProof =
        INativeQueryVerifier.ContinuityProof({
            lowerEndpointDigest: lowerEndpointDigest, 
            roots: continuityRoots
        });
    
    // Verify inclusion proof
    verified = VERIFIER.verifyAndEmit(chainKey, blockHeight, encodedTransaction, merkleProof, continuityProof);
    
    return verified;
}
```

**Description:**

* Constructs the `MerkleProof` and `ContinuityProof` structs from the provided components
* Calls the precompile's `verifyAndEmit()` function synchronously at address `0x0FD2`
* Returns `true` if both Merkle proof (transaction inclusion) and continuity proof (block attestation chain) are valid; reverts on failure (transaction reverts if verification fails)
* Emits `TransactionVerified` event on successful verification
* Verification happens in the same transaction - no async processing

#### Transaction Data Extraction

The contract includes helper functions for extracting and validating transaction data from `encodedTransaction` bytes:

```solidity
function _validateTransactionContents(bytes memory encodedTransaction) 
    internal pure returns (bool found, address burntFrom, uint256 burntValue)
{
    // Validate transaction type
    uint8 txType = EvmV1Decoder.getTransactionType(encodedTransaction);
    require(EvmV1Decoder.isValidTransactionType(txType), "Unsupported transaction type");
    
    // Decode and validate receipt status
    EvmV1Decoder.ReceiptFields memory receipt = EvmV1Decoder.decodeReceiptFields(encodedTransaction);
    require(receipt.receiptStatus == 1, "Transaction did not succeed");
    
    // Find transfer events and validate
    EvmV1Decoder.LogEntry[] memory transferLogs =
        EvmV1Decoder.getLogsByEventSignature(receipt, TRANSFER_EVENT_SIGNATURE);
    require(transferLogs.length > 0, "No transfer events found");
    
    // Get the original sender
    EvmV1Decoder.CommonTxFields memory txFields = EvmV1Decoder.decodeCommonTxFields(encodedTransaction);
    
    // Check if there's an actual burn transfer from the sender
    (found, burntFrom, burntValue) = _processTransferLogs(transferLogs, txFields.from);
    require(found, "No valid burn transfer found");
    
    return (found, burntFrom, burntValue);
}
```

**Description:**

* Uses `EvmV1Decoder` library to decode the transaction bytes
* Validates transaction type and receipt status
* Extracts event logs matching the `Transfer` event signature
* Validates that a burn transfer occurred (transfer to address < 128)

#### Complete Example

See [`USCMinter.sol`](https://github.com/gluwa/usc-testnet-bridge-examples/blob/main/contracts/sol/USCMinter.sol)  for the complete implementation with all helper functions and event processing logic. A corresponding helper script and instructions to use this code are available in the [hello-bridge example](https://github.com/gluwa/usc-testnet-bridge-examples/tree/main/hello-bridge).

## Next Steps

[DApp Design Patterns: Readability](/usc/dapp-builder-infrastructure/dapp-design-patterns-readability.md)

*Check out* [*this tutorial*](https://github.com/gluwa/usc-testnet-bridge-examples) *for an example of how to use the Creditcoin stack to set up a decentralized trustless bridge.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.creditcoin.org/usc/dapp-builder-infrastructure/universal-smart-contracts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
