pyrxd.glyph — Glyph token protocol

class pyrxd.glyph.ContainerRevealScripts[source]

Bases: object

Scripts for a CONTAINER reveal.

__init__(ref, locking_script, scriptsig_suffix, child_ref)
Parameters:
Return type:

None

ref: GlyphRef
locking_script: bytes
scriptsig_suffix: bytes
child_ref: GlyphRef | None
class pyrxd.glyph.DaaMode[source]

Bases: IntEnum

__new__(value)
FIXED = 0
EPOCH = 1
ASERT = 2
LWMA = 3
SCHEDULE = 4
class pyrxd.glyph.DmintAlgo[source]

Bases: IntEnum

__new__(value)
SHA256D = 0
BLAKE3 = 1
K12 = 2
class pyrxd.glyph.DmintCborPayload[source]

Bases: object

The dmint object embedded in Glyph V2 token metadata CBOR.

Indexers read this to discover dMint contracts and display mining parameters in wallets/explorers without parsing the contract script.

Field names mirror Photonic Wallet DmintPayload type in types.ts.

__init__(algo, num_contracts, max_height, reward, premine, diff, daa_mode=DaaMode.FIXED, target_block_time=60, half_life=0, window_size=0)
Parameters:
Return type:

None

daa_mode: DaaMode = 0
classmethod from_cbor_dict(d)[source]

Parse the dmint CBOR value from an on-chain payload.

Parameters:

d (dict)

Return type:

DmintCborPayload

half_life: int = 0
target_block_time: int = 60
to_cbor_dict()[source]

Encode to the dict that becomes the dmint CBOR value.

Return type:

dict

window_size: int = 0
algo: DmintAlgo
num_contracts: int
max_height: int
reward: int
premine: int
diff: int
class pyrxd.glyph.DmintDeployParams[source]

Bases: object

Parameters for deploying a V2 dMint contract.

__init__(contract_ref, token_ref, max_height, reward, difficulty, algo=DmintAlgo.SHA256D, daa_mode=DaaMode.FIXED, target_time=60, half_life=3600, height=0, last_time=0)
Parameters:
Return type:

None

algo: DmintAlgo = 0
daa_mode: DaaMode = 0
half_life: int = 3600
height: int = 0
property initial_target: int

Compute initial target from difficulty using the SHA256d formula.

last_time: int = 0
target_time: int = 60
contract_ref: GlyphRef
token_ref: GlyphRef
max_height: int
reward: int
difficulty: int
class pyrxd.glyph.DmintState[source]

Bases: object

Parsed V2 dMint contract state (from on-chain UTXO script).

__init__(height, contract_ref, token_ref, max_height, reward, algo, daa_mode, target_time, last_time, target)
Parameters:
Return type:

None

classmethod from_script(script_bytes)[source]

Parse a dMint contract UTXO script into a DmintState.

Walks the 10 state pushes in declared order, then verifies that the next byte is OP_STATESEPARATOR (0xbd). Closes ultrareview re-review N7: the previous implementation searched for the FIRST 0xbd byte anywhere in the script and sliced the state at that position. Because 0xbd is a perfectly valid byte value inside any push payload (a 36-byte wire ref, a 4-byte height, a script-int target, etc.), an unlucky byte pattern would truncate the state at the wrong offset and either fail with a misleading error or — if the truncation happened to land on a recognizable opcode — return a DmintState built from garbage parsed past the wrong cut point.

Layout (matches build_dmint_state_script):

[0] height — _push_4bytes_le (opcode 0x04 + 4-byte LE uint32) [1] contractRef — 0xd8 + 36-byte wire ref [2] tokenRef — 0xd0 + 36-byte wire ref [3] maxHeight — _push_minimal [4] reward — _push_minimal [5] algoId — _push_minimal [6] daaMode — _push_minimal [7] targetTime — _push_minimal [8] lastTime — _push_4bytes_le (opcode 0x04 + 4-byte LE uint32) [9] target — _push_minimal (may be large for 256-bit algos) —— OP_STATESEPARATOR (0xbd) —— (code section follows; not parsed here)

Parameters:

script_bytes (bytes) – Raw script bytes from a dMint contract UTXO output.

Raises:

ValidationError – Script is malformed, too short, or missing OP_STATESEPARATOR at the end of the 10-item state.

Return type:

DmintState

property is_exhausted: bool
height: int
contract_ref: GlyphRef
token_ref: GlyphRef
max_height: int
reward: int
algo: DmintAlgo
daa_mode: DaaMode
target_time: int
last_time: int
target: int
class pyrxd.glyph.FtTransferParams[source]

Bases: object

Parameters for an FT transfer transaction.

Parameters:
  • ref – the GlyphRef identifying the token

  • utxos – list of FtUtxo available to spend

  • amount – FT units to send to new_owner_pkh

  • new_owner_pkh – recipient’s 20-byte PKH

  • private_key – sender’s pyrxd.keys.PrivateKey

  • fee_rate – photons/byte (Radiant post-V2 minimum is 10_000)

  • change_pkh – FT-change recipient PKH. Defaults to the sender’s PKH when None.

__init__(ref, utxos, amount, new_owner_pkh, private_key, fee_rate=10000, change_pkh=None)
Parameters:
Return type:

None

change_pkh: Hex20 | None = None
fee_rate: int = 10000
ref: GlyphRef
utxos: list
amount: int
new_owner_pkh: Hex20
private_key: Any
class pyrxd.glyph.FtTransferResult[source]

Bases: object

Output of FtUtxoSet.build_transfer_tx().

Parameters:
  • tx – signed Transaction, ready to broadcast

  • new_ft_script – locking script of the transfer (recipient) output

  • change_ft_script – locking script of the change output, or None if the transfer was an exact match

  • ref – the FT’s GlyphRef

  • fee – fee paid in photons

__init__(tx, new_ft_script, change_ft_script, ref, fee)
Parameters:
Return type:

None

tx: Any
new_ft_script: bytes
change_ft_script: bytes | None
ref: GlyphRef
fee: int
class pyrxd.glyph.FtUtxo[source]

Bases: object

A single UTXO holding some quantity of one FT.

Parameters:
  • txid – txid of the UTXO

  • vout – output index within that tx

  • value – RXD value (photons) on the output

  • ft_amount – token units held on the output

  • ft_script – full FT locking script (75 bytes, see pyrxd.glyph.script.build_ft_locking_script())

__init__(txid, vout, value, ft_amount, ft_script)
Parameters:
Return type:

None

txid: str
vout: int
value: int
ft_amount: int
ft_script: bytes
class pyrxd.glyph.FtUtxoSet[source]

Bases: object

Manages a set of FT UTXOs for a single token ref.

Responsibilities:

  • Total the FT amount across the set.

  • Select a minimum set of UTXOs to cover a requested transfer amount.

  • Build + sign a transfer tx (two-pass fee calculation) that respects conservation.

__init__(ref, utxos)[source]
Parameters:
Return type:

None

build_transfer_tx(amount, new_owner_pkh, private_key, fee_rate=10000, change_pkh=None, dust_limit=546)[source]

Build a signed FT transfer transaction enforcing conservation.

The selected UTXOs are spent with a standard P2PKH scriptSig (same unlock as an NFT transfer — the FT script embeds a full P2PKH prefix before the OP_PUSHINPUTREF / conservation epilogue, so <sig> <pubkey> satisfies it). A transfer output locked to new_owner_pkh is created for amount token units; any leftover token units flow to a change output locked to change_pkh (or the sender’s PKH if omitted).

Fee calculation uses the same two-pass pattern as GlyphBuilder.build_nft_transfer_tx(): build a trial tx → sign → measure bytes → rebuild fresh (so the final signature commits to the final outputs, not the trial ones).

Parameters:
  • amount (int) – FT units to transfer to new_owner_pkh

  • new_owner_pkh (Hex20) – recipient’s 20-byte PKH

  • private_key (Any) – pyrxd.keys.PrivateKey owning the inputs

  • fee_rate (int) – photons/byte (default 10_000, the Radiant minimum)

  • change_pkh (Hex20 | None) – FT-change recipient PKH. Defaults to the sender’s PKH derived from private_key.

  • dust_limit (int) – minimum photon value per output (default 546)

Raises:

ValueErroramount <= 0; total FT < amount; total RXD from the selected inputs cannot cover dust_limit * n_outputs + fee.

Returns:

FtTransferResult (signed tx, scripts, fee, ref).

Return type:

FtTransferResult

select(amount)[source]

Greedily select the minimum number of UTXOs covering amount.

Strategy: sort by ft_amount descending, take until covered.

Raises:

ValueErroramount exceeds total() (including the empty-set case, where total == 0).

Parameters:

amount (int)

Return type:

list[FtUtxo]

total()[source]

Return the sum of ft_amount across all UTXOs in the set.

Return type:

int

class pyrxd.glyph.GlyphBuilder[source]

Bases: object

Build unsigned Glyph transactions.

Separate commit and reveal methods — caller is responsible for:

  1. Signing the commit tx and broadcasting it.

  2. Waiting for confirmation.

  3. Passing the confirmed commit txid to the reveal method.

  4. Signing the reveal tx (via Transaction + PrivateKey).

Method selection guide (N9 — surface grew to 12 methods across 5 protocols)

Minting (commit → reveal)

Goal

Protocol tag(s)

Reveal method

Mint a singleton NFT

[NFT]

prepare_reveal()

Mint a plain FT

[FT]

prepare_ft_deploy_reveal()

Mint a dMint FT

[FT, DMINT]

prepare_dmint_deploy() (3 txs)

Mint a mutable NFT

[NFT, MUT]

prepare_mutable_reveal()

Mint a collection

``[NFT,CONTAINER]`

prepare_container_reveal()

Mint a WAVE name

[NFT,MUT,WAVE]

prepare_wave_reveal()

For every token type the first step is the same: call prepare_commit() (which derives the commit script from the metadata protocol list automatically). Only the reveal step differs.

Transfers (no commit needed)

Low-level (rarely called directly)

  • prepare_reveal() — generic reveal; is_nft picks singleton vs FT reftype

  • build_reveal_scripts() — alternate reveal entry that returns scripts, not params

  • build_transfer_locking_script() — bare FT lock without constructing a tx

  • build_contract_script() — MUT contract script for mutable NFT reveals

build_ft_transfer_tx(params)[source]

Build a signed FT transfer transaction enforcing conservation.

Thin delegator to FtUtxoSet.build_transfer_tx() — the real logic (selection, two-pass fee, conservation) lives there so the API surface is available both at the builder level and directly on a UTXO-set instance.

Parameters:

params (FtTransferParams) – FtTransferParams — see dataclass docstring.

Returns:

FtTransferResult — signed tx + scripts + fee.

Raises:

ValueError – same conditions as FtUtxoSet.build_transfer_tx() (insufficient FT balance, insufficient RXD for fee + dust).

Return type:

FtTransferResult

build_nft_transfer_tx(params)[source]

Build a signed NFT transfer transaction.

Spends an existing NFT UTXO (standard P2PKH scriptSig unlock: <sig> <pubkey>) and creates a new NFT output locked to new_owner_pkh. The 36-byte ref is preserved across the transfer — it’s extracted from the input’s NFT script and written into the new output’s NFT script unchanged.

Fee calculation is two-pass: build a trial tx, sign it to measure actual serialised size, then rebuild with the final value = input_value - size*fee_rate. The trial signature is discarded (reset unlocking_script = None before final sign) so the final tx carries a signature over the final outputs, not the trial ones.

Parameters:

params (TransferParams) – TransferParams — see dataclass docstring

Returns:

TransferResult — signed tx, new locking script, ref, fee

Raises:
Return type:

TransferResult

build_transfer_locking_script(ref, new_owner_pkh, is_nft)[source]

Build the locking script for a transfer output.

Parameters:
Return type:

bytes

prepare_commit(params)[source]

Prepare the commit transaction parameters.

Returns the commit locking script + CBOR bytes + estimated fee. Caller must build, sign, and broadcast the actual transaction.

The commit script’s OP_REFTYPE_OUTPUT check is derived from metadata.protocol: NFT (2 in protocol) produces an OP_2/SINGLETON-expecting commit; any other protocol mix (FT, dMint FT, data, etc.) produces an OP_1/NORMAL-expecting commit. This means the caller does not hand-pick refType — the metadata drives it. Prior versions forced every commit to NFT shape; see build_commit_locking_script for the fix note.

Parameters:

params (CommitParams)

Return type:

CommitResult

prepare_container_reveal(commit_txid, commit_vout, cbor_bytes, owner_pkh, child_ref=None)[source]

Prepare scripts for a CONTAINER reveal.

A container is an NFT with an additional OP_PUSHINPUTREF <child_ref> prefix that links it to a child token ref. When child_ref is None the container is created empty (no child ref in locking script).

Protocol field must include GlyphProtocol.CONTAINER (7).

Parameters:
Return type:

ContainerRevealScripts

prepare_dmint_deploy(params)[source]

Prepare a full dMint token deploy: commit + reveal + deploy scripts.

A dMint deploy requires three transactions in sequence:

  1. Commit tx — commits the token metadata payload hash on-chain (standard Glyph commit, same as prepare_commit()).

  2. Reveal tx — spends the commit, creates the token ref UTXO (a 75-byte FT locking script — same shape as prepare_ft_deploy_reveal()). The token ref outpoint is the permanent identifier of the FT token.

  3. Deploy tx — creates the singleton contract UTXO, funded with the initial reward pool. Its output script is a full build_dmint_contract_script() — state prefix + OP_STATESEPARATOR + covenant code.

Usage

builder = GlyphBuilder()
result = builder.prepare_dmint_deploy(DmintFullDeployParams(...))

# Step 1: build, sign, broadcast commit tx using result.commit_result
# Step 2: wait for confirmation, get commit_txid
# Step 3: build reveal tx using result.reveal_scripts
# Step 4: broadcast reveal, get reveal_txid + reveal_vout
# Step 5: build deploy tx using result.deploy_contract_script
#         (the contract input refs the token ref at reveal outpoint)

The caller is responsible for constructing and signing actual Transaction objects using the scripts returned here, following the same pattern as the integration test in tests/test_dmint_deploy_integration.py.

param params:

DmintFullDeployParams — all deploy configuration.

returns:

DmintDeployResult with commit, reveal, and deploy artefacts.

raises ValidationError:

params.premine_amount < 546 (dust limit); metadata protocol does not include FT; reward pool too small.

Parameters:

params (DmintFullDeployParams)

Return type:

DmintDeployResult

prepare_ft_deploy_reveal(commit_txid, commit_vout, commit_value, cbor_bytes, premine_pkh, premine_amount)[source]

Prepare reveal scripts + premine amount for an FT deploy.

Thin convenience wrapper around prepare_reveal() for the FT-deploy-with-premine flow: the reveal produces one FT output carrying the full issued supply to premine_pkh, and its outpoint becomes the permanent token ref.

Caller still constructs the actual transaction. The returned premine_amount is what vout[0].value must be on the reveal tx — typically the full supply for a premine-only deploy (no covenant UTXO). Radiant FT convention: 1 photon = 1 FT unit, so premine_amount is the supply in whole units.

No dMint-specific logic here. The cbor_bytes already encode whatever protocol markers the caller chose — dMint FT ([1,4]), plain FT ([1]), or any other combination — via GlyphMetadata. pyrxd treats the protocol markers as caller-owned; classification happens at the indexer layer.

Parameters:
  • commit_txid (str)

  • commit_vout (int)

  • commit_value (int)

  • cbor_bytes (bytes)

  • premine_pkh (Hex20)

  • premine_amount (int)

Return type:

FtDeployRevealScripts

prepare_mutable_reveal(commit_txid, commit_vout, cbor_bytes, owner_pkh)[source]

Prepare scripts for a MUT (mutable NFT) reveal.

Returns the two output locking scripts the caller must place in the reveal tx: - nft_script: 63-byte NFT singleton (token the owner holds) - contract_script: 174-byte mutable contract UTXO (holds state)

The reveal scriptSig suffix is also returned; the caller prepends <sig> <pubkey> to form the full scriptSig.

Protocol field in cbor_bytes must include GlyphProtocol.MUT (5). Use GlyphMetadata(protocol=[GlyphProtocol.NFT, GlyphProtocol.MUT]).

Parameters:
Return type:

MutableRevealScripts

prepare_reveal(params)[source]

Prepare the reveal transaction scripts.

Returns locking script + scriptSig suffix. Caller must build, sign, and broadcast the actual transaction.

Parameters:

params (RevealParams)

Return type:

RevealScripts

prepare_wave_reveal(commit_txid, commit_vout, cbor_bytes, owner_pkh, name)[source]

Prepare scripts for a WAVE (on-chain naming) reveal.

WAVE extends MUT with a name field in the CBOR payload. Protocol field must include GlyphProtocol.WAVE (11).

name must be non-empty printable ASCII, max 255 characters. The name is validated here but must already be embedded in cbor_bytes by the caller via GlyphMetadata(name=...).

Protocol requirement: [NFT(2), MUT(5), WAVE(11)].

Parameters:
Return type:

MutableRevealScripts

class pyrxd.glyph.GlyphCreator[source]

Bases: object

Creator identity and optional ECDSA signature over the metadata commit hash.

pubkey: 33-byte compressed secp256k1 pubkey, hex-encoded. sig: DER-encoded ECDSA signature, hex-encoded (empty string = unsigned). algo: Signing algorithm identifier string.

__init__(pubkey, sig='', algo='ecdsa-secp256k1')
Parameters:
Return type:

None

algo: str = 'ecdsa-secp256k1'
classmethod from_cbor_dict(d)[source]
Parameters:

d (dict)

Return type:

GlyphCreator

sig: str = ''
to_cbor_dict()[source]
Return type:

dict

pubkey: str
class pyrxd.glyph.GlyphFt[source]

Bases: object

A minted or transferable FT Glyph.

__init__(ref, owner_pkh, amount, metadata)
Parameters:
Return type:

None

ref: GlyphRef
owner_pkh: Hex20
amount: int
metadata: GlyphMetadata
class pyrxd.glyph.GlyphInspector[source]

Bases: object

Parse raw transaction bytes to find Glyph outputs. Pure — no network access.

extract_reveal_metadata(scriptsig)[source]

Parse a reveal TX scriptSig to extract CBOR metadata.

scriptSig format: <sig> <pubkey> <”gly”> <CBOR> Returns None if this is not a reveal scriptSig.

Parameters:

scriptsig (bytes)

Return type:

GlyphMetadata | None

find_glyphs(tx_outputs)[source]

Given list of (satoshis, script_bytes) outputs, return detected Glyphs.

Parameters:

tx_outputs (list[tuple[int, bytes]])

Return type:

list[GlyphOutput]

class pyrxd.glyph.GlyphMetadata[source]

Bases: object

CBOR payload for a Glyph token.

__init__(protocol, name='', ticker='', description='', token_type='', main=None, attrs=<factory>, loc='', loc_hash='', decimals=0, image_url='', image_ipfs='', image_sha256='', v=None, dmint_params=None, creator=None, royalty=None, policy=None, rights=None, created='', commit_outpoint='')
Parameters:
Return type:

None

commit_outpoint: str = ''
created: str = ''
creator: GlyphCreator | None = None
decimals: int = 0
description: str = ''
dmint_params: DmintCborPayload | None = None
classmethod for_dmint_ft(ticker, name, decimals=0, description='', image_url='', image_ipfs='', image_sha256='', protocol=None, dmint_params=None)[source]

Construct GlyphMetadata for a dMint-marked FT deploy.

Pass dmint_params (a DmintCborPayload) to embed the dMint configuration object in the token metadata. Indexers and wallets use this to display mining parameters without parsing the contract script.

Sets v=2 automatically when dmint_params is provided.

Parameters:
Return type:

GlyphMetadata

image_ipfs: str = ''
image_sha256: str = ''
image_url: str = ''
loc: str = ''
loc_hash: str = ''
main: GlyphMedia | None = None
name: str = ''
policy: GlyphPolicy | None = None
rights: GlyphRights | None = None
royalty: GlyphRoyalty | None = None
ticker: str = ''
to_cbor_dict()[source]

Build the dict that gets CBOR-encoded (excluding ‘gly’ marker).

Return type:

dict

token_type: str = ''
v: int | None = None
protocol: list[int]
attrs: dict[str, str]
class pyrxd.glyph.GlyphNft[source]

Bases: object

A minted or transferable NFT Glyph.

__init__(ref, owner_pkh, metadata)
Parameters:
Return type:

None

ref: GlyphRef
owner_pkh: Hex20
metadata: GlyphMetadata
class pyrxd.glyph.GlyphPolicy[source]

Bases: object

Token behaviour policy flags.

__init__(renderable=None, executable=None, nsfw=None, transferable=None)
Parameters:
  • renderable (bool | None)

  • executable (bool | None)

  • nsfw (bool | None)

  • transferable (bool | None)

Return type:

None

executable: bool | None = None
classmethod from_cbor_dict(d)[source]
Parameters:

d (dict)

Return type:

GlyphPolicy

nsfw: bool | None = None
renderable: bool | None = None
to_cbor_dict()[source]
Return type:

dict

transferable: bool | None = None
class pyrxd.glyph.GlyphProtocol[source]

Bases: IntEnum

__new__(value)
FT = 1
NFT = 2
DAT = 3
DMINT = 4
MUT = 5
BURN = 6
CONTAINER = 7
ENCRYPTED = 8
TIMELOCK = 9
AUTHORITY = 10
WAVE = 11
class pyrxd.glyph.GlyphRef[source]

Bases: object

36-byte Glyph reference: txid (reversed LE) + vout (4-byte LE).

__init__(txid, vout)
Parameters:
Return type:

None

classmethod from_bytes(data)[source]

Parse 36-byte wire format.

Parameters:

data (bytes)

Return type:

GlyphRef

to_bytes()[source]

Encode as 36-byte wire format: txid_reversed + vout_le.

Return type:

bytes

txid: Txid
vout: int
class pyrxd.glyph.GlyphRights[source]

Bases: object

Licensing and attribution information.

__init__(license='', terms='', attribution='')
Parameters:
  • license (str)

  • terms (str)

  • attribution (str)

Return type:

None

attribution: str = ''
classmethod from_cbor_dict(d)[source]
Parameters:

d (dict)

Return type:

GlyphRights

license: str = ''
terms: str = ''
to_cbor_dict()[source]
Return type:

dict

class pyrxd.glyph.GlyphRoyalty[source]

Bases: object

On-chain royalty hint for secondary-market wallets.

bps: Basis points (100 = 1%, 500 = 5%, max 10000 = 100%). address: Radiant address to receive royalty payments. enforced: Whether wallets should enforce this royalty. minimum: Minimum royalty amount in photons (0 = no minimum). splits: Optional list of (address, bps) pairs for royalty splitting.

The sum of split bps should equal the top-level bps.

__init__(bps, address, enforced=False, minimum=0, splits=<factory>)
Parameters:
Return type:

None

enforced: bool = False
classmethod from_cbor_dict(d)[source]
Parameters:

d (dict)

Return type:

GlyphRoyalty

minimum: int = 0
to_cbor_dict()[source]
Return type:

dict

bps: int
address: str
splits: tuple[tuple[str, int], ...]
class pyrxd.glyph.GlyphScanner[source]

Bases: object

Scan a Radiant address or script_hash for Glyph outputs.

Parameters:

client – An already-connected ElectrumXClient. The scanner does not own the connection lifecycle; callers should use the client as a context manager and pass it in.

__init__(client)[source]
Parameters:

client (ElectrumXClient)

Return type:

None

async scan_address(address)[source]

Return all Glyph outputs currently owned at address.

Parameters:

address (str) – Base58Check-encoded P2PKH address.

Returns:

Typed Glyph objects. metadata is None for transfer outputs (no reveal scriptSig in the origin transaction).

Return type:

List[GlyphNft | GlyphFt]

async scan_script_hash(script_hash)[source]

Return all Glyph outputs for script_hash.

Fetches UTXOs, raw transactions, and (where available) reveal transaction metadata, then constructs typed GlyphNft / GlyphFt objects.

Concurrency: UTXO raw-tx fetches and reveal-metadata fetches both run in parallel via asyncio.gather. Pre-fix (closes ultrareview re-review N17) the reveal-metadata path was inside the per-utxo loop and serialised one round-trip per glyph; for a 100-glyph wallet that meant ~100x the latency of the now- batched version.

Parameters:

script_hash (Hex32 | bytes | str)

Return type:

list[GlyphNft | GlyphFt]

class pyrxd.glyph.MutableRevealScripts[source]

Bases: object

Scripts for a MUT reveal — two outputs required.

__init__(ref, nft_script, contract_script, scriptsig_suffix, payload_hash)
Parameters:
Return type:

None

ref: GlyphRef
nft_script: bytes
contract_script: bytes
scriptsig_suffix: bytes
payload_hash: bytes
pyrxd.glyph.build_dmint_contract_script(params)[source]

Build the full V2 dMint output script: state + OP_STATESEPARATOR + code.

Parameters:

params (DmintDeployParams)

Return type:

bytes

pyrxd.glyph.build_dmint_state_script(params)[source]

Build the 10-item V2 dMint state script (before OP_STATESEPARATOR).

Layout (§4.2):

height(4B LE) | d8:contractRef(36B) | d0:tokenRef(36B) | maxHeight | reward | algoId | daaMode | targetTime | lastTime(4B LE) | target

Parameters:

params (DmintDeployParams)

Return type:

bytes

pyrxd.glyph.build_mint_scriptsig(nonce, preimage)[source]

Build the scriptSig a miner includes in the contract-spend input.

Format (SHA256d): <nonce:8B> 20 <inputHash:32B> 20 <outputHash:32B> 00 The nonce is 8 bytes (two u32 values concatenated, as in V1).

Parameters:
  • nonce (bytes) – 8-byte nonce (found during GPU/CPU mining)

  • preimage (bytes) – 64-byte preimage from build_pow_preimage()

Return type:

bytes

pyrxd.glyph.build_mutable_nft_script(mutable_ref, payload_hash)[source]

Build the 175-byte mutable NFT output script.

Layout: PUSH32 <payload_hash> OP_DROP OP_STATESEPARATOR

OP_PUSHINPUTREFSINGLETON <mutable_ref:36> <102-byte body>

Parameters:
  • mutable_ref (GlyphRef) – The singleton ref that identifies the mutable contract.

  • payload_hash (bytes) – 32-byte SHA256d of the CBOR metadata payload.

Return type:

bytes

pyrxd.glyph.build_mutable_scriptsig(operation, cbor_bytes, contract_output_index, ref_hash_index, ref_index, token_output_index)[source]

Build the scriptSig for spending a mutable NFT contract input.

The mutable NFT script expects the scriptSig stack (bottom→top):

gly_marker | cbor_payload | operation | contract_output_index | ref_hash_index | ref_index | token_output_index

Parameters:
  • operation (Literal['mod', 'sl']) – "mod" (modify — update payload hash) or "sl" (seal — burn the mutable contract).

  • cbor_bytes (bytes) – CBOR-encoded metadata for the new state.

  • contract_output_index (int) – Output index of the mutable contract in the tx.

  • ref_hash_index (int) – Index into the refdatasummary for this token.

  • ref_index (int) – Index of the singleton ref in token output data.

  • token_output_index (int) – Output index of the token in the tx.

Return type:

bytes

pyrxd.glyph.build_pow_preimage(txid_le, contract_ref_bytes, input_script, output_script)[source]

Build the 64-byte PoW preimage.

preimage[0..32] = SHA256(txid_LE || contractRef) preimage[32..64] = SHA256(SHA256d(inputScript) || SHA256d(outputScript))

Parameters:
  • txid_le (bytes) – 32-byte txid in little-endian (internal byte order)

  • contract_ref_bytes (bytes) – 36-byte contract ref (wire format)

  • input_script (bytes) – miner’s input locking script (e.g. P2PKH)

  • output_script (bytes) – miner’s output script (e.g. OP_RETURN message)

Return type:

bytes

pyrxd.glyph.compute_next_target_asert(current_target, last_time, current_time, target_time, half_life)[source]

Compute next ASERT-lite target (mirrors on-chain OP_LSHIFT/OP_RSHIFT logic).

drift = (current_time - last_time - target_time) // half_life drift is clamped to [-4, +4]. drift > 0 → target <<= drift (easier) drift < 0 → target >>= |drift| (harder) Minimum target is 1.

Parameters:
  • current_target (int)

  • last_time (int)

  • current_time (int)

  • target_time (int)

  • half_life (int)

Return type:

int

pyrxd.glyph.compute_next_target_linear(current_target, last_time, current_time, target_time)[source]

Compute next linear DAA target: new_target = old_target * time_delta / target_time.

Parameters:
  • current_target (int)

  • last_time (int)

  • current_time (int)

  • target_time (int)

Return type:

int

pyrxd.glyph.difficulty_to_target(difficulty, algo=DmintAlgo.SHA256D)[source]

Convert difficulty to PoW target.

Parameters:
Return type:

int

pyrxd.glyph.parse_mutable_nft_script(script)[source]

Parse a mutable NFT output script, returning (mutable_ref, payload_hash) or None.

Parameters:

script (bytes)

Return type:

tuple[GlyphRef, bytes] | None

pyrxd.glyph.sign_metadata(metadata, private_key, algo='ecdsa-secp256k1')[source]

Return a new GlyphMetadata with creator.sig populated.

The private key’s compressed public key is embedded as creator.pubkey. The signing protocol is:

  1. Build canonical CBOR with sig=”” and the pubkey.

  2. commit_hash = SHA256d(cbor)

  3. message = SHA256(“glyph-v2-creator:” || commit_hash)

  4. sig = ECDSA(private_key, message) [low-s DER, no double-hash]

Parameters:
  • metadata (GlyphMetadata) – GlyphMetadata to sign. Any existing creator field is replaced.

  • private_key (PrivateKey) – pyrxd PrivateKey — the token deployer’s key.

  • algo (str) – Signing algorithm identifier (default: “ecdsa-secp256k1”).

Returns:

A frozen copy of metadata with creator.sig set.

Return type:

GlyphMetadata

pyrxd.glyph.target_to_difficulty(target, algo=DmintAlgo.SHA256D)[source]

Convert PoW target to difficulty (approximate).

Parameters:
Return type:

int

pyrxd.glyph.verify_creator_signature(metadata)[source]

Verify the creator signature embedded in metadata.

Returns:

(True, “”) if valid; (False, reason) if invalid or missing.

Parameters:

metadata (GlyphMetadata)

Return type:

tuple[bool, str]

pyrxd.glyph.verify_sha256d_solution(preimage, nonce, target)[source]

Verify a SHA256d PoW solution.

Valid if: hash[0..4] == 0x00000000 AND int.from_bytes(hash[4..12], ‘big’) < target

target is clamped to MAX_SHA256D_TARGET before comparison — a caller-supplied target above the maximum would make the check trivially pass for any hash that starts with four zero bytes.

Parameters:
Return type:

bool