QubicTypeScript

buildTransaction

Construct the unsigned binary header for a Qubic transaction.

buildTransaction serializes a transaction header into 80 bytes (plus optional payload). The result is unsigned — pass it to signTransaction next.

buildTransaction(params)

import { buildTransaction } from "@qubic.org/tx"
import { publicKeyFromSeed } from "@qubic.org/crypto"
import { toSeed } from "@qubic.org/types"

const seed = toSeed("...")
const sourcePublicKey = publicKeyFromSeed(seed)
const destinationPublicKey = new Uint8Array(32) // zero = contract calls

const unsigned = buildTransaction({
  sourcePublicKey,
  destinationPublicKey,
  amount: 1_000_000n,
  targetTick: currentTick + 5,
  inputType: 0,              // 0 = plain transfer
  inputSize: 0,              // no payload
})
// unsigned is Uint8Array (80 bytes for a plain transfer)

Parameters

NameTypeDescription
sourcePublicKeyUint8Array32-byte sender public key
destinationPublicKeyUint8Array32-byte recipient public key
amountbigintTransfer amount in QU
targetTicknumberTick by which the node must process the transaction
inputTypenumber0 for transfers; procedure index for contract calls
inputSizenumberPayload byte length (0 for plain transfers)
payloadUint8Array | undefinedOptional payload bytes for contract calls

Returns Uint8Array — 80-byte header (+ inputSize payload bytes).


Target tick

targetTick is a deadline, not a schedule. The network rejects the transaction if the current tick has already passed targetTick when the node processes it. If targetTick is in the future, the node will process the transaction when it reaches that tick — or drop it after a grace period.

const { tick } = await live.getTickInfo()
const targetTick = tick + 5  // deadline: process within the next 5 ticks

Setting targetTick too low (e.g. tick + 1) risks rejection if the network is even slightly ahead of your clock. Setting it higher (e.g. tick + 20) gives more leeway but means the transaction sits pending longer before expiring if something goes wrong. The PROTOCOL.TICKS_TO_EXPIRY constant from @qubic.org/types defaults to 5 — a reasonable default for most conditions.


Header field layout

FieldOffsetSizeDescription
sourcePublicKey032 BSender FourQ public key
destinationPublicKey3232 BRecipient FourQ public key
amount648 B (LE)QU amount as little-endian int64
targetTick724 B (LE)Target tick as little-endian uint32
inputType762 B (LE)Procedure index
inputSize782 B (LE)Payload byte length

Plain transfer vs contract call

For a plain transfer (identity to identity):

  • destinationPublicKey = recipient's public key (from identityToPublicKey)
  • inputType = 0
  • inputSize = 0, no payload

For a contract call (SC transaction):

  • destinationPublicKey = 32 zero bytes (the contract's canonical address)
  • inputType = the procedure's input type constant
  • inputSize = payload.length
  • payload = encoded procedure input from a build*Input function

On this page