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
NetworkProviderinstance (used for network operations)an optional
address_type(p2sh20orp2sh32, 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"]())