Architecture

Introduction

The opnet client library is the official SDK for building Bitcoin-based applications on OP_NET. It provides full TypeScript support with type-safe contract interactions, enabling developers to integrate smart contract functionality directly into their applications.

The library follows a layered architecture where each layer encapsulates specific domain functionality. Foundational layers handle network communication and transaction processing, while higher layers build upon these to provide contract interaction and application-level features.

opnet client library architecture
opnet Client Library Architecture Application Code opnet Library Contract Layer Contract Class CallResult ABI System Provider Layer UTXOsManager JSONRpcProvider WebSocketRpcProvider Data Layer Blocks Transactions Epochs External OP_NET Node Bitcoin Network Contract Class (top) --> ABI System (top) --> CallResult (top) --> JSONRpcProvider (top) --> JSONRpcProvider (2 lines: side to top) --> OP_NET Node (from left side) --> OP_NET Node (from right side) --> Bitcoin Network (top) --> JSONRpcProvider (to bottom) --> JSONRpcProvider (to bottom, lower route) --> JSONRpcProvider (to bottom, upper route) -->

Contract Layer

The contract layer provides the classes required to represent and interact with deployed smart contracts on OP_NET. By leveraging Application Binary Interface (ABI) definitions, this layer enables type-safe contract interactions where method parameters and return values are validated at compile time. Contracts rely on RPC providers to communicate with OP_NET nodes.

Creating a Contract

The getContract() factory function is the recommended method for creating type-safe contract instances. This factory handles the instantiation process by binding ABI methods to the contract address and configuring the underlying RPC provider for network communication. The resulting contract instance exposes all defined methods as strongly-typed functions, allowing full IntelliSense support and compile-time parameter validation.

getContract() usage example
typescript
import { getContract, IOP20Contract, OP_20_ABI } from 'opnet';

const token = getContract<IOP20Contract>(
    contractAddress,
    OP_20_ABI,
    provider,
    network
);

// Type-safe method calls
const name = await token.name();
const balance = await token.balanceOf(address);

ABIs (Application Binary Interface)

ABIs define the contract interface: what methods and events exist. The library includes pre-built ABIs for standard contracts:

ABI Purpose
OP_20_ABI Fungible tokens (like ERC20)
OP_721_ABI NFTs (like ERC721)
MOTOSWAP_ROUTER_ABI DEX router
MotoswapPoolAbi Liquidity pools

Type Safety

The library provides full TypeScript support with generics for type-safe contract interactions.

Type-safe interface example
typescript
// Type-safe contract interface
interface IMyToken extends IOP20Contract {
    mint(to: Address, amount: bigint): Promise<CallResult<never>>;
}

// Generic contract instantiation
const token = getContract<IMyToken>(
    address,
    myTokenABI,
    provider,
    network
);

// Type-checked method calls
const result = await token.mint(recipient, 1000n);
//                    ^^^^^ TypeScript knows this returns CallResult<never>

Provider Layer

RPC providers handle communication with OP_NET nodes by abstracting the underlying network protocol and managing request serialization, response parsing, and connection handling. Providers can be configured to connect to different nodes or networks, enabling seamless transitions between development, testing, and production environments without modifying application code.

Since Bitcoin uses UTXOs instead of account balances, the provider layer includes a UTXOsManager that handles UTXO fetching and tracking.

Two provider types are available:

  • JSONRpcProvider: HTTP-based with a request/response pattern.
  • WebSocketRpcProvider: Supports real-time subscriptions and notifications.
JSONRpcProvider and UTXOsManager usage example.
typescript
import { JSONRpcProvider } from 'opnet';
import { networks } from '@btc-vision/bitcoin';

// JSON-RPC for standard operations
const provider = new JSONRpcProvider(
    'https://regtest.opnet.org',
    networks.regtest
);

// Get blockchain state
const blockNumber = await provider.getBlockNumber();
const balance = await provider.getBalance('bc1q...');

// Get UTXOs for an address
const utxos = await provider.utxoManager.getUTXOs({
    address: 'bc1q...',
    optimize: true,
});

Networks

Endpoints

The following table lists the supported Bitcoin networks and their corresponding RPC endpoints:

Network Purpose RPC URL
Mainnet Production https://mainnet.opnet.org
Regtest Local development and testing https://regtest.opnet.org
Testnet

No RPC endpoint is provided for Testnet. Use Regtest for development and testing purposes.

Specifying a Network

The library exposes the networks object which defines available Bitcoin networks. This object is used to specify the target network when calling methods that require network identification.

networks object usage
typescript
import { networks } from '@btc-vision/bitcoin';

// Network objects
networks.bitcoin   // Mainnet
networks.testnet   // Testnet
networks.regtest   // Regtest

Data Layer

The data layer provides classes for managing core blockchain data including blocks, transactions, and epochs. This layer does not access node data directly but instead provides type definitions that represent blockchain data across all interactions with the OP_NET network.

This separation ensures type safety throughout the application while delegating network communication to other layers. When data is fetched or operations are performed, responses are deserialized into the corresponding data layer types, providing strongly-typed objects for application consumption.

Blocks

Blocks in OP_NET correspond directly to Bitcoin blocks and contain all OP_NET transactions processed within that block. The data layer provides access to block information including block height, hash, timestamp, and the decoded OP_NET transactions contained within.

Accessing Block Data with JSONRpcProvider
typescript
import { JSONRpcProvider } from 'opnet';
import { networks } from '@btc-vision/bitcoin';

const network = networks.regtest;
const provider = new JSONRpcProvider('https://regtest.opnet.org', network);

const blockNumber = await provider.getBlockNumber();
console.log('Current block:', blockNumber);

Transactions

Three transaction types exist within OP_NET:

  • Deployment: Deploys new smart contracts to the network.
  • Interaction: Invokes methods on deployed smart contracts.
  • Generic:: Standard Bitcoin transfers without contract interaction.

Refer to the Transaction Types Explained section for detailed information.

Epochs

OP_NET uses epochs for consensus, where each epoch represents a mining cycle during which participants submit SHA-1 collision solutions. The data layer exposes epoch information including mining status, rewards, and finalization state.

Refer to the About Epochs section for detailed information.

JSONRpcProvider and UTXOsManager usage example.
typescript
import { JSONRpcProvider } from 'opnet';
import { networks } from '@btc-vision/bitcoin';

// JSON-RPC for standard operations
const provider = new JSONRpcProvider(
    'https://regtest.opnet.org',
    networks.regtest
);

const epoch = await provider.getLatestEpoch(true);
console.log('Epoch:', epoch.epochNumber);
console.log('Proposer:', epoch.proposer?.publicKey);

Library Modules

The library exposes its functionality through a set of exports. All public classes, interfaces, types, and utility functions are accessible from the main package entry point.

opnet client library exports
typescript
import {
    // Providers
    JSONRpcProvider,
    WebSocketRpcProvider,

    // Contracts
    getContract,
    CallResult,
    OPNetEvent,

    // ABIs
    OP_20_ABI,
    OP_721_ABI,
    MOTOSWAP_ROUTER_ABI,

    // Types
    IOP20Contract,
    IOP721Contract,

    // Data Classes
    Block,
    Epoch,
    Transaction,

    // Utils
    BitcoinUtils,
    RevertDecoder,
} from 'opnet';

Best Practices

  • Always simulate before sending: Check for reverts without spending BTC.
  • Use type-safe interfaces: Leverage TypeScript for contract interactions.
  • Handle BigInt correctly: All amounts are bigint type.
  • Track UTXOs: Use UTXOsManager to avoid double-spending.
  • Choose the right provider: JSON-RPC for most cases, WebSocket for real-time.