dMint V1 Deploy — Mainnet Truth + Photonic Divergence (2026-05-08)¶
Research notes for pyrxd’s M2 (V1 deploy support). All on-chain data was
pulled directly from wss://electrumx.radiant4people.com:50022/; every hex
string and txid below was either copied out of that server’s JSON-RPC
response or computed locally from those bytes.
Verified facts (everything below tagged “from chain”) came from the
public RXD ElectrumX server. Photonic source citations point to
RadiantBlockchain-Community/photonic-wallet@master cloned to
/tmp/photonic-wallet. Unverified assumptions are called out where
they remain.
This doc is the Phase 2a deliverable for the M2 plan
(docs/plans/2026-05-08-feat-dmint-v1-deploy-plan.md). Phase 2b
(implementation) starts only after these findings are reviewed.
1. Reference deployment: Glyph Protocol (GLYPH)¶
The only mainnet V1 dMint deploy located so far is RBG’s “Glyph Protocol” deployment.
Field |
Value |
Source |
|---|---|---|
Deploy commit txid |
|
from chain (h=228604) |
Deploy reveal txid |
|
from chain (h=228604) |
Reveal raw size |
79,141 bytes |
from chain |
Reveal vin × vout |
36 × 35 |
from chain |
Token ticker |
|
CBOR |
Token name |
|
CBOR |
Token description |
|
CBOR |
Protocol version |
|
CBOR |
numContracts |
32 |
count of 241-byte contract outputs in reveal |
maxHeight |
625,000 |
bytes 80..82 of reveal vout 0 contract state (first 3-byte push after tokenRef) |
reward (sats) |
50,000 |
bytes 84..86 of reveal vout 0 contract state (second 3-byte push) |
target (8 bytes BE) |
|
bytes 88..95 of reveal vout 0 contract state |
Total supply |
32 × 625,000 × 50,000 = 1,000,000,000,000 sats (10,000 GLYPH @ 8 decimals) |
computed from above |
Algorithm |
sha256d ( |
epilogue PoW-hash opcode in vout 0 |
DAA mode |
none (jumps straight to cleanup) |
epilogue body shape |
These match the M1 mint research at docs/dmint-research-mainnet.md
exactly — the seven contract UTXOs sampled there were 7 of these 32.
2. Deploy commit shape (verified from chain)¶
The deploy commit a443d9df…878b has 35 outputs, 1448 bytes total
serialized:
vout |
bytes |
type |
role |
|---|---|---|---|
0 |
75 |
gly hashlock (≥1 ref) |
FT commit — preimage on |
1–32 |
25 each |
bare P2PKH |
32 ref-seeds (one sat each, all to the deployer’s PKH) — each becomes the |
33 |
75 |
gly hashlock (≥2 refs) |
NFT commit — preimage on |
34 |
25 |
bare P2PKH |
change |
2.1 The 75-byte hashlock shape¶
Both vout 0 and vout 33 follow the Photonic ftCommitScript/nftCommitScript pattern
(/tmp/photonic-wallet/packages/lib/src/script.ts lines 152–213):
OP_HASH256 <32-byte payload-hash> OP_EQUALVERIFY
PUSH(3) "gly" OP_EQUALVERIFY
OP_INPUTINDEX OP_OUTPOINTTXHASH OP_INPUTINDEX OP_OUTPOINTINDEX
OP_4 OP_NUM2BIN OP_CAT OP_REFTYPE_OUTPUT OP_<N> OP_NUMEQUALVERIFY
OP_DUP OP_HASH160 PUSH(20) <20-byte pkh> OP_EQUALVERIFY OP_CHECKSIG
The OP_<N> byte differs between FT and NFT:
FT commit (vout 0):
OP_1(0x51) — require ≥1 ref output (the FT contract creation)NFT commit (vout 33):
OP_2(0x52) — require ≥2 ref outputs (singleton + mutable container)
2.2 No delegate-ref prefix¶
Both 75-byte scripts on this deploy commit start at offset 0 with aa 20
(OP_HASH256 then PUSH(32)). Photonic’s addDelegateRefScript
(script.ts:138) would prepend OP_PUSHINPUTREF <ref> OP_DUP ... at the
front — but those bytes are absent here. So this deploy did not use
delegate-funded commits. M2 should default delegate=None and treat
delegate-ref support as deferred work (M3+).
3. Deploy reveal shape (verified from chain)¶
Reveal b965b32d…9dd6 has 36 inputs and 35 outputs:
3.1 Inputs¶
vin |
spends |
role |
|---|---|---|
0 |
|
scriptSig (65,685 bytes) carries |
1–32 |
|
scriptSig is plain |
33 |
|
scriptSig (168 bytes) carries |
34 |
|
brings the auth NFT identity in from a prior mint |
35 |
|
funds the (large) reveal fee |
Implication for M2: the V1 deploy reveal needs to handle a heterogeneous input set — non-trivial scriptSigs (vin 0, vin 33) plus many P2PKH spends (vins 1–32, vin 35) plus an optional pre-existing singleton spend (vin 34). The pyrxd builder must:
Sign inputs with different scriptSig shapes (preimage-revealing vs plain P2PKH).
Manage UTXO ordering so vin 0 = FT commit, vin 33 = NFT commit, vins 1–32 = ref-seeds in vout-order, change last.
Optionally accept a “pre-existing auth NFT singleton input” (vin 34 in this reveal). For pyrxd M2’s first cut, we can omit this and require the auth NFT to be created freshly inside the deploy commit, which means using vout 33 of the commit as a true NFT commit with its own CBOR body. See §6 for the choice we make.
3.2 Outputs¶
vout |
bytes |
role |
|---|---|---|
0–31 |
241 each |
32 V1 dMint contract UTXOs (state + epilogue) — each with |
32 |
63 |
FT NFT (the public-facing token marker) — script |
33 |
63 |
Auth/container NFT (forwards prior identity) — script |
34 |
25 |
change P2PKH (~45.87 RXD) |
3.3 Contract UTXO state breakdown (vout 0 of reveal)¶
Verified byte-for-byte from chain. The 96-byte state portion decomposes as:
[ 0.. 4] 04 00 00 00 00 height = 0 (LE-4 push)
[ 5.. 41] d8 8b 87 c3 c7 71 b1 a9 f5 01 5a 4f 26 bf d8 09 79 ed 19 6b
53 66 25 7a 6f 30 92 96 46 df d9 43 a4 01 00 00 00 d8 + contractRef = a443d9df:1 (LE-reversed 32-byte txid + LE-4 vout)
[42.. 78] d0 8b 87 c3 c7 71 b1 a9 f5 01 5a 4f 26 bf d8 09 79 ed 19 6b
53 66 25 7a 6f 30 92 96 46 df d9 43 a4 00 00 00 00 d0 + tokenRef = a443d9df:0
[79.. 82] 03 68 89 09 maxHeight = 625,000 (LE-3 push)
[83.. 86] 03 50 c3 00 reward = 50,000 (LE-3 push)
[87.. 95] 08 74 da 40 a7 0d 74 da 00 target = 0x00da740da740da74 (LE-8 push)
Then byte 96 = bd (OP_STATESEPARATOR), and bytes 97..240 are the
145-byte V1 epilogue (sha256d, fixed difficulty, FT-wrapped reward).
This is exactly what build_dmint_v1_contract_script in M1 emits.
So pyrxd M2 just needs to call that builder once per contract output
in the reveal.
4. CBOR token body (vin 0 of reveal scriptSig)¶
Format: the FT commit preimage is structured as:
<DER-sig> <33-byte pubkey> "gly" <OP_PUSHDATA4> <length-LE-4> <CBOR-map>
For this deploy: payload was 65,569 bytes; CBOR map keys (canonical order):
{
"p": [1, 4], # protocol = V1 dMint FT ← REQUIRED
"ticker": "GLYPH",
"name": "Glyph Protocol",
"desc": "The first of its kind",
"by": [CBORTag(64, <36-byte NFT singleton ref>)],
"main": {"t": "image/png", "b": CBORTag(64, <PNG bytes>)},
}
Critical for M2:
The CBOR
pfield is[1, 4](the integer pair “V1 dMint FT”). pyrxd must emit this exact value for V1 deploys. It must NOT emit avfield (that’s for V2).dMint parameters (numContracts, reward, maxHeight, target, algorithm, daa mode) are NOT in the CBOR. They live entirely inside the contract output scripts. The CBOR is metadata-only.
bycarries the 36-byte ref of the NFT that “owns” / authenticates this deploy. In this case it is the prior mutable container ref (6ad5ce8c…4c87:0), tagged with CBOR tag 64 so RXinDexer/Photonic recognize it as an outpoint, not opaque bytes.maincarries the project’s display image. M2’s first deploy can skip this (no image) —mainis optional in Photonic.
4.1 Auth NFT body (vin 33 of reveal scriptSig)¶
{
"p": [2], # protocol = V2 NFT
"loc": 0,
"by": [CBORTag(64, <NFT singleton ref 874c3cce…d56a:0>)],
}
This is a tiny 33-byte CBOR map (auth NFT had no name/description/image
in this deploy). The by ref points at the prior Glyph commit
(874c3cce…d56a:0 at h=227767), which itself was a Glyph NFT commit
that was revealed at a different time. So this isn’t really a
“freshly-minted auth NFT” — it’s a forwarding of an existing NFT.
For pyrxd M2: this is deferred work. The simpler path is to mint the auth NFT freshly inside the same deploy reveal (using a normal glyph NFT commit/reveal flow). See §6.
5. Photonic Wallet source (canonical reference)¶
The canonical TS source paths for V1 deploy:
File |
Lines |
What it does |
|---|---|---|
|
|
Builds the commit-tx outputs given contract type (“ft”/“nft”/“dat”) and deploy method (“direct”/“psbt”/“dmint”). For |
|
|
Builds the reveal-tx I/O. For |
|
|
The 75-byte gly hashlock shape (with optional delegate-ref prefix). |
|
|
Same shape with |
|
|
EMITS V2 ONLY in current master — does not produce the V1 9-state-item layout. See §7. |
|
|
The shape of params M2 will closely mirror in |
|
|
V2-only schema (algo / daa / etc.); V1 has a much smaller surface. |
5.1 Photonic RevealDmintParams shape¶
type RevealDmintParams = {
address: string; // P2PKH owner of all ref-seeds + change
difficulty: number; // human-friendly difficulty (mapped to target via dMintDiffToTarget)
numContracts: number; // count of parallel contracts (32 for the GLYPH deploy)
maxHeight: number; // max mints per contract
reward: number; // sats per mint
premine: number; // optional premine sats (in addition to dMint contracts)
algorithm?: string; // V2 only — V1 ignores
daaMode?: string; // V2 only — V1 ignores
daaParams?: any; // V2 only — V1 ignores
};
For pyrxd M2 we drop the V2-only fields:
@dataclass(frozen=True)
class DmintV1DeployParams:
owner_address: Address # PKH owner of ref-seeds + change
num_contracts: int # 1..256 (chain has examples up to 32)
reward_sats: int # per-mint reward, fits in 3 bytes (≤ 0xFFFFFF)
max_height: int # max mints per contract, fits in 3 bytes
target: int # 8-byte difficulty target
ticker: str
name: str
description: str
auth_nft_ref: bytes | None = None # if None, mint auth NFT freshly in deploy
main_image: bytes | None = None
main_image_mime: str | None = None
(Final field naming and frozen-ness will match plan §3.1.)
6. Auth NFT decision: forward-prior vs mint-fresh¶
The on-chain GLYPH deploy uses forward-prior: vin 34 spends an
existing mutable-container NFT (6de766d7:12), and vout 33 of the
reveal re-emits the same singleton ref forward.
Pros of forward-prior (the on-chain way):
Single tx, single signing pass.
The “deployer” identity persists across multiple deploys (one auth NFT for many tokens).
Cons:
Requires the deployer to already hold a mutable-container NFT.
The reveal must include both the FT-commit preimage AND the NFT singleton input — heterogeneous scriptSig shapes.
pyrxd doesn’t currently have an NFT-mint flow that creates that initial container (M3 work).
Pros of mint-fresh (the pyrxd M2 approach):
Self-contained: the deploy commit’s vout 33 is a real NFT commit, and the reveal’s vin 33 carries a genuine NFT-body CBOR.
No prior NFT required.
Cons:
Each deploy mints a new auth NFT — no “studio” identity reuse. Indexers will treat each deploy as having its own owner-NFT.
Decision (pyrxd M2): mint-fresh. Forward-prior is documented as
deferred work. RXinDexer accepts both shapes (it just looks at the
by ref in the FT body CBOR).
This means our deploy reveal is simpler than the on-chain example:
vin 0: spend FT commit hashlock (CBOR FT body)
vin 1..N: spend N ref-seeds (P2PKH)
vin N+1: spend NFT commit hashlock (CBOR NFT body, p:[2], by=<self>)
vin N+2: spend change (P2PKH)
vout 0..N-1: N dMint contract UTXOs
vout N: FT NFT (d8 <commit:0-LE> 75 P2PKH)
vout N+1: auth NFT (d8 <commit:N+1-LE> 75 P2PKH)
vout N+2: change
…where N = numContracts. Total commit vouts = N+3 (FT-commit, N seeds, NFT-commit, change). Total reveal vouts = N+3 (N contracts, FT NFT, auth NFT, change).
7. Photonic divergences (pyrxd-specific)¶
7.1 V1 contract output layout (RESOLVED IN M1)¶
dMintScript() in current photonic-wallet master only emits the V2
10-state-item shape. pyrxd M1 already implemented build_dmint_v1_contract_script
(in pyrxd.glyph.dmint) which emits the V1 9-state-item shape used on
mainnet. M2 will call this M1 builder.
7.2 Premine handling¶
Photonic supports an optional premine: number in RevealDmintParams.
The on-chain GLYPH deploy did not use a premine. Decision (M2):
skip premine support in the first cut — file as deferred work. Adds 1
output to the reveal if non-zero, no other complexity.
7.3 Delegate-ref commit prefix¶
Photonic supports delegateRef in commit scripts (a prefix like
OP_PUSHINPUTREF <ref> OP_DUP ...). The on-chain GLYPH deploy did
not use one. Decision (M2): delegate=None always; defer
delegate-ref support to a later milestone if anyone asks for it.
7.4 Algorithm + DAA mode¶
Photonic’s dMintScript accepts algorithm and daaMode parameters
(for V2). V1 contracts have no DAA and only sha256d in practice.
Decision (M2): hardcode algorithm = 'sha256d', no DAA. M1 also
made this choice.
7.5 V1 vs V2 protocol vector in CBOR¶
V1:
p: [1, 4](novfield)V2:
v: 1, p: [2, 4](different keys)
M2 must emit [1, 4] and not include v. This was already the
plan’s spec, now confirmed against chain truth.
8. Acceptance gates derived from this research¶
The plan §4 (Acceptance Criteria) already lists the three-tier gate (synthetic → VPS testmempoolaccept → real mainnet). This research adds:
Synthetic vector: build a tx with the same params as GLYPH (
numContracts=32,reward=625_000,maxHeight=50_000,target=0x00da740da740da74) and assert that vout 0 of the reveal is byte-identical to the on-chain reveal’s vout 0 (after substituting the test deployer’s PKH and a placeholder commit txid). This is the strongest synthetic test we can write — the chain itself is the oracle.VPS testmempoolaccept: relay the deploy reveal in
dryrunmode viaradiant-cli testmempoolacceptagainst a regtest fork that’s been synced past the V1 dMint activation height. Assertallowed: true.Mainnet smoke: deploy a small token (
numContracts=4,reward=1,maxHeight=10, target high enough to allow CPU mining) to mainnet from a tiny test wallet; verify it appears in RXinDexer and that we can mint from at least one contract using the M1 mint builder.
9. Open questions remaining¶
Reveal scriptSig stub size for fees. The FT preimage push can be arbitrarily large (the GLYPH reveal carried a 65KB PNG). pyrxd’s fee estimator must accept caller-provided body length and pad correctly. This is a builder-API design point for Phase 2b.
Joint NFT+FT V1 deploy — would it be useful to deploy an NFT and an FT together? Photonic supports it via
commitBatch. Filed as deferred work; not needed for M2 acceptance.Resume after partial broadcast. If the commit confirms but the reveal fails, we must be able to resume by signing only the reveal given the saved commit txid. Plan already calls for this; this research confirms the resume input shape: just the saved
commit_txidand theDmintV1DeployParamsis enough to deterministically reproduce the reveal.
10. Sources¶
From chain (queried 2026-05-08 from wss://electrumx.radiant4people.com:50022/)¶
Deploy commit
a443d9df…878braw bytes, vout count, all 35 scriptPubKey hexes — saved to/tmp/dmint-m2-research/commit_raw.hex+commit_verbose.jsonduring research.Deploy reveal
b965b32d…9dd6raw bytes, all 36 input prevouts + scriptSigs, all 35 output scripts — saved to/tmp/dmint-m2-research/reveal_raw.hex+reveal_verbose.json.Prior tx
874c3cce…d56a(h=227767) — confirmed as a 3-vout Glyph NFT commit/reveal predecessor.Prior tx
6de766d7…3eaf(h=228398) — confirmed as the 14-vin/14-vout mutable-container NFT mint that supplies vin 34 of the deploy reveal.
From Photonic Wallet master (cloned to /tmp/photonic-wallet)¶
packages/lib/src/mint.ts:174–276(commit builders) — read in full.packages/lib/src/mint.ts:362–484(reveal builder) — read in full.packages/lib/src/script.ts:152–263(commit/output script primitives) — read.packages/lib/src/script.ts:704–766(dMintScript — V2-only in master) — read.packages/lib/src/types.ts:60–110(DeployMethod,RevealDmintParams,DmintPayload) — read.
From pyrxd M1 work (this branch’s parent feat/dmint-v1-mint)¶
src/pyrxd/glyph/dmint.py—build_dmint_v1_contract_script,build_dmint_v1_state_script,build_dmint_v1_code_script,is_token_bearing_script,find_dmint_funding_utxo. All reused as-is by M2.docs/dmint-research-mainnet.md§2–§5 — original V1 contract decode.docs/dmint-research-photonic.md— original Photonic source citations from M1.docs/solutions/logic-errors/dmint-v1-mint-shape-mismatch.md— institutional lesson #1.docs/solutions/logic-errors/funding-utxo-byte-scan-dos.md— institutional lesson #2 (opcode-aware classification).
11. Phase 2a exit checklist¶
Per plan §2.5, Phase 2a is complete when ALL six items below are true:
[x] On-chain V1 deploy located, fetched, and decoded byte-by-byte.
[x] Photonic source for
createCommitOutputs+createRevealOutputs+dMintScriptread in full and key divergences documented.[x] Auth NFT strategy decided (mint-fresh; forward-prior is deferred).
[x] Premine + delegate-ref decisions documented (both deferred).
[x] Acceptance-test inputs derived (golden synthetic vector parameters identified).
[x] Open questions logged with decisions or “deferred” tags.
Phase 2a deliverable: this document. Ready to start Phase 2b.