Transactions¶
A Kaspa transaction has the same shape as on any UTXO chain: a list
of inputs (each spending a previous output), a list of outputs, and
a few metadata fields. The SDK exposes the underlying types —
Transaction,
TransactionInput,
TransactionOutput,
TransactionOutpoint,
UtxoEntryReference
— and helpers that build, sign, mass, and serialise them.
Most callers don't need this section
The Transaction Generator (and
the managed Wallet (see Wallet) on top of it)
handles UTXO selection, mass, signing, and submission for you.
Reach for the primitives below only when you need custom lockup
scripts, exact input ordering, payload data, or offline signing.
Anatomy¶
Transaction
version, lock_time, subnetwork_id, gas, payload, mass
inputs: [TransactionInput, ...]
outputs: [TransactionOutput, ...]
TransactionInput
previous_outpoint: TransactionOutpoint(transaction_id, index)
signature_script (filled at sign time)
sequence
sig_op_count
utxo: UtxoEntryReference
TransactionOutput
value (sompi)
script_public_key (lockup script)
What sets Kaspa apart from a Bitcoin-shaped chain:
- Inputs carry their own UTXO context via
UtxoEntryReference, so the signer doesn't have to re-fetch the spent output for its amount and lockup. See Inputs. - Mass replaces "byte size × rate" as the fee model. Compute mass on the transaction (including a storage component derived from input and output values), then multiply by the prevailing fee rate. See Mass & fees.
- The atomic unit is the sompi:
1 KAS = 100_000_000 sompi. Every amount in the transaction surface is a sompi int. Seekaspa_to_sompiandsompi_to_kaspa.
End-to-end (manual path)¶
This walks the manual flow using
sign_transaction,
pay_to_address_script,
and
update_transaction_mass:
from kaspa import (
Transaction, TransactionInput, TransactionOutput, TransactionOutpoint,
UtxoEntryReference, sign_transaction, pay_to_address_script,
update_transaction_mass,
)
resp = await client.get_utxos_by_addresses({"addresses": [my_address]})
my_utxos = resp["entries"]
inputs = [
TransactionInput(
previous_outpoint=TransactionOutpoint(
transaction_id=u["outpoint"]["transactionId"],
index=u["outpoint"]["index"],
),
signature_script="", # filled at sign time
sequence=0,
sig_op_count=1,
utxo=UtxoEntryReference(u),
)
for u in my_utxos
]
outputs = [
TransactionOutput(value=amount, script_public_key=pay_to_address_script(recipient)),
TransactionOutput(value=change_amount, script_public_key=pay_to_address_script(change_addr)),
]
tx = Transaction(
version=0, inputs=inputs, outputs=outputs,
lock_time=0,
subnetwork_id="0000000000000000000000000000000000000000",
gas=0, payload="", mass=0,
)
update_transaction_mass("mainnet", tx) # mass is signed over — fill before signing
signed = sign_transaction(tx, [private_key], verify_sig=True)
await client.submit_transaction({
"transaction": signed,
"allowOrphan": False,
})
This is what the Generator (see Transaction Generator) does
internally — it picks UTXOs, computes mass, signs, and yields one or
more ready-to-submit PendingTransactions.