Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.


License Post-Integration Documentation Status Twitter Follow PyPI version



Cometa.py is a lightweight, high-performance Python library binding for the libcardano-c library, designed to simplify blockchain development on Cardano.

Cometa.py packages libcardano-c using CFFI bindings, providing a fully documented, developer-friendly Pythonic API with type hints for excellent IDE support.

The 2.0 release candidate uses cardano-c v2.0.0-rc.6. The stable 1.2 series remains available for applications using cardano-c 1.2.

Example:

from cometa import TxBuilder, SlotConfig

builder = TxBuilder(protocol_params, SlotConfig.mainnet())

unsigned_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .send_lovelace(recipient_address, 12_000_000)
    .expires_in(3600)
    .build()
)

Dijkstra Era Support

Cometa supports Dijkstra transaction building with direct deposits into reward accounts, independently signed sub-transactions, key and script guards, account balance constraints, and Plutus V4. Use protocol version 12 parameters and the network's V4 cost model when evaluating V4 scripts.

The examples below use protocol_params and slot_config from the target network. Wallet UTxOs, addresses, and key handlers belong to the parties participating in the transaction. Build these transactions for a Dijkstra network.

Direct account transfers

Transfer 2 ADA from one registered reward account to another, with the wallet paying the fee:

from cometa import TxBuilder

transaction = (
    TxBuilder(protocol_params, slot_config)
    .set_utxos(wallet_utxos)
    .set_change_address(change_address)
    .withdraw_rewards(source_reward_address, 2_000_000)
    .add_direct_deposit(destination_reward_address, 2_000_000)
    .build()
)

Sign with the source account's staking key and the keys for the wallet inputs. add_direct_deposit() credits the destination account without creating a UTxO. To fund the deposit from wallet UTxOs instead, omit withdraw_rewards(). Repeated deposits to the same account accumulate.

Build, sign, and batch sub-transactions

A sub-transaction expresses a party's intent. Its inputs and outputs need not balance on their own, and it pays no fee or collateral. The enclosing transaction balances the whole batch. Here, party_utxo contains 10 ADA and the party requests 12 ADA back; the batcher supplies the remaining 2 ADA and pays the fee.

from cometa import SubTransactionBuilder, TxBuilder

sub_transaction = (
    SubTransactionBuilder(protocol_params, slot_config)
    .add_input(party_utxo)
    .send_lovelace(party_address, 12_000_000)
    .require_top_level_guard(batcher_credential)
    .build()
)

# party_keys is a SoftwareEd25519SecureKeyHandler for the input's payment key.
sub_transaction.apply_vkey_witnesses(
    party_keys.sign_sub_transaction(sub_transaction)
)

transaction = (
    TxBuilder(protocol_params, slot_config)
    .set_utxos(batcher_utxos)
    .set_change_address(batcher_address)
    .add_guard(batcher_credential)
    .add_sub_transaction(sub_transaction, [party_utxo])
    .build()
)
transaction.apply_vkey_witnesses(batcher_keys.sign_transaction(transaction))

batcher_credential is the key credential of batcher_keys. Requiring it prevents the intent from being included without that party's authorization. The batch preserves the sub-transaction's body and signatures. Resolve all spent inputs when adding each sub-transaction, plus reference inputs carrying scripts. BIP32 key handlers also provide sign_sub_transaction(sub_transaction, paths).

Sub-transactions share the input, output, minting, staking, governance, direct deposit, and deferred-redeemer methods of TxBuilder. For script execution, provide collateral on the enclosing builder. Sub-transaction scripts use Plutus V4 or native scripts; their execution budgets are fixed before the party signs.

Account balance constraints

Require a registered account's balance to lie in a range when the transaction executes, and separately constrain its balance at the start of the block:

from cometa import AccountBalanceInterval, TxBuilder

transaction = (
    TxBuilder(protocol_params, slot_config)
    .set_utxos(wallet_utxos)
    .set_change_address(change_address)
    .send_lovelace(recipient_address, 2_000_000)
    .add_account_balance_interval(
        reward_address, AccountBalanceInterval.new(5_000_000, 10_000_000)
    )
    .add_starting_account_balance_interval(
        reward_address, AccountBalanceInterval.new_exact(5_000_000)
    )
    .build()
)

Range lower bounds are inclusive and upper bounds are exclusive. Either bound can be None. Sub-transactions support execution-time balance constraints; starting-balance constraints belong to the enclosing transaction.

Script guards

A Plutus V4 guard authorizes the transaction through its own redeemer:

from cometa import Credential, TxBuilder

transaction = (
    TxBuilder(protocol_params, slot_config)
    .set_utxos(wallet_utxos)
    .set_change_address(change_address)
    .set_collateral_utxos(collateral_utxos)
    .set_collateral_change_address(change_address)
    .add_script(guard_script)
    .add_guard(Credential.from_script_hash(guard_script.hash), redeemer=0)
    .build()
)

guard_script is a PlutusV4Script; replace 0 with its expected redeemer. SubTransactionBuilder.add_guard() applies the same requirement within an intent. require_top_level_guard(credential, datum=terms) can attach terms for an enclosing guard to check. Native scripts can require a guard with ScriptRequireGuard.new(credential), including inside all/any/n-of-k scripts.

Build a Plutus V4 transaction

Use the network's protocol parameters and slot configuration, the UTxO locked by your validator, and wallet UTxOs for fees and collateral. validator_cbor_hex is the compiled, CBOR-wrapped Plutus V4 validator.

from cometa import PlutusV4Script, Script, TxBuilder

script = Script.from_plutus_v4(PlutusV4Script.from_hex(validator_cbor_hex))

builder = (
    TxBuilder(protocol_params, slot_config)
    .set_utxos(wallet_utxos)
    .set_change_address(change_address)
    .set_collateral_utxos(collateral_utxos)
    .set_collateral_change_address(change_address)
    .add_script(script)
)

transaction = (
    builder
    .add_input(script_utxo, redeemer=0)
    .send_lovelace(recipient_address, 2_000_000)
    .expires_in(3600)
    .build()
)

The builder evaluates the validator locally and includes its execution budget in the fee. Replace 0 with the redeemer expected by your validator, then sign and submit the transaction as usual.

Evaluate a transaction locally

For an existing transaction, use NativeTxEvaluator with the same network parameters and the UTxOs referenced by the transaction:

from cometa import NativeTxEvaluator

evaluator = NativeTxEvaluator.from_parameters(protocol_params, slot_config)
redeemers = evaluator.evaluate(transaction, resolved_inputs)

for redeemer in redeemers:
    print(redeemer.tag, redeemer.index, redeemer.ex_units)

Script parameters can also be applied locally before creating the V4 script:

from cometa import apply_params_to_script, PlutusV4Script

parameterized_hex = apply_params_to_script([42], parameterized_validator_cbor_hex)
validator = PlutusV4Script.from_hex(parameterized_hex)

Deferred redeemers

Deferred redeemers are available for both Conway and Dijkstra transactions. Pass a callback to add_input, mint_token, withdraw_rewards, vote or add_certificate when the redeemer depends on the balanced transaction:

from cometa import PlutusData

# Locate this input after the builder has selected and ordered all inputs.
def spend_redeemer(draft_tx, resolved_inputs):
    for index, tx_input in enumerate(draft_tx.body.inputs):
        if tx_input == script_utxo.input:
            return PlutusData.from_int(index)
    raise ValueError("Script input is missing")

builder.add_input(script_utxo, redeemer=spend_redeemer)
tx = builder.build()

Callbacks receive a Transaction and a list of Utxo objects. Treat the draft as read-only and keep the callback deterministic: balancing may call it several times. Callback exceptions are reported by build() with the original exception as their cause.

Conway Era Support

Cometa.py supports all features up to the Conway era, which is the current era of the Cardano blockchain. Conway era brought decentralized governance to Cardano, including:

These are some of the examples illustrated in the examples directory. However, you should be able to build any valid transaction for the current era. See the Documentation for more information.


Installation

Install the stable package:

pip install biglup-cometa

Normal installs select the stable release, currently 1.2.1.post6. Pip does not select the 2.0 release candidate unless you opt in.

To install the release candidate with the new Dijkstra APIs:

pip install "biglup-cometa==2.0.0rc3"

The 2.0 binary wheels require glibc 2.33 or newer on Linux x86-64/ARM64, or macOS 26 or newer on macOS. Source installations require a compatible cardano-c 2.x library.

Once installed, you can import it into your application:

import cometa

version = cometa.get_lib_version()
print(f"Library version: {version}")

Getting Started

The primary component for creating transactions is the TxBuilder. It provides a fluent (chainable) API that simplifies the complex process of assembling inputs, outputs, and calculating fees.

The TxBuilder requires protocol parameters and a SlotConfig for slot/time calculations:

from cometa import TxBuilder, SlotConfig, ProtocolParameters

# SlotConfig provides network timing configuration
# Use the appropriate factory method for your network:
slot_config = SlotConfig.mainnet()   # For mainnet
slot_config = SlotConfig.preprod()   # For preprod testnet
slot_config = SlotConfig.preview()   # For preview testnet

# Create the builder
builder = TxBuilder(protocol_params, slot_config)

Note: The TxBuilder uses NativeTxEvaluator by default for local Plutus script evaluation. You can override this with a custom evaluator using builder.set_evaluator().

First, establish a connection to the Cardano network using a Provider:

from cometa import BlockfrostProvider, NetworkMagic

provider = BlockfrostProvider(
    network=NetworkMagic.PREPROD,
    project_id="YOUR_BLOCKFROST_PROJECT_ID"
)

Tip: You can create your own providers by implementing the Provider protocol.

Create your addresses and fetch UTxOs:

from cometa import Address

sender_address = Address.from_bech32("addr_test1...")
recipient_address = Address.from_bech32("addr_test1...")

# Fetch UTxOs from the provider
utxos = provider.get_unspent_outputs(sender_address)
protocol_params = provider.get_parameters()

Build your transaction using the fluent API:

from cometa import TxBuilder, SlotConfig

builder = TxBuilder(protocol_params, SlotConfig.preprod())

unsigned_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .send_lovelace(recipient_address, 2_000_000)  # Send 2 ADA
    .expires_in(7200)  # Valid for 2 hours
    .build()
)

Sign and submit the transaction:

tx_hash = provider.submit_transaction(signed_tx)
print(f"Transaction submitted! TxHash: {tx_hash}")

Transaction Builder Examples

The TxBuilder supports a wide range of transaction types. Here are some common patterns.

All examples below assume you have already created the builder:

from cometa import TxBuilder, SlotConfig

builder = TxBuilder(protocol_params, SlotConfig.preprod())

Sending Multiple Outputs

tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .send_lovelace("addr_test1qz...", 5_000_000)   # Send 5 ADA
    .send_lovelace("addr_test1qp...", 10_000_000)  # Send 10 ADA
    .send_lovelace("addr_test1qr...", 2_000_000)   # Send 2 ADA
    .expires_in(7200)  # Expires in 2 hours
    .build()
)

Minting Tokens with Native Scripts

from cometa import ScriptAll, ScriptPubkey, Value

# Create a native script policy
pub_key_hash = payment_key.to_hash()
native_script = ScriptAll.new([
    ScriptPubkey.new(pub_key_hash)
])
policy_id = native_script.hash

# Mint tokens
tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .mint_token(amount=100, policy_id=policy_id, asset_name=b"MyToken")
    .add_script(native_script)
    .send_value(
        address=str(sender_address),
        value=Value.from_dict([2_000_000, {policy_id: {b"MyToken": 100}}])
    )
    .expires_in(3600)
    .build()
)

Burning Tokens

# Burn tokens (negative amount)
tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .mint_token(amount=-50, policy_id=policy_id, asset_name=b"MyToken")
    .add_script(native_script)
    .expires_in(3600)
    .build()
)

Attaching Metadata (CIP-25 NFTs)

# CIP-25 NFT metadata
nft_metadata = {
    policy_id.hex(): {
        "MyNFT": {
            "name": "My Awesome NFT",
            "image": "ipfs://QmXyz...",
            "description": "A unique digital artwork"
        }
    }
}

tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .mint_token(amount=1, policy_id=policy_id, asset_name=b"MyNFT")
    .add_script(native_script)
    .set_metadata(metadata=nft_metadata, tag=721)  # CIP-25 uses tag 721
    .send_value(
        address=recipient_address,
        value=Value.from_dict([2_000_000, {policy_id: {b"MyNFT": 1}}])
    )
    .expires_in(3600)
    .build()
)

Staking Operations

from cometa import DRep

# Delegate stake to a pool
tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .delegate_stake(
        reward_address=reward_address,
        pool_id="pool1..."
    )
    .build()
)

# Delegate voting power to a DRep (Conway era)
tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .delegate_voting_power(
        reward_address=reward_address,
        drep=DRep.from_key_hash("drep_key_hash_hex...")
    )
    .build()
)

Treasury Donation

# Donate to the Cardano treasury
tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .donate(1_000_000_000)  # Donate 1000 ADA
    .build()
)

Plutus Smart Contracts

Cometa.py supports Plutus V1, V2, and V3 scripts for smart contract interactions. Plutus scripts can be used for spending validation, minting policies, and staking operations.

Loading Plutus Scripts

from cometa import PlutusV3Script, PlutusV2Script, PlutusV1Script, Script

# Load a Plutus V3 script from CBOR hex
plutus_v3 = PlutusV3Script.from_hex("590dff010000323232...")
script = Script.from_plutus_v3(plutus_v3)

# Load Plutus V2 or V1 similarly
plutus_v2 = PlutusV2Script.from_hex("...")
script_v2 = Script.from_plutus_v2(plutus_v2)

# Get the script hash (used as policy ID for minting)
script_hash = script.hash
print(f"Script hash: {script_hash.hex()}")

Creating Script Addresses

from cometa import EnterpriseAddress, Credential, NetworkId

# Create a credential from the script hash
script_credential = Credential.from_script_hash(script_hash)

# Create an enterprise address (no staking) for the script
script_address = EnterpriseAddress.from_credentials(
    NetworkId.TESTNET,
    script_credential
).to_address()

print(f"Script address: {script_address}")

Spending from a Plutus Script

from cometa import ConstrPlutusData

# Get UTXOs locked at the script address
script_utxos = provider.get_unspent_outputs(str(script_address))

# Create a redeemer (argument to the script)
# ConstrPlutusData(0) is a simple constructor - your script defines the format
redeemer = ConstrPlutusData(0)

# Build transaction to spend from the script
spend_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .add_input(utxo=script_utxos[0], redeemer=redeemer)  # Script input with redeemer
    .send_lovelace(address=recipient_address, amount=5_000_000)
    .add_script(script)  # Include the script for validation
    .expires_in(3600)
    .build()
)

Working with Plutus Data

from cometa import ConstrPlutusData, PlutusList, PlutusMap
# Constructor with fields (most common pattern)
# Represents: data MyDatum = MyDatum { owner: PubKeyHash, amount: Integer }
datum = ConstrPlutusData(
    0,  # Constructor index
    [
        b"pubkey_hash_here", # owner
        1000000              # amount
    ]
)

# List of integers
int_list = PlutusList.from_list([
    1,
    2,
    3
])

# Map (key-value pairs)
plutus_map = PlutusMap()
plutus_map[b"key1"] = 100
plutus_map[b"key2"] = 200

Working with Scripts

Cometa.py provides some utilities to parameterize scripts and local transaction evaluation using cardano-c's native Plutus virtual machine.

Applying Parameters to Scripts

Many contracts are parameterized, they require configuration data to be applied before deployment. Use apply_params_to_script to apply parameters to compiled scripts:

from cometa import apply_params_to_script, PlutusV2Script, Script, PlutusList, PlutusData, ConstrPlutusData

# Load your compiled script
compiled_code = "590221010000323232..."

# Build parameters as Plutus Data
# Example: Gift Card contract requires token_name and utxo_ref
token_name = "MyToken"
output_ref = ConstrPlutusData(0, [
    ConstrPlutusData(0, [PlutusData.from_hex(utxo.input.transaction_id.hex())]),
    PlutusData.from_int(utxo.input.index)
])

params = PlutusList.from_list([
    PlutusData.from_string(token_name),
    PlutusData.from_constr(output_ref)
])

# Apply parameters to get the final script
parameterized_code = apply_params_to_script(params, compiled_code)

# Create the script object
plutus_script = PlutusV2Script.from_hex(parameterized_code)
script = Script.from_plutus_v2(plutus_script)

# Get the policy ID (script hash)
policy_id = script.hash
print(f"Policy ID: {policy_id.hex()}")

Example: Minting with Parameterized Script

from cometa import (
    BlockfrostProvider, NetworkMagic, TxBuilder, SlotConfig,
    PlutusV2Script, Script, Value,
    PlutusList, PlutusData, ConstrPlutusData, apply_params_to_script
)

# Setup provider
provider = BlockfrostProvider(
    network=NetworkMagic.PREPROD,
    project_id="YOUR_PROJECT_ID"
)

# Get protocol parameters and UTXOs
protocol_params = provider.get_parameters()
utxos = provider.get_unspent_outputs(sender_address)

# Select a UTXO to use as parameter (ensures script uniqueness)
param_utxo = utxos[0]

# Build script parameters
token_name = "MyNFT"
output_ref = ConstrPlutusData(0, [
    ConstrPlutusData(0, [PlutusData.from_hex(param_utxo.input.transaction_id.hex())]),
    PlutusData.from_int(param_utxo.input.index)
])

params = PlutusList.from_list([
    PlutusData.from_string(token_name),
    PlutusData.from_constr(output_ref)
])

# Apply parameters and create script
compiled_code = "590221010000323232..."
parameterized = apply_params_to_script(params, compiled_code)
script = Script.from_plutus_v2(PlutusV2Script.from_hex(parameterized))

# Build mint transaction
# Note: TxBuilder uses NativeTxEvaluator by default for local Plutus evaluation
policy_id = script.hash
asset_name = token_name.encode("utf-8")
mint_redeemer = ConstrPlutusData(0)  # Mint action

builder = TxBuilder(protocol_params, SlotConfig.preprod())

tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .add_input(param_utxo)  # Must spend the referenced UTXO
    .mint_token(policy_id=policy_id, asset_name=asset_name, amount=1, redeemer=mint_redeemer)
    .add_script(script)
    .send_value(
        address=str(recipient_address),
        value=Value.from_dict([2_000_000, {policy_id: {asset_name: 1}}])
    )
    .expires_in(3600)
    .build()
)

# Sign and submit
signed_tx = sign_transaction(tx, private_key)
tx_hash = provider.submit_transaction(signed_tx.serialize_to_cbor())
print(f"Transaction submitted: {tx_hash}")

Conway Governance

Cardano's Conway era introduced decentralized governance. Cometa.py supports all governance features including DRep registration, voting, and proposal submission.

Registering as a DRep

Delegated Representatives (DReps) vote on governance proposals on behalf of delegators:

from cometa import DRep, DRepType, Credential, Anchor, Blake2bHash, Ed25519PublicKey

# Create DRep credential from your DRep key
drep_pub_key = Ed25519PublicKey.from_hex("your_drep_public_key_hex")
drep_credential = Credential.from_key_hash(drep_pub_key.to_hash())

# Create the DRep object
drep = DRep.new(drep_type=DRepType.KEY_HASH, credential=drep_credential)
print(f"DRep ID: {drep.to_cip129_string()}")

# Create an anchor (metadata URL + hash)
anchor = Anchor.new(
    url="https://example.com/drep-metadata.jsonld",
    hash_value=Blake2bHash.from_hex("metadata_hash_hex...")
)

# Register as a DRep
register_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .register_drep(drep=drep, anchor=anchor)
    .build()
)

Delegating Voting Power

ADA holders can delegate their voting power to a DRep:

from cometa import DRep

# Delegate to a specific DRep
drep = DRep.from_string("drep1...")  # DRep ID in CIP-129 format

# First register your stake key (if not already registered)
register_stake_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .register_reward_address(reward_address=reward_address)
    .build()
)

# Then delegate voting power
delegate_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .delegate_voting_power(
        drep=drep,
        reward_address=reward_address
    )
    .build()
)

# You can also delegate to special DReps
from cometa import DRep

# Delegate to "Abstain" (participate in quorum but don't vote)
abstain_drep = DRep.new_abstain()

# Delegate to "No Confidence" (vote no on everything)
no_confidence_drep = DRep.new_no_confidence()

Voting on Proposals

DReps can vote on governance proposals:

from cometa import (
    Voter, VoterType, Vote, VotingProcedure,
    GovernanceActionId, Anchor, Blake2bHash
)

# Create the voter (DRep credential)
voter = Voter.new(VoterType.DREP_KEY_HASH, drep_credential)

# Reference the governance action to vote on
action_id = GovernanceActionId.from_bech32(
    "gov_action1u8gafgcskj6sqvgwqse7adc0h9438m535lg97czcvxntscvw7f5sqgf2n7j"
)

# Create voting procedure with rationale anchor
rationale_anchor = Anchor.new(
    url="https://example.com/vote-rationale.jsonld",
    hash_value=Blake2bHash.from_hex("rationale_hash...")
)
voting_procedure = VotingProcedure.new(Vote.YES, rationale_anchor)

# Cast the vote
vote_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .vote(
        voter=voter,
        action_id=action_id,
        voting_procedure=voting_procedure
    )
    .build()
)

Proposing Governance Actions

Submit proposals for on-chain governance:

from cometa import Anchor, Blake2bHash

# All proposals require an anchor with metadata
proposal_anchor = Anchor.new(
    url="https://example.com/proposal-metadata.jsonld",
    hash_value=Blake2bHash.from_hex("metadata_hash...")
)

# Info action (non-binding poll)
info_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .propose_info(
        reward_address=reward_address,  # Deposit refund address
        anchor=proposal_anchor
    )
    .build()
)

Deregistering a DRep

# Deregister and reclaim your deposit
deregister_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .deregister_drep(drep=drep)
    .build()
)

Withdrawing Staking Rewards

# Get current rewards balance
rewards_balance = provider.get_rewards_balance(reward_address)

# Withdraw all rewards
withdraw_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .withdraw_rewards(
        amount=rewards_balance,
        reward_address=reward_address
    )
    .build()
)

# Optionally deregister stake key to reclaim deposit
deregister_stake_tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .withdraw_rewards(amount=rewards_balance, reward_address=reward_address)
    .deregister_reward_address(reward_address=reward_address)
    .build()
)

You can see the full capabilities of the transaction builder in the TxBuilder API documentation.


Working with CBOR

Cardano uses CBOR (Concise Binary Object Representation) for serialization. Cometa.py provides CborReader and CborWriter for encoding and decoding CBOR data.

Writing CBOR Data

from cometa import CborWriter

# Create a writer
writer = CborWriter()

# Write primitive values
writer.write_int(42)
writer.write_str("Hello, Cardano!")
writer.write_bytes(b"\x01\x02\x03")
writer.write_bool(True)
writer.write_null()

# Get the encoded bytes
cbor_bytes = writer.encode()
cbor_hex = writer.to_hex()

Reading CBOR Data

from cometa import CborReader, CborReaderState

# Create a reader from hex or bytes
reader = CborReader.from_hex("83010203")  # Array [1, 2, 3]

# Check what type of data is next
state = reader.peek_state()
if state == CborReaderState.START_ARRAY:
    length = reader.read_array_len()
    for _ in range(length):
        value = reader.read_uint()
        print(value)
    reader.read_array_end()

Cryptography

Cometa.py provides comprehensive cryptographic primitives for Cardano development, including Ed25519 key pairs, BIP32 hierarchical deterministic keys, and BIP39 mnemonic support.

Working with Mnemonics (BIP39)

BIP39 mnemonics are human-readable word sequences that encode cryptographic entropy:

from cometa import mnemonic_to_entropy, entropy_to_mnemonic

# Convert a mnemonic phrase to entropy
mnemonic_words = [
    "abandon", "abandon", "abandon", "abandon",
    "abandon", "abandon", "abandon", "abandon",
    "abandon", "abandon", "abandon", "about"
]
entropy = mnemonic_to_entropy(mnemonic_words)
print(f"Entropy: {entropy.hex()}")

Deriving Keys from Mnemonics (CIP-1852)

Cardano uses CIP-1852 for HD wallet key derivation:

from cometa import (
    mnemonic_to_entropy,
    Bip32PrivateKey,
    harden,
    BaseAddress,
    NetworkId,
    Credential
)

# Convert mnemonic to entropy
mnemonic = "your 24 word mnemonic phrase here...".split()
entropy = mnemonic_to_entropy(mnemonic)

# Create root key from entropy
root_key = Bip32PrivateKey.from_bip39_entropy(b"optional-passphrase", entropy)

# Derive account key using CIP-1852 path: m/1852'/1815'/0'
# 1852' = Cardano purpose, 1815' = ADA coin type, 0' = account 0
account_key = root_key.derive([
    harden(1852),  # Purpose
    harden(1815),  # Coin type (ADA)
    harden(0)      # Account index
])

# Get account public key (can be shared safely)
account_pub_key = account_key.get_public_key()

# Derive payment key: m/1852'/1815'/0'/0/0
payment_key = account_pub_key.derive([0, 0])  # External chain, address 0

# Derive staking key: m/1852'/1815'/0'/2/0
staking_key = account_pub_key.derive([2, 0])  # Staking chain, index 0

# Create credentials from key hashes
payment_credential = Credential.from_key_hash(
    payment_key.to_ed25519_key().to_hash()
)
staking_credential = Credential.from_key_hash(
    staking_key.to_ed25519_key().to_hash()
)

# Create a base address
address = BaseAddress.from_credentials(
    NetworkId.MAINNET,
    payment_credential,
    staking_credential
)
print(f"Address: {address.to_bech32()}")

Signing and Verifying Messages

Ed25519 signatures are used for transaction signing and message authentication:

from cometa import Ed25519PrivateKey, Ed25519PublicKey

# Create a private key (in practice, derive from HD wallet)
private_key = Ed25519PrivateKey.from_normal_bytes(bytes(32))

# Get the corresponding public key
public_key = private_key.get_public_key()
print(f"Public key hash: {public_key.to_hash().to_hex()}")

# Sign a message
message = b"Hello, Cardano!"
signature = private_key.sign(message)
print(f"Signature: {signature.to_hex()}")

# Verify the signature
is_valid = public_key.verify(signature, message)
print(f"Signature valid: {is_valid}")

# Verification fails with wrong message
is_valid = public_key.verify(signature, b"Wrong message")
print(f"Wrong message valid: {is_valid}")  # False

Extending the Transaction Builder

The TxBuilder API allows you to override its core logic for coin selection and transaction evaluation. If these custom implementations are not provided, the builder uses the following defaults:

  • Coin Selection: A "Largest First" strategy via LargeFirstCoinSelector
  • Transaction Evaluation: Local evaluation via NativeTxEvaluator (uses cardano-c's Plutus virtual machine)

Implementing a Custom CoinSelector

The coin selector is responsible for choosing which UTxOs to spend to cover the value required by the transaction's outputs. You can provide your own strategy by implementing the CoinSelector protocol:

from typing import List, Tuple
from cometa import Utxo, Value

class MyCoinSelector:
    """Custom coin selection strategy."""

    def get_name(self) -> str:
        return "MyCustomSelector"

    def select(
        self,
        pre_selected_utxo: List[Utxo],
        available_utxo: List[Utxo],
        target: Value,
    ) -> Tuple[List[Utxo], List[Utxo]]:
        # Your custom selection logic here
        # Return: (selected_utxos, remaining_utxos)
        ...

Attach your custom selector to the builder:

my_selector = MyCoinSelector()
builder.set_coin_selector(my_selector)

Transaction Evaluators

The transaction evaluator calculates execution units (ExUnits) for Plutus scripts.

Default: Local Evaluation with NativeTxEvaluator

By default, TxBuilder uses NativeTxEvaluator for local Plutus script evaluation. This is configured automatically based on the SlotConfig and protocol parameters you provide:

from cometa import TxBuilder, SlotConfig

# NativeTxEvaluator is used automatically
builder = TxBuilder(protocol_params, SlotConfig.preprod())

# Build transaction with Plutus scripts - evaluation happens locally
tx = (
    builder
    .set_change_address(sender_address)
    .set_utxos(utxos)
    .add_input(script_utxo, redeemer=redeemer)
    .add_script(script)
    .build()
)

Custom NativeTxEvaluator Configuration

If you need to customize the evaluator settings, you can create your own instance:

from cometa import TxBuilder, SlotConfig
from cometa import NativeTxEvaluator

# Create custom evaluator with specific settings
evaluator = NativeTxEvaluator.from_parameters(protocol_params, SlotConfig.preprod())

# Override the default evaluator
builder = TxBuilder(protocol_params, SlotConfig.preprod())
builder.set_evaluator(evaluator)

Custom Evaluator

You can also implement your own evaluator by following the TxEvaluator protocol:

from typing import List, Optional
from cometa import Transaction, Utxo, Redeemer

class MyTxEvaluator:
    """Custom transaction evaluator."""

    def get_name(self) -> str:
        return "MyCustomEvaluator"

    def evaluate(
        self,
        transaction: Transaction,
        additional_utxos: Optional[List[Utxo]] = None,
    ) -> List[Redeemer]:
        # Your custom evaluation logic here
        ...

Attach your custom evaluator to the builder:

my_evaluator = MyTxEvaluator()
builder.set_evaluator(my_evaluator)

Building and Testing

While the underlying libcardano-c library has its own comprehensive test suite, Cometa.py maintains a separate, dedicated suite of tests. These binding-level tests verify the correctness of the Python-to-C interface and ensure the high-level API functions as expected.

To build and run the tests, use the following commands:

pip install -e ".[dev]"
pytest

To run the linter:

pylint src/cometa

License

Cometa.py is licensed under the Apache 2.0 License. See the LICENSE file for more information.

Metadata

Release files for biglup-cometa 2.0.0rc3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for biglup-cometa 2.0.0rc3
File Size Uploaded Provenance Actions
biglup_cometa-2.0.0rc3.tar.gz 364.7 kB Without provenance Details for biglup_cometa-2.0.0rc3.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for biglup-cometa 2.0.0rc3
File Actions
biglup_cometa-2.0.0rc3-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for biglup_cometa-2.0.0rc3-py3-none-win_amd64.whl
biglup_cometa-2.0.0rc3-py3-none-manylinux_2_33_x86_64.whl Python 3 none Linux glibc 2.33+ x86-64 Details for biglup_cometa-2.0.0rc3-py3-none-manylinux_2_33_x86_64.whl
biglup_cometa-2.0.0rc3-py3-none-manylinux_2_33_aarch64.whl Python 3 none Linux glibc 2.33+ ARM64 Details for biglup_cometa-2.0.0rc3-py3-none-manylinux_2_33_aarch64.whl
biglup_cometa-2.0.0rc3-py3-none-macosx_26_0_x86_64.whl Python 3 none macOS 26.0+ x86-64 Details for biglup_cometa-2.0.0rc3-py3-none-macosx_26_0_x86_64.whl
biglup_cometa-2.0.0rc3-py3-none-macosx_26_0_arm64.whl Python 3 none macOS 26.0+ ARM64 Details for biglup_cometa-2.0.0rc3-py3-none-macosx_26_0_arm64.whl
biglup_cometa-2.0.0rc3-py3-none-linux_armv7l.whl Python 3 none linux armv7l Details for biglup_cometa-2.0.0rc3-py3-none-linux_armv7l.whl
biglup_cometa-2.0.0rc3-py3-none-linux_armv6l.whl Python 3 none linux armv6l Details for biglup_cometa-2.0.0rc3-py3-none-linux_armv6l.whl

Total release size: 13.8 MB

Release files / biglup_cometa-2.0.0rc3.tar.gz

Download URL biglup_cometa-2.0.0rc3.tar.gz
Size 364.7 kB
Tags Source
SHA-256 checksum
How to use checksums
e804b4e770b21a78952025223001859e86ca56e254d4b1c4d214b602e824ec7d
BLAKE2b-256 checksum
How to use checksums
59448262ac37cc6a60d67c37d8f260580c48458c3b7703b197a8f502a7a0103b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / biglup_cometa-2.0.0rc3-py3-none-win_amd64.whl

Download URL biglup_cometa-2.0.0rc3-py3-none-win_amd64.whl
Size 1.4 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
f3e384b86f5790b9b9946af26f03e43747b2589a195d0f547eeb0d87dcb54785
BLAKE2b-256 checksum
How to use checksums
d4f6870c43c9ef00b809bb89b6a325ffeb375d6c8d98e1e298ded2f5d89c37c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / biglup_cometa-2.0.0rc3-py3-none-manylinux_2_33_x86_64.whl

Download URL biglup_cometa-2.0.0rc3-py3-none-manylinux_2_33_x86_64.whl
Size 1.7 MB
Tags Linux glibc 2.33+ x86-64 Python 3
SHA-256 checksum
How to use checksums
012bf9742814b769fed2454be7456a66c0aa8a23672eec08cc1d9e2cb1001575
BLAKE2b-256 checksum
How to use checksums
60e15d293294e740407254e85cd3569e2ebf205c5dcef41b85e42f7a31cc7570
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / biglup_cometa-2.0.0rc3-py3-none-manylinux_2_33_aarch64.whl

Download URL biglup_cometa-2.0.0rc3-py3-none-manylinux_2_33_aarch64.whl
Size 1.6 MB
Tags Linux glibc 2.33+ ARM64 Python 3
SHA-256 checksum
How to use checksums
7f5c7059c7d6cdc585b5df74b0050b1b89061296b3b1f18291b2383c9ccae5d8
BLAKE2b-256 checksum
How to use checksums
a1957b4cf04383ef47d1986b2cf20fbe0c2741a08cb8480483ca02046a25c615
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / biglup_cometa-2.0.0rc3-py3-none-macosx_26_0_x86_64.whl

Download URL biglup_cometa-2.0.0rc3-py3-none-macosx_26_0_x86_64.whl
Size 1.7 MB
Tags Python 3 macOS 26.0+ x86-64
SHA-256 checksum
How to use checksums
fe37da2edb6e6cda66b11ca3e58a11e6a70119f7ed017b4d0e25554d20e117b0
BLAKE2b-256 checksum
How to use checksums
94fe443b4dcff2763b59742e46e8b9a7860037bfb4d2c7e94c3d521b501c2bea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / biglup_cometa-2.0.0rc3-py3-none-macosx_26_0_arm64.whl

Download URL biglup_cometa-2.0.0rc3-py3-none-macosx_26_0_arm64.whl
Size 1.6 MB
Tags Python 3 macOS 26.0+ ARM64
SHA-256 checksum
How to use checksums
84a8df2ce582328316e8717cf7318ee529109973d9396f662363d1f1960b7d89
BLAKE2b-256 checksum
How to use checksums
c2ff6dd839521ce1002439d126905da83f4d8f486a8eeda490ac8b028360791d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / biglup_cometa-2.0.0rc3-py3-none-linux_armv7l.whl

Download URL biglup_cometa-2.0.0rc3-py3-none-linux_armv7l.whl
Size 1.6 MB
Tags Python 3 linux armv7l
SHA-256 checksum
How to use checksums
1e23ca1fcc8e50c2c8da8a1e317dcf91123d64c537107be5c6c652f6d17f21d0
BLAKE2b-256 checksum
How to use checksums
1e3d874717dffc4b9e7a85462752fa88a4a020eed620b5d6ba18c5c3c44dd98a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / biglup_cometa-2.0.0rc3-py3-none-linux_armv6l.whl

Download URL biglup_cometa-2.0.0rc3-py3-none-linux_armv6l.whl
Size 3.9 MB
Tags Python 3 linux armv6l
SHA-256 checksum
How to use checksums
a00285baa56c78d7ddb4d1269c5e66cec3d5e681e9a7a8789fe88fc99d2403b7
BLAKE2b-256 checksum
How to use checksums
1327440cd0a2e20a15ed9aa90321ed632b2149ae75ac7582b50baa428d40c609
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Security for biglup-cometa 2.0.0rc3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page