Class: Solrengine::Sdp::TokenMint

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/solrengine/sdp/token_mint.rb

Overview

Engine-owned record of every mint attempted through SDP — the audit trail and the never-double-mint guard.

Status machine:

minting   → just recorded, not yet sent (created before the POST)
in_flight → claimed by MintJob; the POST is being sent (atomic claim
            so a crash + queue-retry never re-sends the same mint)
minted    → confirmed on-chain (terminal)
failed    → SDP rejected it, or it was never sent (terminal)
unknown   → the POST read-timed out: outcome uncertain. NEVER re-sent
            (double-mint risk), and SDP exposes no mint-transaction
            listing to reconcile against — surfaced for manual review.

The mint POST is NEVER retried (SDP has no idempotency key). Unlike a Transfer there is no memo-token reconcile path (no list endpoint for mint transactions), so a timed-out mint stays ‘unknown` rather than auto-resolving.

Constant Summary collapse

MEMO_TOKEN_PREFIX =
"sdpmint-"
MEMO_SEPARATOR =
" | "
STATUSES =
%w[minting in_flight minted failed unknown].freeze
TERMINAL_STATUSES =
%w[minted failed unknown].freeze

Instance Method Summary collapse

Instance Method Details

#claim!Object

Atomic claim: minting → in_flight in one UPDATE. Returns true only for the caller that won the claim, so a crash + queue-retry (or two workers) can never send the same mint twice. A row stuck in_flight is a crashed-mid-send and is left for manual reconcile, never auto-re-sent.



48
49
50
51
52
# File 'app/models/solrengine/sdp/token_mint.rb', line 48

def claim!
  won = self.class.where(id: id, status: "minting").update_all(status: "in_flight", updated_at: Time.current)
  reload if won == 1
  won == 1
end

#composed_memoObject



81
82
83
# File 'app/models/solrengine/sdp/token_mint.rb', line 81

def composed_memo
  [ memo, memo_token ].compact.join(MEMO_SEPARATOR)
end

#pending?Boolean

Returns:

  • (Boolean)


40
41
42
# File 'app/models/solrengine/sdp/token_mint.rb', line 40

def pending?
  %w[minting in_flight].include?(status)
end

#submit_to_sdp!Object

The single, never-retried mint POST. Every outcome lands on the row.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'app/models/solrengine/sdp/token_mint.rb', line 55

def submit_to_sdp!
  tx = Solrengine::Sdp.client.mint_token(
    token.sdp_token_id,
    signing_wallet_id: token.signing_wallet_id,
    destination: destination,
    amount: amount,
    memo: composed_memo
  )
  update!(
    status: terminal_for(tx.status),
    signature: tx.signature,
    sdp_transaction_id: tx.id,
    token_account: tx.,
    sdp_error: tx.error,
    settled_at: Time.current
  )
rescue ::Sdp::Timeout
  # Outcome unknown — NEVER re-send. No mint-tx listing to reconcile.
  update!(status: "unknown")
rescue ::Sdp::Unavailable => e
  # Request never processed — safe to mark failed (no money moved).
  update!(status: "failed", sdp_error: "unsent: #{e.message}", settled_at: Time.current)
rescue ::Sdp::Error => e
  update!(status: "failed", sdp_error: e.message, settled_at: Time.current)
end