Commit graph

275 commits

Author SHA1 Message Date
Hossein Zoda
0eb86131f4 ido: keep offeredTokenTotalSupply in Active parameters
IdoActiveParameters dropped offeredTokenTotalSupply, so clients couldn't compute the offered-vs-total-supply share for live (non-PREINIT) IDOs. Carry it forward from the preinit parameters at the PreInit->Active transition and add it to the struct. A serde default of -1 (the pre-existing-token "unknown supply" sentinel) lets ido_state rows written before this field existed still deserialize.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 01:01:55 +03:00
Hossein Zoda
a73dff52df update offering initial output 2026-07-17 03:40:30 +03:00
Hossein Zoda
da26864cba update ipfs rebuild contract 2026-07-16 21:23:47 +03:00
Hossein Zoda
c1952142de ido: categories in display/UI byte order, drop hardcoded PLP limits
libriften moved encodeVmTokenCategory/decodeVmTokenCategory (which reverse
the 32 category bytes, display<->VM) into the ido announcement and ORB
IdoParams serialize/deserialize layer. Net wire effects the indexer sees:
- preinit announcement delphiCategory[44..76] and xTokenCategory[126..158]
  are now VM/little-endian (were display order);
- the IdoParams commitment stays VM on-wire, but the derived on-chain
  postlaunch orbPoolParamsCategory push flips display->VM (decode now
  returns display, the unchanged bake re-wraps it in encodeVmTokenCategory).

Keep the three categories (delphiCategory, xTokenCategory,
orbPoolParamsCategory) in display/UI byte order in-memory and over RPC:
reverse at every parse site (announcement + IdoParams NFT commitment) and
restore the .rev() on the output#0 delphi-NFT to_blob() compare. The
build_*_bytecode helpers keep reversing display->VM when baking, so the
output#7 P2SH32 rebuild matches the new on-chain layout.

Also drop the now-unused hardcoded MAX_PLP_SHARE / MAX_PLP_ANNUAL_DISCOUNT
/ MIN_PLP_ANNUAL_DISCOUNT statics and dead checks; the min-PLP limits are
NFT-pinned (minPlpShare / minPlpAfterDiscount) and the discount/max-discount
checks now just guard against negatives.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 21:44:18 +00:00
Hossein Zoda
4677cc955e ido: port "CldIdo00" signature + announcement permanentLiquidityMinFee
Sync the IDO indexer to libriften 48aa1f7 (+ follow-ups):

- IDO_SIGNATURE 20->10 bytes: [0x08 "CldIdo00" 0x75] (was OP_PUSH18
  "CauldronIdo-2026Q2"). The separate "CauldronIdo0" announcement
  signature is folded into the same 8 raw bytes, so
  IDO_PREINIT_ANNOUNCEMENT_SIGNATURE = 6a 4c b9 + "CldIdo00";
  is_preinit_broadcast is now length-agnostic. Electrum mempool
  filters track automatically (they reference the constants).
- Recompile the 3 affected contracts from templates: IDO initiator
  233->231, IDO preinit 1469->1465, offering launcher 630->628.
  IDO_POSTLAUNCH_CONTRACT and the other offering contracts are
  byte-identical and left as-is.
- Announcement OP_RETURN carries permanentLiquidityMinFee as a 2-byte
  field at data[166..168]; mainData is now 185 bytes. Read minFee from
  the announcement rather than the (unreadable) postlaunch copy.

Fix the source of the two "free" postlaunch params:

- Output #7 (ido initiator bytecode storage) is P2SH32, so the partial
  bytecode cannot be read back from it. Drop the impossible extraction
  (extract_params_from_partial_ido_initiator_bytecode +
  PartialPostlaunchExtractedParams). extract_data_from_storage_script_
  with_data_and_size is kept for its valid callers (revealed redeem
  scripts, bare bcmr storages).
- orbPoolParamsCategory now comes from the ORB IdoParams NFT commitment
  (output #10). The commitment parse is moved above the params
  construction so the value is available; the now-tautological
  orbPoolParamsCategory vs NFT check is removed.
- Verification is the existing output #7 rebuild: build the expected
  bytecode from the announcement values plus the NFT-sourced
  orbPoolParamsCategory, hash to P2SH32, and compare. Since minFee is a
  2-byte announcement field it always fits the postlaunch's 2-byte push,
  so build_partial_postlaunch_bytecode stays infallible.

- Tests: preinit_detect -> legacy_preinit_announcement_not_detected
  (legacy fixture must no longer be detected under the new signature);
  replace the extraction round-trip test with a structural check of the
  partial postlaunch bytecode layout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:32:20 +00:00
Hossein Zoda
c8450e210b ido: sync IdoParams commitment to 127-byte layout, enforce NFT-pinned min PLP
libriften 0941c88 grew the ORB IdoParams NFT commitment 121->127 bytes,
inserting minPlpAfterDiscount/minPlpShare (4-byte pIntLE numerators over
PERMANENT_LIQUIDITY_SHARE_DENOMINATOR) between maxExpireDuration and
entryExecutionFee, and shrinking paramsUseFee 4->2 bytes.

- Parse the two new fields; shift entryExecutionFee/createExecutionFee offsets.
- Drop the hardcoded MIN_PLP_SHARE / MIN_PLP_AFTER_DISCOUNT statics; enforce
  both minimums from the NFT commitment inside the version-verified block
  (permanentLiquidityShareNumerator >= minPlpShare, and
  maxDiscountRateNumerator + minPlpAfterDiscount <= permanentLiquidityShareNumerator).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 11:22:41 +00:00
Hossein Zoda
ca7f829591 ido: resync postlaunch contract & enforce IdoParams NFT version
- update IDO_POSTLAUNCH_CONTRACT to the recompiled 1627-byte script
  (libriften cd58dd1): postlaunch.cash reordered the permanent-pool
  sibling config, moving the all-zero nftOwner to the end. The indexer
  byte-compares this body against on-chain output#7, so the stale
  1669-byte constant would have marked every new IDO invalid.
- set CHIPNET_IDO_PARAMS_NFT_CATEGORY (was an all-zero placeholder).
- validate the ORB IdoParams NFT commitment version byte: only index
  when it equals IDO_PARAMS_VERSION (0x00), else push an
  "incompatible with the indexer" reason and mark the IDO invalid.
  The other commitment fields are read at v0 offsets, so the parameter
  comparisons are skipped on a version mismatch to avoid spurious errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 01:51:56 +00:00
Hossein Zoda
c3f3c269e2 bcmr: index new registrations from mempool, no confirmation needed
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>
2026-07-06 08:59:46 +00:00
Hossein Zoda
2bcf35172c ido: postlaunch collect/run lifecycle + bare-p2s locks, no backward compatibility
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>
2026-07-05 20:19:43 +00:00
Hossein Zoda
a5f4ce40d4 ido: port to ORB IdoParams generation, no backward compatibility
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>
2026-07-04 07:32:37 +00:00
Hossein Zoda
1ddab462aa ido minor fixes 2026-06-26 10:52:40 +03:00
Hossein Zoda
d363c2c930 ido followup update, offering contract updated & set ido create exe fee to 10m sats 2026-06-25 17:20:31 +03:00
jakobsn
4a23ce70d4 Merge branch 'authChain' into 'master'
Expose authchain head + optional local IPFS gateway for BCMR downloads

See merge request riftenlabs/riftenlabs-indexer!91
2026-06-24 11:07:31 +00:00
jakobsn
3c5af42b4b Expose authchain head + optional local IPFS gateway for BCMR downloads 2026-06-24 11:07:31 +00:00
jakobsn
69d443d13f Merge branch 'graph-price-inconsistency' into 'master'
Use last trade as the basis for the price outside chart instead of the last token/sats amount

See merge request riftenlabs/riftenlabs-indexer!86
2026-06-23 14:16:20 +00:00
jakobsn
b36c0b71a6 Use last trade as the basis for the price outside chart instead of the last token/sats amount 2026-06-23 14:16:19 +00:00
Dagur Valberg Johannsson
d5fa393870 Merge branch 'ido' into 'master'
ido

See merge request riftenlabs/riftenlabs-indexer!81
2026-06-23 13:08:55 +00:00
Hossein Zoda
b88475a75b ido: record EntryDistributed per distribution tx with the entry's txid
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>
2026-06-23 12:57:31 +00:00
Hossein Zoda
f9ee877392 format 2026-06-23 02:38:25 +03:00
Hossein Zoda
0831834d8f ido: replace txchain model with unified state-chain indexing
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>
2026-06-22 19:46:23 +00:00
Hossein Zoda
e2f72e608e format 2026-06-22 10:48:08 +00:00
Hossein Zoda
c7a9e9bea6 ido: replace num-bigint with malachite
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>
2026-06-22 10:41:39 +00:00
Hossein Zoda
5f49ad75c0 format ido 2026-06-21 01:44:39 +03:00
Hossein Zoda
0aa4d1c530 add copyright to db/ido/mod.rs 2026-06-21 01:44:39 +03:00
Hossein Zoda
62b8fb6436 ido: only update block_height when tx is already in the txchain
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
9b0a54c926 ido: maintain entry aggregates in active state
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
b8468a1256 ido: record created_at and launched_at timestamps
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
d5bdf5a740 ido: filter list_ido_entries by owner_nfthash
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
aec0a6f0f8 ido: add /<id>/aggregates endpoint for entry totals
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
a410aee95f ido: migrate to bitcoincash 0.32 script API; fix mempool diff
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
edf7955a23 rebase fix 2026-06-21 01:44:39 +03:00
Hossein Zoda
856b374a6d ido improvements & fixes (WIP) 2026-06-21 01:44:39 +03:00
Hossein Zoda
b1df63c6c4 ido: garbage collect tracker entries of mempool txs that never confirm
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
7f46b1b4b7 ido: index unconfirmed txs from the mempool
- 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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
e14fbd4f1e ido more fixes 2026-06-21 01:44:39 +03:00
Hossein Zoda
874e9f0231 set mock platform fee nfthash 2026-06-21 01:44:39 +03:00
Hossein Zoda
366823cf02 ido: validate delphi nft in preinit first output; announcement moves to last
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
b56ce5bc63 ido: key txchain tx lookup by txid; gate debug endpoints behind config
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
e86de7d5f5 ido: hide txchain_entrypoint, expose txchain_head as head txid
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
6728753db0 ido: use preinit_txid hex as public id (rename internal id)
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>
2026-06-21 01:44:39 +03:00
Hossein Zoda
210a51f274 ido bcmr ser/deser fixes 2026-06-21 01:44:39 +03:00
Hossein Zoda
c4eaad4cec ido more fixes +two unittests 2026-06-21 01:44:39 +03:00
Hossein Zoda
a944db4702 ido better error reporting 2026-06-21 01:44:39 +03:00
Hossein Zoda
f8ddac6ec3 followup update for ido -> adding ipfs bcmr placeholder 2026-06-21 01:44:39 +03:00
Hossein Zoda
335818460f followup changes to ido contracts 2026-06-21 01:44:39 +03:00
Hossein Zoda
3f8a9cd026 ido more fixes 2026-06-21 01:44:39 +03:00
Hossein Zoda
aa99f775da tiny fix 2026-06-21 01:44:39 +03:00
Hossein Zoda
988426e485 ido, compiles, with claude generated unittests 2026-06-21 01:44:39 +03:00
Hossein Zoda
0629e168c3 ido incomplete c02 2026-06-21 01:44:39 +03:00
Hossein Zoda
ce9dba23cf (WIP) ido 2026-06-21 01:44:39 +03:00