solrengine-sdp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "solana-sdp"
5
+ require "solrengine/realtime"
6
+
7
+ require_relative "sdp/version"
8
+ require_relative "sdp/errors"
9
+ require_relative "sdp/configuration"
10
+ require_relative "sdp/wallet_owner"
11
+ require_relative "sdp/broadcaster"
12
+ require_relative "sdp/faucet"
13
+ require_relative "sdp/engine" if defined?(Rails::Engine)
14
+
15
+ module Solrengine
16
+ # Rails engine for custodial Solana wallets backed by the Solana Developer
17
+ # Platform (SDP). Composes the solana-sdp client with the solrengine family.
18
+ module Sdp
19
+ # Rake task prefixes for which the boot-time api_key check is skipped:
20
+ # CI and Docker image builds run these without production secrets.
21
+ EXEMPT_TASK_PREFIXES = %w[assets: db: app: tmp: log:].freeze
22
+
23
+ # Name this engine registers under on the solrengine-realtime subscriber
24
+ # registry (start_realtime!/stop_realtime!). Apps can register their own
25
+ # subscribers alongside it under their own names.
26
+ REALTIME_SUBSCRIBER_NAME = :solrengine_sdp
27
+
28
+ class << self
29
+ def configuration
30
+ @configuration ||= Configuration.new
31
+ end
32
+
33
+ def configure
34
+ yield(configuration)
35
+ @client = nil
36
+ configuration
37
+ end
38
+
39
+ # Memoized SDP API client built from the configuration. Reset whenever
40
+ # `configure` runs, so reconfiguring always yields a fresh client.
41
+ def client
42
+ @client ||= ::Sdp::Client.new(
43
+ api_key: configuration.validate!.api_key,
44
+ base_url: configuration.base_url
45
+ )
46
+ end
47
+
48
+ def reset_configuration!
49
+ @configuration = nil
50
+ @client = nil
51
+ end
52
+
53
+ # Pure function over rake task names so the exemption logic is
54
+ # unit-testable: exempt_context?(["assets:precompile"]) => true.
55
+ def exempt_context?(task_names)
56
+ Array(task_names).any? do |task|
57
+ EXEMPT_TASK_PREFIXES.any? { |prefix| task.to_s.start_with?(prefix) }
58
+ end
59
+ end
60
+
61
+ # True when the current process is an exempt rake task (boot check skip).
62
+ def exempt_rake_context?
63
+ return false unless defined?(Rake) && Rake.respond_to?(:application)
64
+
65
+ application = Rake.application
66
+ return false unless application.respond_to?(:top_level_tasks)
67
+
68
+ exempt_context?(application.top_level_tasks)
69
+ end
70
+
71
+ # solrengine-tokens is an optional price source — never a hard
72
+ # dependency. True when its JupiterClient is loadable.
73
+ def price_source_available?
74
+ return true if defined?(Solrengine::Tokens::JupiterClient)
75
+
76
+ begin
77
+ require "solrengine/tokens"
78
+ rescue LoadError
79
+ return false
80
+ end
81
+
82
+ defined?(Solrengine::Tokens::JupiterClient) ? true : false
83
+ end
84
+
85
+ # USD price for a mint via the optional tokens gem. Returns nil when the
86
+ # gem is absent or the price lookup fails — price must never gate money
87
+ # flows (the U9 broadcaster builds on this).
88
+ def price_for(mint)
89
+ return nil unless price_source_available?
90
+
91
+ Solrengine::Tokens::JupiterClient.fetch_prices([ mint ])[mint]
92
+ rescue StandardError
93
+ nil
94
+ end
95
+
96
+ # USD value for an Sdp::Balance (AE3): SDP's own usd_value when present
97
+ # (v0.29+ populates it), else derived from the optional tokens gem's
98
+ # Jupiter price, else nil. Price data is decorative — every failure
99
+ # path degrades to nil so a price hiccup can NEVER fail a broadcaster
100
+ # fetch or gate a money-movement broadcast.
101
+ def usd_value_for(balance)
102
+ usd = balance.usd_value
103
+ return usd unless usd.nil? || usd.to_s.empty?
104
+
105
+ price = price_for(balance.mint)
106
+ return nil unless price
107
+
108
+ BigDecimal(balance.ui_amount.to_s) * BigDecimal(price.to_s)
109
+ rescue StandardError
110
+ nil
111
+ end
112
+
113
+ # Registers the engine's Broadcaster on the solrengine-realtime
114
+ # subscriber registry: every account-change dispatch re-fetches and
115
+ # broadcasts for that wallet. Called by the watcher process
116
+ # (bin/sdp_watcher); idempotent — re-subscribing replaces the block.
117
+ def start_realtime!
118
+ Solrengine::Realtime.subscribe(REALTIME_SUBSCRIBER_NAME) do |wallet_address|
119
+ Broadcaster.call(wallet_address)
120
+ end
121
+ end
122
+
123
+ def stop_realtime!
124
+ Solrengine::Realtime.unsubscribe(REALTIME_SUBSCRIBER_NAME)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "solrengine/sdp"
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solrengine-sdp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jose Ferrer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '7.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: solana-sdp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: solrengine-realtime
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.2'
55
+ description: 'Rails engine for SDP-backed apps: Wallet-per-User provisioning, transfer
56
+ persistence and tracking, and real-time balance broadcasts built on the solrengine
57
+ family.'
58
+ email:
59
+ - estoy@moviendo.me
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - LICENSE
65
+ - README.md
66
+ - app/jobs/solrengine/sdp/provision_wallet_job.rb
67
+ - app/jobs/solrengine/sdp/track_transfer_job.rb
68
+ - app/models/solrengine/sdp/transfer.rb
69
+ - lib/generators/solrengine/sdp/install_generator.rb
70
+ - lib/generators/solrengine/sdp/templates/add_solrengine_sdp_to_users.rb
71
+ - lib/generators/solrengine/sdp/templates/cable.yml
72
+ - lib/generators/solrengine/sdp/templates/create_solrengine_sdp_transfers.rb
73
+ - lib/generators/solrengine/sdp/templates/initializer.rb
74
+ - lib/generators/solrengine/sdp/templates/sdp_watcher
75
+ - lib/solrengine-sdp.rb
76
+ - lib/solrengine/sdp.rb
77
+ - lib/solrengine/sdp/broadcaster.rb
78
+ - lib/solrengine/sdp/configuration.rb
79
+ - lib/solrengine/sdp/engine.rb
80
+ - lib/solrengine/sdp/errors.rb
81
+ - lib/solrengine/sdp/faucet.rb
82
+ - lib/solrengine/sdp/version.rb
83
+ - lib/solrengine/sdp/wallet_owner.rb
84
+ homepage: https://github.com/solrengine/sdp
85
+ licenses:
86
+ - MIT
87
+ metadata:
88
+ homepage_uri: https://github.com/solrengine/sdp
89
+ source_code_uri: https://github.com/solrengine/sdp
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 3.2.0
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubygems_version: 3.5.22
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Custodial Solana wallets for Rails via the Solana Developer Platform
109
+ test_files: []