Skip to content

Engine 0.3.0 — token issuance (Token + Mint/Burn jobs) + devnet fixes - #2

Merged
moviendome merged 4 commits into
mainfrom
feat/sdp-v0.3
Jun 26, 2026
Merged

moviendome merged 4 commits into
mainfrom
feat/sdp-v0.3

Conversation

@moviendome

@moviendome moviendome commented Jun 25, 2026 •

Copy link
Copy Markdown
Member

Engine 0.3.0 — adds token issuance on the custodial Wallet-per-User path, plus the fixes surfaced verifying it end-to-end on a live SDP devnet stack (the M3 Kudos reference app is the consumer).

What's in it

  • Issuance (M3-C/D): Solrengine::Sdp::Token — register! → deploy! → mint! / burn!, each persisted as an engine-owned audit row (TokenMint / TokenBurn). MintJob / BurnJob send a single never-retried POST; the atomic claim (minting → in_flight) guarantees a mint/burn is never sent twice. A read-timeout lands unknown (no mint-tx list to reconcile against), surfaced not auto-re-sent.
  • Clean decimal amounts: BigDecimal#to_s("F") rendered a whole 10 as "10.0", which SDP rejects for a 0-decimal token ("Amount has too many decimal places") — so every whole-number mint/burn failed on-chain. Now sent as "10"; fractions keep their places.
  • Doorbell on settle: app-initiated issuance is its own doorbell. The chain-WebSocket watcher only sees a wallet's native account, not the token ATA a mint credits, so it never rang for an earn — MintJob/BurnJob now ring the balance broadcast for the affected wallet on settle (every earn/redeem, including the first), reusing the app's broadcast_targets.
  • Docs: README gains an Issuance section; compatibility line corrected to match COMPATIBLE_SDP_VERSION (v0.31).

Verification

  • Full loop verified on devnet: signup → provision → create → deploy → earn/mint → redeem/burn → live balance.
  • 151 runs, 0 failures; rubocop clean; solrengine-sdp-0.3.0.gem builds; runtime deps (solana-sdp 0.2, solrengine-realtime 0.2) resolve from RubyGems.

The amount and doorbell bugs were invisible to the WebMock suite (stubs don't validate amounts or deliver chain events) — they only appeared against the real stack, which is exactly what this milestone's live verification is for.

The deferred-from-M2 issuance models, built against Kudos as the real consumer.

- Solrengine::Sdp::Token: register! (create_token) / deploy! / mint! — the
  persisted issued token (mirrors Transfer's audit-trail posture)
- Solrengine::Sdp::TokenMint: per-mint record; status machine
  minting -> in_flight -> minted | failed | unknown
- MintJob: single never-retried mint POST; atomic claim (minting -> in_flight)
  guarantees a mint is never sent twice across crashes/retries/concurrent
  workers. Timeout -> unknown (no mint-tx listing to reconcile; surfaced for
  manual review, never auto-re-sent). Unavailable -> failed unsent.
- Migration templates (tokens + token_mints) wired into the install generator;
  VERSION 0.2.0 -> 0.3.0

143 runs, 479 assertions, 0 failures. rubocop clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
moviendome and others added 3 commits June 25, 2026 16:35
The redeem-path counterpart to mint, same never-double-* discipline.

- Solrengine::Sdp::TokenBurn: per-burn record (burning -> in_flight ->
  burned | failed | unknown). A burn is signed by the SOURCE wallet's owner,
  so signing_wallet_id is the holder's custodial wallet, not the treasury.
- BurnJob: single never-retried burn POST + atomic claim (never sent twice)
- Token#burn!(source:, signing_wallet_id:, amount:, memo:)
- Migration template + install generator + test schema

147 runs, 493 assertions, 0 failures. rubocop clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two devnet-surfaced fixes the WebMock-stubbed tests structurally could not
catch (stubs don't validate amounts or deliver real chain events):

- Amount normalization: BigDecimal#to_s("F") renders a whole "10" as
  "10.0", which SDP rejects for a 0-decimal token ("Amount has too many
  decimal places") — so every mint/burn of a whole-number points token
  failed on-chain. Strip trailing fractional zeros so "10" goes out as "10"
  (fractions keep their places). SDP still enforces the token's decimals.

- App-initiated issuance is its own doorbell: the chain-WebSocket watcher
  only sees a wallet's native account, not the token ATA a mint credits, so
  it never rang for an earn. MintJob/BurnJob now ring the balance broadcast
  for the affected wallet on settle (every earn/redeem, including the first),
  reusing the app's configured broadcast_targets. Broadcast failure can never
  fail a settled write.

Regression tests for both; corrected the two tests that baked in "10.0".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0.3.0 adds token issuance; the README only covered transfers. Add an
Issuance section (Token.register!/deploy!/mint!/burn!, the mint/burn status
machine, decimal-amount semantics, never-double posture, and the
broadcast-on-settle doorbell). Correct the compatibility line to match the
COMPATIBLE_SDP_VERSION constant (v0.31), which had drifted to v0.28.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@moviendome moviendome changed the title Engine 0.3 — issuance Token model + MintJob (M3 Workstream C) Engine 0.3.0 — token issuance (Token + Mint/Burn jobs) + devnet fixes Jun 26, 2026
@moviendome
moviendome marked this pull request as ready for review June 26, 2026 05:21
@moviendome
moviendome merged commit 92a6298 into main Jun 26, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant