Instantiating a Contract

Using getContract()

The getContract() factory function is the recommended approach for creating type-safe contract instances. This function binds ABI methods to the contract address and configures the underlying RPC provider for network communication.

typescript
getContract() Function Signature
function getContract<T extends BaseContractProperties>(
    address: string | Address,
    abi: BitcoinInterface | BitcoinInterfaceAbi,
    provider: AbstractRpcProvider,
    network: Network,
    sender?: Address
): BaseContract<T> & Omit<T, keyof BaseContract<T>>

The table below describes the function parameters.

Parameter Type Required Description
address string | Address Yes Contract address in P2OP or hex format
abi BitcoinInterface | BitcoinInterfaceAbi Yes Contract ABI definition
provider AbstractRpcProvider Yes RPC provider instance
network Network Yes Bitcoin network configuration
sender Address No Default sender address for contract calls

Type-Safe Contract Interactions

Using generics with getContract() provides full TypeScript support, including IntelliSense and compile-time validation.

typescript
Type-Safe Method Calls
// Create type-safe OP-20 contract
const token = getContract<IOP20Contract>(
    address,
    OP_20_ABI,
    provider,
    network
);

// TypeScript knows all available methods and return types
const name = await token.name();              // CallResult with name property
const balance = await token.balanceOf(addr);  // CallResult with balance property
const decimals = await token.decimals();      // CallResult with decimals property

Setting Sender Address

The sender address identifies who is calling the contract during simulations. The contract uses this address to determine the caller's identity for authorization checks, verify token balances and allowances, evaluate access control rules, and resolve message sender within the contract logic.

Providing an accurate sender address is essential. Without it, simulations that depend on caller-specific state (such as balance lookups or ownership checks) will return incorrect results or revert unexpectedly.

Setting Sender at Construction

The most common approach is to provide the sender address when instantiating the contract through the getContract() function. This sets the default sender for all subsequent calls on that contract instance.

typescript
Setting Sender at Construction
import {
    Address,
    AddressTypes,
    Mnemonic,
    MLDSASecurityLevel,
} from '@btc-vision/transaction';

const mnemonic = new Mnemonic(
    'your seed phrase here ...',
    '',
    network,
    MLDSASecurityLevel.LEVEL2
);
const wallet = mnemonic.deriveOPWallet(AddressTypes.P2TR, 0);

// Set sender at construction
const token = getContract<IOP20Contract>(
    tokenAddress,
    OP_20_ABI,
    provider,
    network,
    wallet.address  // Sender address
);

Setting Sender After Construction

To change the sender after instantiation, call setSender() on the contract instance. This updates the caller identity for all subsequent simulations without requiring a new contract instance.

typescript
Setting Sender After Construction
// Create without sender
const token = getContract<IOP20Contract>(
    tokenAddress,
    OP_20_ABI,
    provider,
    network
);

// Set sender later
token.setSender(wallet.address);

Address Formats

OP_NET contracts support multiple address representations. The contract instance exposes properties to access the address in both P2OP format (the OP_NET-native address encoding) and standard hexadecimal format.

typescript
Address Formats
// Get P2OP format address
const p2opAddress = token.p2op;
console.log('P2OP:', p2opAddress);

// Get full Address object
const contractAddress = await token.contractAddress;
console.log('Hex:', contractAddress.toHex());
Format Example Use Case
P2OP bcrt1p... Display and configuration
Hex 0x1234... Internal operations
Address object Address Type-safe operations

Examples

OP-20 Token Contract

typescript
OP-20 Token Example
import {
    getContract,
    IOP20Contract,
    JSONRpcProvider,
    OP_20_ABI,
} from 'opnet';
import {
    Address,
    AddressTypes,
    Mnemonic,
    MLDSASecurityLevel,
} from '@btc-vision/transaction';
import { networks } from '@btc-vision/bitcoin';

async function main() {
    const network = networks.regtest;
    const provider = new JSONRpcProvider('https://regtest.opnet.org', network);
    
    const mnemonic = new Mnemonic(
        'your seed phrase here ...',
        '',
        network,
        MLDSASecurityLevel.LEVEL2
    );
    const wallet = mnemonic.deriveOPWallet(AddressTypes.P2TR, 0);

    const tokenAddress = Address.fromString('0x...');

    const token = getContract<IOP20Contract>(
        tokenAddress,
        OP_20_ABI,
        provider,
        network,
        wallet.address
    );

    // Read token info
    const [name, symbol, decimals] = await Promise.all([
        token.name(),
        token.symbol(),
        token.decimals(),
    ]);

    console.log(`Token: ${name.properties.name} (${symbol.properties.symbol})`);
    console.log(`Decimals: ${decimals.properties.decimals}`);

    // Check balance
    const balance = await token.balanceOf(wallet.address);
    console.log(`Balance: ${balance.properties.balance}`);

    await provider.close();
}

OP-721 NFT Contract

typescript
OP-721 NFT Example
import {
    getContract,
    IExtendedOP721Contract,
    OP_721_ABI,
} from 'opnet';

const nft = getContract<IExtendedOP721Contract>(
    nftAddress,
    OP_721_ABI,
    provider,
    network,
    wallet.address
);

// Read NFT info
const name = await nft.name();
const symbol = await nft.symbol();

// Check ownership
const owner = await nft.ownerOf(tokenId);
console.log('Owner:', owner.properties.owner);

DEX Router Contract

typescript
DEX Router Example
import {
    getContract,
    IMotoswapRouterContract,
    MOTOSWAP_ROUTER_ABI,
} from 'opnet';

const router = getContract<IMotoswapRouterContract>(
    routerAddress,
    MOTOSWAP_ROUTER_ABI,
    provider,
    network,
    wallet.address
);

// Get quote
const quote = await router.getAmountOut(
    amountIn,
    reserveIn,
    reserveOut
);
console.log('Expected output:', quote.properties.amountOut);