Module: Solrengine::Sdp
- Defined in:
- lib/solrengine/sdp.rb,
lib/solrengine/sdp/engine.rb,
lib/solrengine/sdp/errors.rb,
lib/solrengine/sdp/faucet.rb,
lib/solrengine/sdp/version.rb,
lib/solrengine/sdp/broadcaster.rb,
lib/solrengine/sdp/wallet_owner.rb,
lib/solrengine/sdp/configuration.rb,
app/models/solrengine/sdp/transfer.rb,
app/jobs/solrengine/sdp/track_transfer_job.rb,
app/jobs/solrengine/sdp/provision_wallet_job.rb,
lib/generators/solrengine/sdp/install_generator.rb
Overview
Rails engine for custodial Solana wallets backed by the Solana Developer Platform (SDP). Composes the solana-sdp client with the solrengine family.
Defined Under Namespace
Modules: WalletOwner Classes: Broadcaster, Configuration, ConfigurationError, Engine, Error, Faucet, InstallGenerator, InsufficientBalance, ProvisionWalletJob, TrackTransferJob, Transfer
Constant Summary collapse
- EXEMPT_TASK_PREFIXES =
Rake task prefixes for which the boot-time api_key check is skipped: CI and Docker image builds run these without production secrets.
%w[assets: db: app: tmp: log:].freeze
- REALTIME_SUBSCRIBER_NAME =
Name this engine registers under on the solrengine-realtime subscriber registry (start_realtime!/stop_realtime!). Apps can register their own subscribers alongside it under their own names.
:solrengine_sdp- VERSION =
"0.1.0"- COMPATIBLE_SDP_VERSION =
The SDP release this engine version is tested against. SDP breaks its API between minors; bump this (and re-verify) on every SDP upgrade.
"0.28"
Class Method Summary collapse
-
.client ⇒ Object
Memoized SDP API client built from the configuration.
- .configuration ⇒ Object
- .configure {|configuration| ... } ⇒ Object
-
.exempt_context?(task_names) ⇒ Boolean
Pure function over rake task names so the exemption logic is unit-testable: exempt_context?() => true.
-
.exempt_rake_context? ⇒ Boolean
True when the current process is an exempt rake task (boot check skip).
-
.price_for(mint) ⇒ Object
USD price for a mint via the optional tokens gem.
-
.price_source_available? ⇒ Boolean
solrengine-tokens is an optional price source — never a hard dependency.
- .reset_configuration! ⇒ Object
-
.start_realtime! ⇒ Object
Registers the engine’s Broadcaster on the solrengine-realtime subscriber registry: every account-change dispatch re-fetches and broadcasts for that wallet.
- .stop_realtime! ⇒ Object
-
.usd_value_for(balance) ⇒ Object
USD value for an Sdp::Balance (AE3): SDP’s own usd_value when present (v0.29+ populates it), else derived from the optional tokens gem’s Jupiter price, else nil.
Class Method Details
.client ⇒ Object
Memoized SDP API client built from the configuration. Reset whenever ‘configure` runs, so reconfiguring always yields a fresh client.
41 42 43 44 45 46 |
# File 'lib/solrengine/sdp.rb', line 41 def client @client ||= ::Sdp::Client.new( api_key: configuration.validate!.api_key, base_url: configuration.base_url ) end |
.configuration ⇒ Object
29 30 31 |
# File 'lib/solrengine/sdp.rb', line 29 def configuration @configuration ||= Configuration.new end |
.configure {|configuration| ... } ⇒ Object
33 34 35 36 37 |
# File 'lib/solrengine/sdp.rb', line 33 def configure yield(configuration) @client = nil configuration end |
.exempt_context?(task_names) ⇒ Boolean
Pure function over rake task names so the exemption logic is unit-testable: exempt_context?() => true.
55 56 57 58 59 |
# File 'lib/solrengine/sdp.rb', line 55 def exempt_context?(task_names) Array(task_names).any? do |task| EXEMPT_TASK_PREFIXES.any? { |prefix| task.to_s.start_with?(prefix) } end end |
.exempt_rake_context? ⇒ Boolean
True when the current process is an exempt rake task (boot check skip).
62 63 64 65 66 67 68 69 |
# File 'lib/solrengine/sdp.rb', line 62 def exempt_rake_context? return false unless defined?(Rake) && Rake.respond_to?(:application) application = Rake.application return false unless application.respond_to?(:top_level_tasks) exempt_context?(application.top_level_tasks) end |
.price_for(mint) ⇒ Object
USD price for a mint via the optional tokens gem. Returns nil when the gem is absent or the price lookup fails — price must never gate money flows (the U9 broadcaster builds on this).
88 89 90 91 92 93 94 |
# File 'lib/solrengine/sdp.rb', line 88 def price_for(mint) return nil unless price_source_available? Solrengine::Tokens::JupiterClient.fetch_prices([ mint ])[mint] rescue StandardError nil end |
.price_source_available? ⇒ Boolean
solrengine-tokens is an optional price source — never a hard dependency. True when its JupiterClient is loadable.
73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/solrengine/sdp.rb', line 73 def price_source_available? return true if defined?(Solrengine::Tokens::JupiterClient) begin require "solrengine/tokens" rescue LoadError return false end defined?(Solrengine::Tokens::JupiterClient) ? true : false end |
.reset_configuration! ⇒ Object
48 49 50 51 |
# File 'lib/solrengine/sdp.rb', line 48 def reset_configuration! @configuration = nil @client = nil end |
.start_realtime! ⇒ Object
Registers the engine’s Broadcaster on the solrengine-realtime subscriber registry: every account-change dispatch re-fetches and broadcasts for that wallet. Called by the watcher process (bin/sdp_watcher); idempotent — re-subscribing replaces the block.
117 118 119 120 121 |
# File 'lib/solrengine/sdp.rb', line 117 def start_realtime! Solrengine::Realtime.subscribe(REALTIME_SUBSCRIBER_NAME) do |wallet_address| Broadcaster.call(wallet_address) end end |
.stop_realtime! ⇒ Object
123 124 125 |
# File 'lib/solrengine/sdp.rb', line 123 def stop_realtime! Solrengine::Realtime.unsubscribe(REALTIME_SUBSCRIBER_NAME) end |
.usd_value_for(balance) ⇒ Object
USD value for an Sdp::Balance (AE3): SDP’s own usd_value when present (v0.29+ populates it), else derived from the optional tokens gem’s Jupiter price, else nil. Price data is decorative — every failure path degrades to nil so a price hiccup can NEVER fail a broadcaster fetch or gate a money-movement broadcast.
101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/solrengine/sdp.rb', line 101 def usd_value_for(balance) usd = balance.usd_value return usd unless usd.nil? || usd.to_s.empty? price = price_for(balance.mint) return nil unless price BigDecimal(balance.ui_amount.to_s) * BigDecimal(price.to_s) rescue StandardError nil end |