Contract Instantiation

Before interacting with a smart contract on the BCH network, CashScript-Py needs to instantiate a Contract object. Instantiation is done by providing the compiled cashc artifact and the contract constructor arguments. After this, the SDK can interact with the BCH contract.

Creating a Contract

The Contract class represents a CashScript contract as a Python object. Contract objects can be used to retrieve the contract address and balance, and to interact with the contract by generating an Unlocker via contract functions exposed under contract.unlock[...].

Constructor

from cashscript_py import Contract, LockingBytecodeType

contract = Contract(
    artifact,
    constructor_args,
    provider,
    address_type=LockingBytecodeType.P2SH32,
)

A contract is instantiated by providing:

  • an artifact dictionary produced by cashc (JSON)

  • a list of constructor arguments (in constructor declaration order)

  • a NetworkProvider instance (used for network operations)

  • an optional address_type (p2sh20 or p2sh32, default: p2sh32)

The NetworkProvider option is used to manage network operations (query UTXOs/balance and broadcast transactions). The recommended provider is ElectrumNetworkProvider (see Network Provider).

The address_type option chooses between p2sh20 and p2sh32. By default, p2sh32 is used because it has increased cryptographic security, but it is not yet supported by all wallets.

Caution: P2SH32 was introduced because P2SH20 is cryptographically insecure for a large subset of smart contracts. For contracts holding large sums of BCH, this provides an incentive to find a hash collision and steal funds.

Example

import json

from typing import Any

from cashscript_py import Contract, ElectrumNetworkProvider, LockingBytecodeType

with open("./p2pkh.json", "r", encoding="utf-8") as f:
    p2pkh_artifact: dict[str, Any] = json.load(f)

contract_arguments = [alice_pkh]

provider = ElectrumNetworkProvider("chipnet")
contract = Contract(p2pkh_artifact, contract_arguments, provider, address_type=LockingBytecodeType.P2SH20)

Contract Properties

address

contract.address: str

A contract’s regular address (without token support) can be retrieved through the address field.

Note: wallets will not allow you to send CashTokens to this address. For that you must use token_address below. Wallets which have not upgraded might not recognize this new address type.

Example

print(contract.address)

token_address

contract.token_address: str

A contract’s token-supporting address can be retrieved through the token_address field.

Example

print(contract.token_address)

bytecode

contract.bytecode: str

Returns the contract’s redeem script encoded as a hex string.

Example

print(contract.bytecode)

bytesize

contract.bytesize: int

The size of the contract bytecode in bytes. This is useful to ensure the contract is not too big, since Bitcoin Cash smart contracts can be 1,650 bytes at most.

Tip: contract.bytesize includes constructor arguments. The cashc compiler size outputs are based on bytecode without constructor arguments, so they are always an underestimate.

Example

# Make sure the contract bytesize is within standardness limits
assert contract.bytesize <= 1650

opcount

contract.opcount: int

The number of non-push opcodes in the contract’s redeem script.

Example

print(contract.opcount)

Contract Methods

get_balance()

await contract.get_balance() -> int

Returns the total balance of the contract in satoshis. Both confirmed and unconfirmed balance are included.

Example

contract_balance = await contract.get_balance()

get_utxos()

await contract.get_utxos() -> list[Utxo]

Returns all UTXOs that can be spent by the contract. Both confirmed and unconfirmed UTXOs are included.

Example

utxos = await contract.get_utxos()

Contract unlockers

Once a contract has been instantiated, you can invoke an ABI function to create an Unlocker by calling the function name under contract.unlock[...]. The provided parameters must match the CashScript function signature.

These unlockers are used when adding inputs in the Transaction Builder.

contract_utxos = await contract.get_utxos()
transaction_builder.add_input(contract_utxos[0], contract.unlock["spend"]())