Add an OP_RETURN "BCMR" prefix filter to the rostrum mempool.get pass and
index matching txs in update_mempool with the all-zeros sentinel blockhash
(same pattern as oracle). A newly registered BCMR becomes the auth head and
is downloaded immediately; the confirming block re-stamps the entry with
its real blockhash in place.
- insert_authheader: INSERT OR REPLACE -> upsert. REPLACE deletes the row,
cascading away downloaded bcmr_data on every mempool->confirmed upgrade.
- update_mempool drops sentinel entries whose tx left the mempool (evicted
or replaced), so stale auth heads never linger.
- clear bcmr mempool state at startup; always-run migration adds txid and
blockhash indexes on auth_chain_entry for the per-pass lookups.
Auth chain transfers without a BCMR output still index at confirmation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sync with libriften ido+ttd head (37a5c01):
- postlaunch rework: collect copies the offering confirmation NFT through
io#4 (the chain continues from the verified copy at output#4, state
unchanged); run consumes it at input#5. The called method is dispatched
from the carrier's unlocking bytecode (<args..> <functionIndex> <redeem>);
run's altPPOut argument is decoded as a VM number — when true the pool
legs were paid back to the collector (pool-deploy-failure fallback,
recorded as altPPOutPayout) instead of deploying the permanent pool. The
accumulated BCH pot paid to the platform p2nfth at output#5 is recorded
as platformBchPayout. Chain-follow probe list extended to [0,1,3,4,5].
- postlaunch constructor gains a 4-byte executionFee push (partial
postlaunch bytecode is now 8 pushes + body).
- p2nfth and plain storages lock as bare-p2s (blob storages stay p2sh32);
nfthash preimage flipped to hash256(commitment + category);
P2NFTH contract is 78cf7bce7eaa87.
- all changed contract constants regenerated from the libriften templates
(initiator 233 B, postlaunch 1669 B, preinit 1469 B).
- fix IdoActiveParameters construction missing orbPoolParamsCategory and
permanentLiquidityMinFee; box IdoUpdate::State to keep the enum small.
- ido db version 3; no migration — delete ido.db and re-index.
- legacy-generation fixture tests marked #[ignore].
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Preinit txs must now spend an ORB IdoParams NFT (use() at input #1,
preserved at output #10) whose per-network category is pinned and whose
121-byte commitment is cross-checked field-by-field against the
announced parameters; xToken must be a non-native token. ido.db is
version-gated (PRAGMA user_version = 2); legacy IDOs do not parse.
Also refresh the embedded IDOPostLaunch contract to the current
tokentoken-delegation build (1616 bytes, libriften ido+ttd a9fcfa0);
the previous copy predated the recompile and would have failed the
preinit output #7 byte-compare. All other embedded contracts verified
byte-identical to the libriften templates.
Per-network IdoParams NFT categories are still all-zero placeholders;
until set, every preinit indexes as is_valid=false.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The EntryDistributed update was pushed in the POSTLAUNCH->DISTRIBUTED
branch using the collection tx's own txid. That branch fires once at
final collection rather than per distribution tx, and tx.compute_txid()
never equals an entry's creation txid, so the dist_expr join
(d.entry_txid = e.txid) never matched and entries were never marked
distributed.
Push it in the DISTRIBUTING handler instead, once per distribution tx,
using input#1.previous_output.txid (the entry NFT being spent), which is
the entry's creation txid recorded by IdoUpdate::Entry.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace index_block/index_mempool with a single index_txs that takes an
Option<blockhash> (Some for confirmed, None for mempool). Add
delete_entries(blockhash) for reorg undo and to drop stale mempool state
before applying confirmed blocks. Replace has_txchain_tx with
has_indexed_tx; chain-follow now keys on ido_state.next_output_index
instead of the removed tracker map.
Remove the debug-only txchain RPC endpoints and the debug config gating.
Keep txchain_head as a public RPC field.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate the ido module's arbitrary-precision math from num-bigint to
malachite (already a workspace dependency). BigInt becomes
malachite::Integer throughout; the VM-number byte codec uses
PowerOf2Digits, sign handling uses Integer::sign(), and primitive
conversions use try_from.
Add an IntegerAsStr serde adapter for string-serialized fields, since
malachite's FromStr::Err is () and does not satisfy DisplayFromStr's
Display bound. JSON output is unchanged.
Drop the now-unused num-bigint and num-traits dependencies.
Also fix all clippy warnings in the module surfaced by the migration
(unwrap-after-is_none control flow, a const->static LazyLock bug,
an oversized enum variant boxed, and assorted mechanical lints).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
on_add_ido_tx rebuilt the whole chain whenever the input tx was not the
txchain head. A mempool tx confirming after the chain advanced past it
would needlessly trigger a full rebuild.
Reconstruct the current chain (txchain_head .. txchain_entrypoint) and,
if the tx is already part of it, only update its block height. Extract
the shared chain-walking logic into reconstruct_txchain, reused by both
the membership check and the rebuild branch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the per-request get_ido_entry_aggregates SQL scan with running
totals carried in IdoActiveState: totalDemandAmount, totalSupplyAmount,
and totalDiscount. Initialized to 0 at the preinit->active transition and
incremented on each entry added; the rebuild path recomputes them by
replaying the txchain, so they self-heal.
Drop the now-unused get_ido_entry_aggregates DB fn, the IdoEntryAggregatesRpc
type, the /<id>/aggregates RPC handler, and its route registration.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add two timestamp columns to the ido table, both sourced from Delphi NFT
commitments (48-bit LE unix seconds):
- created_at (NOT NULL, default 0): from the Delphi NFT in the preinit's
first output, set at IDO creation. 0 if the commitment is too short.
- launched_at (NULL): from the Delphi NFT in output#3 of the launch
transaction, set in lockstep with launch_txid. Null until launched.
Both are threaded through the parse/context/update paths and exposed on
IdoRpcRecord.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an optional owner_nfthash query param to GET /<id>/entries. Accepts
up to 20 comma-delimited 32-byte hex hashes; an entry matches any listed
value via an owner_nfthash IN (...) clause. Rejects malformed hex,
wrong-length values, and >20 filters with a 400.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sum demand/supply amounts and count entries for an IDO, used to show
"raised so far" for active offerings where on-chain state keeps no
running total.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update ido/mod.rs for the bitcoincash 0.32 API: Script -> ScriptBuf,
push_slice via &PushBytes (new pb() helper), as_byte_array/as_bytes.
Fix update_mempool to diff against cauldron_txs instead of defi_txs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stamp mempool tracker entries with the negative of the highest known
block height instead of a fixed -1 sentinel, and trim on abs(height) so
entries whose tx is invalidated before confirming (e.g. by a double
spend) age out after TRACKER_MAX_BLOCK_DEPTH like confirmed ones. The
height is still replaced with the real one once the tx confirms.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- electrum mempool fetch gains an ido filter: state machine spends
(IDO_SIGNATURE in scriptsig) union preinit announcements
(IDO_PREINIT_ANNOUNCEMENT_SIGNATURE in scriptpubkey)
- split tx scanning out of index_block into index_txs and add
index_mempool, which indexes with a -1 sentinel height;
txchain_trim_tracker leaves negative heights alone and the real
height replaces the sentinel once the tx confirms in a block
- block indexing now skips re-creating an ido already seen in the
mempool, only updating its tracker height
- mempool txs are kahn-sorted so txchain parents index before children
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The preinit tx layout changed: the first output is now the Delphi NFT and
the announcement OP_RETURN is the last output. Read the announcement from the
last output in both is_preinit_broadcast and parse_ido_preinit_tx_params.
Add validity checks on the first output's Delphi NFT: its category must match
the announcement's delphiCategory, and the 48-bit commitment timestamp (current
time) must place launchConditions.expiresAt within a 1-30 day window.
The two PREINIT_TEST_TX vectors use the old layout, so the three preinit parse
tests are marked #[ignore] pending new-format sample transactions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change get_txchain_tx to take the public txid (a unique field) instead of
the non-public internal txchain item id, and promote it to a production
endpoint. Mount the two remaining debug endpoints (list_ido_txchain,
list_txchain_tracker_map) only when `debug = true` in the config.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The IDO RPC record no longer leaks internal txchain row ids. Drop the
txchain_entrypoint field entirely, and change txchain_head from the
internal ido_txchain.id to the head record's txid (display hex).
list_idos and get_ido_by_offering_token_id resolve this in a single
query via LEFT JOIN ido_txchain ON head_tx.id = ido.txchain_head; a
NULL head yields null. Adds tests for both the resolved and null cases.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rename ido.id -> ido.internal_id in the schema and IdoDBRecord, and
expose the preinit_txid hex as the public "id" in all RPC responses.
Public API shape:
- IdoRpcRecord.id: i64 -> String (hex of preinit_txid). preinit_txid
field is preserved unchanged.
- IdoEntryRpcRecord.ido_id: i64 -> String (hex of parent preinit_txid).
- IdoTxChainRpcRecord.ido_id: i64 -> String (hex of parent preinit_txid).
- IdoTxChainRpcRecord gains ido_internal_id: i64 (debug endpoint only).
- Routes /<id>/entries and /<id>/txchain accept the preinit_txid hex
as the path id; returns 404 IDO_NOT_FOUND on miss.
Internals:
- New lookup_internal_id_by_preinit_txid helper.
- list_ido_entries / list_ido_txchain take preinit_txid_hex as input
so the caller (which already parsed it from the path) avoids the
extra "preinit_txid by internal_id" lookup.
- Child table FK columns (ido_entry.ido_id, ido_txchain.ido_id) keep
their names; only the parent PK and field accesses were renamed.
Notes:
- Breaking API change for /ido/* endpoints. Clients reading "id" or
"ido_id" as integers must switch to strings.
- ido.db has no migration framework: drop the file and re-index on
deploy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
List every active TokenToken pool (no pair filter) so the frontend can
present the set of pooled token pairs without probing each candidate pair.
Mirrors db_active_pools_for_pair minus the pair WHERE clause; served at a
distinct /pools path (the param'd /pool/active already matches param-less
requests via its Option guards, so reusing it would collide).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes the indexer crash on chipnet: bitcoincash 0.32.1's
Opcode::classify panicked on BCH re-enabled opcodes (e.g. OP_SPLIT),
which riftenlabs-defi hit while parsing input scriptSigs in
parse_cauldrons_from_tx. bitcoincash 0.32.2 makes classify total and
panic-free (and adds the May 2026 upgrade opcodes); riftenlabs-defi
0.4.1 additionally hardens read_push_from_script to not classify
non-push opcodes at all.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Migrate off the deprecated bitcoincash 0.29 API (Amount/Version types,
FromHex -> FromStr/parse, non-exhaustive Network) across the indexer and
tests.
Add indexing of native token-A <-> token-B (TokenToken) AMM pools:
- tokentoken_pool / tokentoken_pool_history_entry tables in cauldron.db,
created via an always-run idempotent migration (no DB_VERSION bump, so
existing databases upgrade in place)
- block-path indexing sharing the cauldron write transaction and reorg
undo, with creation/swap/withdrawal state tracking and reserve deltas
- mempool indexing: electrum mempool.get filters on the tokentoken
contract code (spends) and the CONJURE op_return hint (creations);
first_seen_timestamp reconciles with mtp on confirmation
- RPC endpoints /tokentoken/pool/active (pair lookup, order-insensitive)
and /tokentoken/tokens
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>