mpp-rb 0.1.4 → 0.1.6
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.
- checksums.yaml +4 -4
- data/README.md +128 -1
- data/lib/mpp/challenge.rb +31 -8
- data/lib/mpp/challenge_echo.rb +14 -3
- data/lib/mpp/challenge_id.rb +30 -6
- data/lib/mpp/client/transport.rb +1 -1
- data/lib/mpp/errors.rb +22 -0
- data/lib/mpp/http/headers.rb +61 -0
- data/lib/mpp/http.rb +8 -0
- data/lib/mpp/methods/evm/assets.rb +103 -0
- data/lib/mpp/methods/evm/authorization.rb +140 -0
- data/lib/mpp/methods/evm/charge_intent.rb +129 -0
- data/lib/mpp/methods/evm/evm_method.rb +133 -0
- data/lib/mpp/methods/evm.rb +67 -0
- data/lib/mpp/methods/stripe/charge_intent.rb +10 -8
- data/lib/mpp/methods/stripe/crypto_payment_recorder.rb +55 -0
- data/lib/mpp/methods/stripe/defaults.rb +1 -0
- data/lib/mpp/methods/stripe/machine_payments.rb +130 -0
- data/lib/mpp/methods/stripe/stripe_method.rb +22 -3
- data/lib/mpp/methods/stripe.rb +23 -0
- data/lib/mpp/methods/tempo/attribution.rb +3 -9
- data/lib/mpp/methods/tempo/client_method.rb +35 -6
- data/lib/mpp/methods/tempo/fee_payer_client.rb +120 -0
- data/lib/mpp/methods/tempo/intents.rb +80 -48
- data/lib/mpp/methods/tempo/proof.rb +39 -12
- data/lib/mpp/methods/tempo/relay.rb +257 -0
- data/lib/mpp/methods/tempo.rb +2 -0
- data/lib/mpp/parsing.rb +22 -2
- data/lib/mpp/receipt.rb +4 -3
- data/lib/mpp/server/accept_payment.rb +194 -0
- data/lib/mpp/server/compose.rb +399 -0
- data/lib/mpp/server/decorator.rb +30 -7
- data/lib/mpp/server/method.rb +15 -0
- data/lib/mpp/server/middleware.rb +160 -18
- data/lib/mpp/server/mpp_handler.rb +322 -34
- data/lib/mpp/server/result.rb +100 -0
- data/lib/mpp/server/verify.rb +24 -14
- data/lib/mpp/server.rb +4 -0
- data/lib/mpp/version.rb +1 -1
- data/lib/mpp/x402/facilitator.rb +127 -0
- data/lib/mpp/x402/header.rb +131 -0
- data/lib/mpp/x402/server.rb +247 -0
- data/lib/mpp/x402/types.rb +33 -0
- data/lib/mpp/x402.rb +12 -0
- data/lib/mpp.rb +16 -3
- metadata +48 -1
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "header"
|
|
5
|
+
require "digest"
|
|
6
|
+
require "openssl"
|
|
7
|
+
|
|
8
|
+
module Mpp
|
|
9
|
+
module X402
|
|
10
|
+
# Server-side x402 exact binding, challenge decoration, and header merge.
|
|
11
|
+
module Server
|
|
12
|
+
extend T::Sig
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
sig { params(values: T::Array[String]).returns(String) }
|
|
17
|
+
def merge_payment_required(values)
|
|
18
|
+
decoded = values.map { |value| Header.decode_payment_required(value) }
|
|
19
|
+
first = decoded.first
|
|
20
|
+
Kernel.raise ArgumentError, "Expected at least one x402 payment-required header." unless first
|
|
21
|
+
|
|
22
|
+
rest = decoded.drop(1)
|
|
23
|
+
incompatible = rest.any? do |value|
|
|
24
|
+
value["resource"] != first["resource"] || value["extensions"] != first["extensions"]
|
|
25
|
+
end
|
|
26
|
+
if incompatible
|
|
27
|
+
error = [first["error"], "Cannot merge x402 payment requirements with different resources."]
|
|
28
|
+
.compact
|
|
29
|
+
.reject { |item| item.to_s.empty? }
|
|
30
|
+
.join("; ")
|
|
31
|
+
return Header.encode_payment_required(first.merge("error" => error))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
errors = [first["error"], *rest.map { |value| value["error"] }]
|
|
35
|
+
.compact
|
|
36
|
+
.reject { |item| item.to_s.empty? }
|
|
37
|
+
merged = first.merge("accepts" => decoded.flat_map { |value| value["accepts"] })
|
|
38
|
+
merged["error"] = errors.join("; ") unless errors.empty?
|
|
39
|
+
Header.encode_payment_required(merged)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
sig do
|
|
43
|
+
params(
|
|
44
|
+
request: T::Hash[T.untyped, T.untyped],
|
|
45
|
+
authorization: T::Hash[T.untyped, T.untyped],
|
|
46
|
+
max_timeout_seconds: Integer
|
|
47
|
+
).returns(T::Hash[String, T.untyped])
|
|
48
|
+
end
|
|
49
|
+
def to_payment_requirements(request, authorization:, max_timeout_seconds:)
|
|
50
|
+
chain_id = request.dig("methodDetails", "chainId")
|
|
51
|
+
Kernel.raise ArgumentError, "EVM charge request requires methodDetails.chainId" if chain_id.nil?
|
|
52
|
+
|
|
53
|
+
{
|
|
54
|
+
"amount" => request["amount"].to_s,
|
|
55
|
+
"asset" => request["currency"].to_s,
|
|
56
|
+
"extra" => {
|
|
57
|
+
"assetTransferMethod" => ASSET_TRANSFER_EIP3009,
|
|
58
|
+
"name" => authorization["name"] || authorization[:name],
|
|
59
|
+
"version" => authorization["version"] || authorization[:version]
|
|
60
|
+
},
|
|
61
|
+
"maxTimeoutSeconds" => max_timeout_seconds,
|
|
62
|
+
"network" => "#{EVM_NETWORK_PREFIX}#{chain_id}",
|
|
63
|
+
"payTo" => request["recipient"].to_s,
|
|
64
|
+
"scheme" => SCHEME_EXACT
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
sig do
|
|
69
|
+
params(
|
|
70
|
+
requirements: T::Hash[T.untyped, T.untyped],
|
|
71
|
+
resource_url: String,
|
|
72
|
+
extensions: T.nilable(T::Hash[T.untyped, T.untyped]),
|
|
73
|
+
error: T.nilable(String)
|
|
74
|
+
).returns(T::Hash[String, T.untyped])
|
|
75
|
+
end
|
|
76
|
+
def payment_required_body(requirements:, resource_url:, extensions: nil, error: nil)
|
|
77
|
+
body = {
|
|
78
|
+
"accepts" => [requirements],
|
|
79
|
+
"resource" => {"url" => resource_url},
|
|
80
|
+
"x402Version" => VERSION
|
|
81
|
+
}
|
|
82
|
+
body["extensions"] = extensions if extensions
|
|
83
|
+
body["error"] = error if error
|
|
84
|
+
body
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
sig do
|
|
88
|
+
params(
|
|
89
|
+
challenge: Mpp::Challenge,
|
|
90
|
+
http_method: T.nilable(String)
|
|
91
|
+
).returns(T.nilable(T::Hash[String, T.untyped]))
|
|
92
|
+
end
|
|
93
|
+
def route_extensions(challenge, http_method)
|
|
94
|
+
return nil if http_method.nil? || http_method.empty?
|
|
95
|
+
|
|
96
|
+
binding = {"method" => http_method}
|
|
97
|
+
binding["digest"] = challenge.digest if challenge.digest
|
|
98
|
+
binding["opaque"] = Mpp::Parsing.b64_encode(challenge.opaque) if challenge.opaque
|
|
99
|
+
{
|
|
100
|
+
MPPX_EXTENSION_KEY => {
|
|
101
|
+
"info" => binding,
|
|
102
|
+
"schema" => MPPX_ROUTE_BINDING_SCHEMA
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
sig do
|
|
108
|
+
params(
|
|
109
|
+
accepted: T::Hash[T.untyped, T.untyped],
|
|
110
|
+
resource: T::Hash[T.untyped, T.untyped],
|
|
111
|
+
extensions: T::Hash[T.untyped, T.untyped]
|
|
112
|
+
).returns(String)
|
|
113
|
+
end
|
|
114
|
+
def route_nonce(accepted:, resource:, extensions:)
|
|
115
|
+
input = [
|
|
116
|
+
serialize_request(accepted),
|
|
117
|
+
serialize_request(resource),
|
|
118
|
+
serialize_request(extensions)
|
|
119
|
+
].join("|")
|
|
120
|
+
digest = Digest::SHA256.digest(input)
|
|
121
|
+
"0x#{digest.unpack1("H*")}"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
sig { params(value: T.untyped).returns(String) }
|
|
125
|
+
def serialize_request(value)
|
|
126
|
+
json = Mpp::Json.compact_encode(value)
|
|
127
|
+
Mpp.b64url_encode(json)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
sig do
|
|
131
|
+
params(
|
|
132
|
+
payment_payload: T::Hash[T.untyped, T.untyped],
|
|
133
|
+
requirements: T::Hash[T.untyped, T.untyped],
|
|
134
|
+
resource_url: T.nilable(String),
|
|
135
|
+
challenge: Mpp::Challenge,
|
|
136
|
+
body: T.untyped,
|
|
137
|
+
route_binding: Symbol,
|
|
138
|
+
http_method: T.nilable(String)
|
|
139
|
+
).returns(T::Hash[T.untyped, T.untyped])
|
|
140
|
+
end
|
|
141
|
+
def bind_credential(payment_payload:, requirements:, resource_url:, challenge:, body:, route_binding:, http_method: nil)
|
|
142
|
+
unless canonical_equal?(payment_payload["accepted"], requirements)
|
|
143
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "x402 payment payload does not match route requirements")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
assert_body_digest!(challenge, body)
|
|
147
|
+
|
|
148
|
+
expected_resource = {"url" => resource_url}
|
|
149
|
+
client_nonce = payment_payload.dig("extensions", MPPX_EXTENSION_KEY, "info", "nonce")
|
|
150
|
+
route_bound = !client_nonce.nil?
|
|
151
|
+
route_requires_binding = !challenge.digest.nil? || !challenge.opaque.nil?
|
|
152
|
+
|
|
153
|
+
if route_requires_binding && !route_bound && route_binding == :required
|
|
154
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "x402 payment payload does not bind required route metadata")
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
payload_resource = payment_payload["resource"]
|
|
158
|
+
if route_bound
|
|
159
|
+
unless payload_resource.is_a?(Hash) && payload_resource["url"] == expected_resource["url"]
|
|
160
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "x402 payment payload resource does not match route resource")
|
|
161
|
+
end
|
|
162
|
+
expected_extensions = route_extensions(challenge, http_method) || {}
|
|
163
|
+
unless contains_extensions?(payment_payload["extensions"], expected_extensions)
|
|
164
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "x402 payment payload extensions do not match route binding")
|
|
165
|
+
end
|
|
166
|
+
elsif resource_url
|
|
167
|
+
if payload_resource.is_a?(Hash) && payload_resource["url"] != resource_url
|
|
168
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "x402 payment payload resource does not match route resource")
|
|
169
|
+
end
|
|
170
|
+
if route_requires_binding && (payload_resource.nil? || payload_resource["url"] != resource_url)
|
|
171
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "x402 payment payload resource does not match route resource")
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
authorization = payload_to_authorization(payment_payload)
|
|
176
|
+
if route_bound
|
|
177
|
+
expected_nonce = route_nonce(
|
|
178
|
+
accepted: requirements,
|
|
179
|
+
extensions: payment_payload["extensions"],
|
|
180
|
+
resource: expected_resource
|
|
181
|
+
)
|
|
182
|
+
unless authorization["nonce"].to_s.downcase == expected_nonce.downcase
|
|
183
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "x402 authorization nonce does not match route binding")
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
authorization
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
sig { params(payment_payload: T::Hash[T.untyped, T.untyped]).returns(T::Hash[String, T.untyped]) }
|
|
191
|
+
def payload_to_authorization(payment_payload)
|
|
192
|
+
payload = payment_payload["payload"]
|
|
193
|
+
unless payload.is_a?(Hash) && payload["authorization"].is_a?(Hash)
|
|
194
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "EVM charge only supports x402 EIP-3009 authorization payloads")
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
authorization = payload["authorization"]
|
|
198
|
+
{
|
|
199
|
+
"from" => authorization["from"].to_s,
|
|
200
|
+
"nonce" => authorization["nonce"].to_s,
|
|
201
|
+
"signature" => payload["signature"].to_s,
|
|
202
|
+
"to" => authorization["to"].to_s,
|
|
203
|
+
"type" => "authorization",
|
|
204
|
+
"validAfter" => authorization["validAfter"].to_s,
|
|
205
|
+
"validBefore" => authorization["validBefore"].to_s,
|
|
206
|
+
"value" => authorization["value"].to_s
|
|
207
|
+
}
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
sig { params(left: T.untyped, right: T.untyped).returns(T::Boolean) }
|
|
211
|
+
def canonical_equal?(left, right)
|
|
212
|
+
Mpp::Json.compact_encode(left) == Mpp::Json.compact_encode(right)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
sig { params(challenge: Mpp::Challenge, body: T.untyped).void }
|
|
216
|
+
def assert_body_digest!(challenge, body)
|
|
217
|
+
return if body.nil? || challenge.digest.nil?
|
|
218
|
+
return if Mpp::BodyDigest.verify(T.must(challenge.digest), body)
|
|
219
|
+
|
|
220
|
+
Kernel.raise Mpp::VerificationFailedError.new(reason: "x402 payment body digest mismatch")
|
|
221
|
+
end
|
|
222
|
+
private_class_method :assert_body_digest!
|
|
223
|
+
|
|
224
|
+
sig { params(actual: T.untyped, expected: T::Hash[T.untyped, T.untyped]).returns(T::Boolean) }
|
|
225
|
+
def contains_extensions?(actual, expected)
|
|
226
|
+
return false unless actual.is_a?(Hash)
|
|
227
|
+
|
|
228
|
+
expected.all? do |key, expected_extension|
|
|
229
|
+
actual_extension = actual[key]
|
|
230
|
+
next false unless actual_extension.is_a?(Hash)
|
|
231
|
+
|
|
232
|
+
canonical_equal?(actual_extension["schema"], expected_extension["schema"]) &&
|
|
233
|
+
canonical_equal?(strip_client_nonce(actual_extension["info"]), expected_extension["info"])
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
private_class_method :contains_extensions?
|
|
237
|
+
|
|
238
|
+
sig { params(info: T.untyped).returns(T.untyped) }
|
|
239
|
+
def strip_client_nonce(info)
|
|
240
|
+
return info unless info.is_a?(Hash)
|
|
241
|
+
|
|
242
|
+
info.except("nonce")
|
|
243
|
+
end
|
|
244
|
+
private_class_method :strip_client_nonce
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Mpp
|
|
5
|
+
module X402
|
|
6
|
+
VERSION = 2
|
|
7
|
+
PAYMENT_METHOD = "evm"
|
|
8
|
+
EXACT_INTENT = "charge"
|
|
9
|
+
SCHEME_EXACT = "exact"
|
|
10
|
+
ASSET_TRANSFER_EIP3009 = "eip3009"
|
|
11
|
+
EVM_NETWORK_PREFIX = "eip155:"
|
|
12
|
+
SYNTHETIC_CHALLENGE_ID_PREFIX = "x402:"
|
|
13
|
+
|
|
14
|
+
PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED"
|
|
15
|
+
PAYMENT_SIGNATURE_HEADER = "PAYMENT-SIGNATURE"
|
|
16
|
+
PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE"
|
|
17
|
+
|
|
18
|
+
MPPX_EXTENSION_KEY = "mppx"
|
|
19
|
+
|
|
20
|
+
MPPX_ROUTE_BINDING_SCHEMA = T.let({
|
|
21
|
+
"additionalProperties" => false,
|
|
22
|
+
"properties" => {
|
|
23
|
+
"_mppx_scope" => {"type" => "string"},
|
|
24
|
+
"digest" => {"type" => "string"},
|
|
25
|
+
"method" => {"type" => "string"},
|
|
26
|
+
"nonce" => {"type" => "string"},
|
|
27
|
+
"opaque" => {"type" => "string"}
|
|
28
|
+
},
|
|
29
|
+
"required" => ["method"],
|
|
30
|
+
"type" => "object"
|
|
31
|
+
}.freeze, T::Hash[String, T.untyped])
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/mpp/x402.rb
ADDED
data/lib/mpp.rb
CHANGED
|
@@ -11,6 +11,9 @@ require_relative "mpp/secure_compare"
|
|
|
11
11
|
module Mpp
|
|
12
12
|
extend T::Sig
|
|
13
13
|
|
|
14
|
+
AUTHORIZATION_HEADER = T.let("Authorization", String)
|
|
15
|
+
PAYMENT_AUTHORIZATION_HEADER = T.let("Payment-Authorization", String)
|
|
16
|
+
|
|
14
17
|
autoload :Challenge, "mpp/challenge"
|
|
15
18
|
autoload :ChallengeEcho, "mpp/challenge_echo"
|
|
16
19
|
autoload :Credential, "mpp/credential"
|
|
@@ -22,6 +25,8 @@ module Mpp
|
|
|
22
25
|
autoload :Events, "mpp/events"
|
|
23
26
|
autoload :Units, "mpp/units"
|
|
24
27
|
autoload :MemoryStore, "mpp/store"
|
|
28
|
+
autoload :Http, "mpp/http"
|
|
29
|
+
autoload :X402, "mpp/x402"
|
|
25
30
|
|
|
26
31
|
# Server module (autoloaded)
|
|
27
32
|
autoload :Server, "mpp/server"
|
|
@@ -33,6 +38,7 @@ module Mpp
|
|
|
33
38
|
module Methods
|
|
34
39
|
autoload :Tempo, "mpp/methods/tempo"
|
|
35
40
|
autoload :Stripe, "mpp/methods/stripe"
|
|
41
|
+
autoload :Evm, "mpp/methods/evm"
|
|
36
42
|
end
|
|
37
43
|
|
|
38
44
|
# Extensions namespace
|
|
@@ -40,9 +46,16 @@ module Mpp
|
|
|
40
46
|
autoload :MCP, "mpp/extensions/mcp"
|
|
41
47
|
end
|
|
42
48
|
|
|
43
|
-
sig { params(method: T.untyped, realm: T.untyped, secret_key: T.untyped, events: T.nilable(Mpp::Events::Dispatcher)).returns(T.untyped) }
|
|
44
|
-
def self.create(method
|
|
45
|
-
Server::MppHandler.create(
|
|
49
|
+
sig { params(method: T.untyped, methods: T.nilable(T::Array[T.untyped]), realm: T.untyped, secret_key: T.untyped, events: T.nilable(Mpp::Events::Dispatcher), requires_auth: T::Boolean).returns(T.untyped) }
|
|
50
|
+
def self.create(method: nil, methods: nil, realm: nil, secret_key: nil, events: nil, requires_auth: false)
|
|
51
|
+
Server::MppHandler.create(
|
|
52
|
+
method: method,
|
|
53
|
+
methods: methods,
|
|
54
|
+
realm: realm,
|
|
55
|
+
secret_key: secret_key,
|
|
56
|
+
events: events,
|
|
57
|
+
requires_auth: requires_auth
|
|
58
|
+
)
|
|
46
59
|
end
|
|
47
60
|
|
|
48
61
|
# Error hierarchy
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mpp-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stripe
|
|
@@ -23,6 +23,34 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0.3'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: keccak
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.3'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.3'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: sorbet-runtime
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
26
54
|
description: Ruby SDK for the Machine Payments Protocol (MPP) — an HTTP 402 Payment
|
|
27
55
|
Authentication scheme.
|
|
28
56
|
executables: []
|
|
@@ -50,22 +78,33 @@ files:
|
|
|
50
78
|
- lib/mpp/extensions/mcp/errors.rb
|
|
51
79
|
- lib/mpp/extensions/mcp/types.rb
|
|
52
80
|
- lib/mpp/extensions/mcp/verify.rb
|
|
81
|
+
- lib/mpp/http.rb
|
|
82
|
+
- lib/mpp/http/headers.rb
|
|
53
83
|
- lib/mpp/json.rb
|
|
84
|
+
- lib/mpp/methods/evm.rb
|
|
85
|
+
- lib/mpp/methods/evm/assets.rb
|
|
86
|
+
- lib/mpp/methods/evm/authorization.rb
|
|
87
|
+
- lib/mpp/methods/evm/charge_intent.rb
|
|
88
|
+
- lib/mpp/methods/evm/evm_method.rb
|
|
54
89
|
- lib/mpp/methods/stripe.rb
|
|
55
90
|
- lib/mpp/methods/stripe/charge_intent.rb
|
|
56
91
|
- lib/mpp/methods/stripe/client_method.rb
|
|
92
|
+
- lib/mpp/methods/stripe/crypto_payment_recorder.rb
|
|
57
93
|
- lib/mpp/methods/stripe/defaults.rb
|
|
94
|
+
- lib/mpp/methods/stripe/machine_payments.rb
|
|
58
95
|
- lib/mpp/methods/stripe/stripe_method.rb
|
|
59
96
|
- lib/mpp/methods/tempo.rb
|
|
60
97
|
- lib/mpp/methods/tempo/account.rb
|
|
61
98
|
- lib/mpp/methods/tempo/attribution.rb
|
|
62
99
|
- lib/mpp/methods/tempo/client_method.rb
|
|
63
100
|
- lib/mpp/methods/tempo/defaults.rb
|
|
101
|
+
- lib/mpp/methods/tempo/fee_payer_client.rb
|
|
64
102
|
- lib/mpp/methods/tempo/fee_payer_envelope.rb
|
|
65
103
|
- lib/mpp/methods/tempo/fee_payer_policy.rb
|
|
66
104
|
- lib/mpp/methods/tempo/intents.rb
|
|
67
105
|
- lib/mpp/methods/tempo/keychain.rb
|
|
68
106
|
- lib/mpp/methods/tempo/proof.rb
|
|
107
|
+
- lib/mpp/methods/tempo/relay.rb
|
|
69
108
|
- lib/mpp/methods/tempo/rpc.rb
|
|
70
109
|
- lib/mpp/methods/tempo/schemas.rb
|
|
71
110
|
- lib/mpp/methods/tempo/transaction.rb
|
|
@@ -73,16 +112,24 @@ files:
|
|
|
73
112
|
- lib/mpp/receipt.rb
|
|
74
113
|
- lib/mpp/secure_compare.rb
|
|
75
114
|
- lib/mpp/server.rb
|
|
115
|
+
- lib/mpp/server/accept_payment.rb
|
|
116
|
+
- lib/mpp/server/compose.rb
|
|
76
117
|
- lib/mpp/server/decorator.rb
|
|
77
118
|
- lib/mpp/server/defaults.rb
|
|
78
119
|
- lib/mpp/server/intent.rb
|
|
79
120
|
- lib/mpp/server/method.rb
|
|
80
121
|
- lib/mpp/server/middleware.rb
|
|
81
122
|
- lib/mpp/server/mpp_handler.rb
|
|
123
|
+
- lib/mpp/server/result.rb
|
|
82
124
|
- lib/mpp/server/verify.rb
|
|
83
125
|
- lib/mpp/store.rb
|
|
84
126
|
- lib/mpp/units.rb
|
|
85
127
|
- lib/mpp/version.rb
|
|
128
|
+
- lib/mpp/x402.rb
|
|
129
|
+
- lib/mpp/x402/facilitator.rb
|
|
130
|
+
- lib/mpp/x402/header.rb
|
|
131
|
+
- lib/mpp/x402/server.rb
|
|
132
|
+
- lib/mpp/x402/types.rb
|
|
86
133
|
homepage: https://github.com/stripe/mpp-rb
|
|
87
134
|
licenses:
|
|
88
135
|
- MIT
|