rail0-sdk 1.7.0 → 1.7.2
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 +25 -4
- data/lib/rail0/error_hints.rb +7 -3
- data/lib/rail0/payload_verify.rb +77 -2
- data/lib/rail0/resources/wallets.rb +6 -1
- data/lib/rail0/types.rb +16 -26
- data/lib/rail0/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c69ef678235fc14acf0f3bcaebc302bd3b63d6dd1b41a1358381b49fd6a9738
|
|
4
|
+
data.tar.gz: 1d42362b54cf2118b2150087211bd7f5df49a8248278af49603fd745d32be08b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 061516a40ea00e3ebf114f9ae841bfac830682f443caaa8f82fbe4789de91d1eab760896c6a0447a371092cd01f5bbb9f30200e8e17f0897bce60390ba541e82
|
|
7
|
+
data.tar.gz: 5f0e8c80653d3234d24f2816f607a84ecfb99c743afa2dd58fa64d3c184510458796ab54efc8cad00c7b478f35a26bf68d6339e1c592dff8d2712d087e3aae03
|
data/README.md
CHANGED
|
@@ -150,8 +150,16 @@ signs after `create` (and the payee signs in refund phase 1) is the more dangero
|
|
|
150
150
|
two artifacts: the **token** honours it on its own, with no RAIL0 involvement, for up to
|
|
151
151
|
its `value` — so an endpoint that answered with `{from: you, to: attacker, value: your
|
|
152
152
|
whole balance}` used to get exactly that signed. `sign_signing_payload(signing_payload,
|
|
153
|
-
key, payment:, amount: nil)` checks it first
|
|
154
|
-
`
|
|
153
|
+
key, payment:, amount: nil)` checks it first. The typed-data envelope: `primaryType` is
|
|
154
|
+
`ReceiveWithAuthorization` (authorize/charge on v1.4.0+ deployments, and every refund) or
|
|
155
|
+
`TransferWithAuthorization` (authorize/charge on v1.1.0–v1.3.x); `types[primaryType]` is
|
|
156
|
+
**exactly** the EIP-3009 struct — `address from, address to, uint256 value, uint256
|
|
157
|
+
validAfter, uint256 validBefore, bytes32 nonce`, same names, types and order;
|
|
158
|
+
`types.EIP712Domain`, when present, is exactly `string name, string version, uint256
|
|
159
|
+
chainId, address verifyingContract`; and `types` defines nothing else (a local key hashes
|
|
160
|
+
with fixed typehashes, but a browser wallet hashes whatever `types` says, so this is what
|
|
161
|
+
lets `PayloadVerify.verify` guard an `eth_signTypedData_v4` call). Then, against data you
|
|
162
|
+
already hold: `message.from` is your key's address, `domain.chainId` the payment's `chain_id`,
|
|
155
163
|
`domain.verifyingContract` the payment's `token`, `message.to` its `rail0_contract`, and
|
|
156
164
|
`message.value` **exactly** the amount — `amount:` scaled by the payment's `decimals` when
|
|
157
165
|
you pass one (a refund), otherwise the payment's own base-unit `amount` (a created
|
|
@@ -374,6 +382,7 @@ client.wallets.list(account_id, token_active: true)
|
|
|
374
382
|
|
|
375
383
|
client.wallets.get(account_id, id_or_address)
|
|
376
384
|
client.wallets.update(account_id, id_or_address, label: "Renamed", active: false)
|
|
385
|
+
client.wallets.update(account_id, id_or_address, active: true) # back on (see below)
|
|
377
386
|
client.wallets.delete(account_id, id_or_address) # 204
|
|
378
387
|
client.wallets.balances(account_id, id_or_address, chain_id: 84532) # live on-chain balances
|
|
379
388
|
```
|
|
@@ -384,6 +393,17 @@ refused with 422 `last_active_wallet` — login resolves the account from a wall
|
|
|
384
393
|
so an account with none could neither act nor add one back. Another wallet must
|
|
385
394
|
be active first.
|
|
386
395
|
|
|
396
|
+
**Switching a wallet back on.** Every switch-off records who did it in the wallet's
|
|
397
|
+
`deactivated_by`: `"owner"` (a session signed in with that wallet) or `"operator"`
|
|
398
|
+
(an operator session); `nil` while active, and on a switch-off older than the record.
|
|
399
|
+
A deactivated wallet's session is read-only (403 `wallet_deactivated`) except for one
|
|
400
|
+
write: `update(account_id, id, active: true)` on its **own** wallet, which switches it
|
|
401
|
+
back on when its owner switched it off. A wallet an operator switched off (or with
|
|
402
|
+
`deactivated_by: nil`) raises 403 `wallet_deactivated_by_operator`: an operator's
|
|
403
|
+
switch-off revokes the key, so only an operator lifts it. The flip side: a wallet its
|
|
404
|
+
owner switched off can be switched back on by whoever holds its key, so a definitive
|
|
405
|
+
revocation (a leaked key) must come from an operator.
|
|
406
|
+
|
|
387
407
|
**A session is bound to the wallet it signed in with.** Reads (`list`, `get`,
|
|
388
408
|
`balances`) are account-wide, but `update`, `delete` and the token-holding methods
|
|
389
409
|
act only on the session's own wallet: another wallet of the same account is
|
|
@@ -827,7 +847,7 @@ Requires the `eth` gem. No private key ever leaves your process.
|
|
|
827
847
|
|--------|-----|
|
|
828
848
|
| `sign_signing_payload(signing_payload, signer, payment:, amount: nil)` | Verify the EIP-3009 payload from a create/refund response against the payment, then sign it verbatim — the recommended path, and the only one that follows the gateway across contract versions |
|
|
829
849
|
| `sign_payload(signer, signing_payload, payment: nil, amount: nil)` | The same signer; with `payment:` it is `sign_signing_payload`, without it signs blindly (**deprecated**) |
|
|
830
|
-
| `Rail0::PayloadVerify.verify(signing_payload, payment:, signer:, amount: nil)` | The payload pre-sign check on its own |
|
|
850
|
+
| `Rail0::PayloadVerify.verify(signing_payload, payment:, signer:, amount: nil)` | The payload pre-sign check on its own — run it before handing the payload to a browser wallet |
|
|
831
851
|
| `sign_transaction(unsigned_transaction, key, payment:, operation:, amount: nil)` | Verify a prepare step's unsigned EIP-1559 transaction against the payment, then sign it; returns the 0x raw tx. Without `payment:` it signs blindly (**deprecated**) |
|
|
832
852
|
| `Rail0::TxVerify.verify(unsigned_transaction, payment:, operation:, amount: nil, signer: nil)` | The pre-sign check on its own — for a signer that is not a local key |
|
|
833
853
|
| `sign_transfer_with_authorization(signer, domain, params)` | Raw EIP-3009 `TransferWithAuthorization` signer, for talking to a token directly |
|
|
@@ -846,7 +866,8 @@ client.payments.sign(payment[:rail0_id], { signature: sig.to_hex })
|
|
|
846
866
|
**The gateway builds the payload; you sign it verbatim.** `sign_signing_payload` takes the
|
|
847
867
|
typehash from the payload's `primaryType` and every field from its `message` — only
|
|
848
868
|
the gateway knows which contract version a payment lives on, and the version selects
|
|
849
|
-
the typehash
|
|
869
|
+
the typehash and the EIP-712 domain (the field layout is EIP-3009's own, the same on
|
|
870
|
+
every version, which is why the check pins it). An unrecognised `primaryType`
|
|
850
871
|
raises rather than falling back, because a guessed typehash yields a *valid*
|
|
851
872
|
signature over the wrong digest, which fails only on-chain, after gas.
|
|
852
873
|
|
data/lib/rail0/error_hints.rb
CHANGED
|
@@ -55,7 +55,10 @@ module Rail0
|
|
|
55
55
|
"not_payer_or_payee" => "only the payer or the payee may do this",
|
|
56
56
|
"release_submitter_not_a_party" => "a release must be sent by the payment's payer or payee — omit `from` to build it for the signed-in wallet",
|
|
57
57
|
"payer_must_be_caller" => "the payer must be the signed-in wallet — sign in as the buyer to create its payment",
|
|
58
|
-
|
|
58
|
+
# gateway#439: a deactivated session may switch its OWN wallet back on when its owner
|
|
59
|
+
# switched it off; an operator's switch-off is the operator's to lift.
|
|
60
|
+
"wallet_deactivated" => "this wallet is deactivated: it can still read, but not act on payments or change the account — if you switched it off, its own session can switch it back on (wallets.update(..., active: true)), or sign in with another of the account's wallets",
|
|
61
|
+
"wallet_deactivated_by_operator" => "an operator deactivated this wallet, so only an operator can reactivate it — ask an operator to reactivate it",
|
|
59
62
|
"account_deactivated" => "the merchant account is deactivated: void, release and refund still work, but authorize, charge, capture and account changes do not — ask an operator to reactivate it",
|
|
60
63
|
# A session is bound to the one wallet it signed in with: the account's other wallets
|
|
61
64
|
# are readable, but not this session's to change (operators are exempt).
|
|
@@ -65,8 +68,9 @@ module Rail0
|
|
|
65
68
|
"wallet_add_unavailable" => "adding a wallet to an account is not available yet — it returns with the merchant wallet-management section",
|
|
66
69
|
# Login resolves the account FROM a wallet, so an account left with no active one
|
|
67
70
|
# could neither act nor add a wallet back. Adding a wallet is suspended and a session
|
|
68
|
-
# changes only its own wallet, so the other wallet
|
|
69
|
-
|
|
71
|
+
# changes only its own wallet, so the other wallet comes back on from its own session
|
|
72
|
+
# (if its owner switched it off) or from an operator (gateway#439).
|
|
73
|
+
"last_active_wallet" => "this is the account's only active wallet — another wallet must be active before this one can be switched off: sign in with one you switched off and reactivate it, or ask an operator (adding a wallet is not available yet)",
|
|
70
74
|
"last_admin" => "the change would leave no active operator — grant the operator role to another active account first",
|
|
71
75
|
"not_redrivable" => "only a pending transaction that already holds its signed bytes can be redriven — check the transaction's `redrivable` flag, and submit the signature if it has none",
|
|
72
76
|
"refund_expired" => "the refund window has closed (refundExpiry passed) — refund/dispute is no longer possible",
|
data/lib/rail0/payload_verify.rb
CHANGED
|
@@ -27,10 +27,17 @@ module Rail0
|
|
|
27
27
|
# 5. +message.value+ is EXACTLY the amount asked for, in base units — not a ceiling:
|
|
28
28
|
# the gateway asks for the full amount of the operation.
|
|
29
29
|
#
|
|
30
|
+
# Before those, the typed-data envelope: +primaryType+ is one of the two EIP-3009
|
|
31
|
+
# authorization types, +types[primaryType]+ is EXACTLY the EIP-3009 field list (names,
|
|
32
|
+
# types, order), +types.EIP712Domain+ (when present) is exactly the token domain's
|
|
33
|
+
# field list, and +types+ defines nothing else. {Signing.sign_payload} hashes with
|
|
34
|
+
# fixed typehashes and would not notice, but a browser wallet hashes whatever +types+
|
|
35
|
+
# says — so a caller that verifies here and then hands the payload to
|
|
36
|
+
# +eth_signTypedData_v4+ needs it.
|
|
37
|
+
#
|
|
30
38
|
# The payload is still signed VERBATIM: the typehash comes from its own +primaryType+
|
|
31
39
|
# and the digest from its own message. This only refuses a message whose fields
|
|
32
|
-
# contradict what the caller asked for. Like the CLI, it does not check
|
|
33
|
-
# against the contract version (the signer already refuses an unknown one), the
|
|
40
|
+
# contradict what the caller asked for. Like the CLI, it does not check the
|
|
34
41
|
# validity window, or +message.nonce+ — recomputing the nonce needs the deployment's
|
|
35
42
|
# VERSION(), which no payment response carries. The bounded residual is an
|
|
36
43
|
# authorization for the RIGHT token, on the RIGHT chain, from the RIGHT signer, for
|
|
@@ -62,6 +69,7 @@ module Rail0
|
|
|
62
69
|
pay = payment_fields(payment)
|
|
63
70
|
refuse("cannot check the authorization without the address of the signing key") if blank?(signer)
|
|
64
71
|
|
|
72
|
+
check_typed_data(sp[:primaryType], sp[:types])
|
|
65
73
|
check_from(message[:from], signer.to_s)
|
|
66
74
|
check_chain(domain[:chainId], pay[:chain_id])
|
|
67
75
|
check_address(domain[:verifyingContract], pay[:token], "token") do |got, want|
|
|
@@ -91,6 +99,73 @@ module Rail0
|
|
|
91
99
|
|
|
92
100
|
private_class_method :parse, :payment_fields
|
|
93
101
|
|
|
102
|
+
# The EIP-3009 authorization types the gateway emits. Which one a payment needs is the
|
|
103
|
+
# deployment's contract version, which no payment response carries: 1.4.0 and later
|
|
104
|
+
# use ReceiveWithAuthorization for authorize/charge, 1.1.0–1.3.x used
|
|
105
|
+
# TransferWithAuthorization, and refunds are ReceiveWithAuthorization on every
|
|
106
|
+
# version. So both are accepted and nothing else is.
|
|
107
|
+
PRIMARY_TYPES = %w[TransferWithAuthorization ReceiveWithAuthorization].freeze
|
|
108
|
+
|
|
109
|
+
# The EIP-3009 struct shared by both types: names, types AND order are the typehash.
|
|
110
|
+
AUTHORIZATION_FIELDS = [
|
|
111
|
+
%w[from address], %w[to address], %w[value uint256],
|
|
112
|
+
%w[validAfter uint256], %w[validBefore uint256], %w[nonce bytes32]
|
|
113
|
+
].freeze
|
|
114
|
+
|
|
115
|
+
# The token's EIP-712 domain, as the gateway declares it and the token hashes it.
|
|
116
|
+
DOMAIN_FIELDS = [
|
|
117
|
+
%w[name string], %w[version string], %w[chainId uint256], %w[verifyingContract address]
|
|
118
|
+
].freeze
|
|
119
|
+
|
|
120
|
+
private_constant :PRIMARY_TYPES, :AUTHORIZATION_FIELDS, :DOMAIN_FIELDS
|
|
121
|
+
|
|
122
|
+
# The typed-data envelope: refuses an unknown +primaryType+, a +types[primaryType]+
|
|
123
|
+
# that differs from the EIP-3009 struct in any name, type or position, an
|
|
124
|
+
# +EIP712Domain+ that differs from the token domain, or any further type.
|
|
125
|
+
def self.check_typed_data(primary_type, types)
|
|
126
|
+
unless PRIMARY_TYPES.include?(primary_type)
|
|
127
|
+
refuse("the authorization's primaryType #{primary_type.inspect} is not an EIP-3009 authorization type " \
|
|
128
|
+
"(TransferWithAuthorization or ReceiveWithAuthorization)")
|
|
129
|
+
end
|
|
130
|
+
refuse("the signing payload has no types") unless types.is_a?(Hash)
|
|
131
|
+
|
|
132
|
+
types = types.transform_keys(&:to_s)
|
|
133
|
+
extra = types.keys.find { |name| name != primary_type && name != "EIP712Domain" }
|
|
134
|
+
if extra
|
|
135
|
+
refuse("the signing payload's types define #{extra.inspect}, which an EIP-3009 authorization does not use")
|
|
136
|
+
end
|
|
137
|
+
check_type_fields("types.#{primary_type}", types[primary_type], AUTHORIZATION_FIELDS)
|
|
138
|
+
check_type_fields("types.EIP712Domain", types["EIP712Domain"], DOMAIN_FIELDS) if types.key?("EIP712Domain")
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def self.check_type_fields(label, fields, want)
|
|
142
|
+
return if exact_fields?(fields, want)
|
|
143
|
+
|
|
144
|
+
expected = want.map { |name, type| "#{type} #{name}" }.join(",")
|
|
145
|
+
refuse("#{label} is (#{describe_fields(fields)}) but must be exactly (#{expected})")
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def self.describe_fields(fields)
|
|
149
|
+
return (fields.nil? ? "null" : fields.inspect) unless fields.is_a?(Array)
|
|
150
|
+
|
|
151
|
+
fields.map { |f| f.is_a?(Hash) ? "#{field_of(f, 'type')} #{field_of(f, 'name')}" : f.inspect }.join(",")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.exact_fields?(fields, want)
|
|
155
|
+
fields.is_a?(Array) && fields.size == want.size &&
|
|
156
|
+
fields.each_with_index.all? do |f, i|
|
|
157
|
+
f.is_a?(Hash) && f.size == 2 && field_of(f, "name") == want[i][0] && field_of(f, "type") == want[i][1]
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# A field entry's +name+ / +type+, whether the payload arrived string- or
|
|
162
|
+
# symbol-keyed.
|
|
163
|
+
def self.field_of(field, key)
|
|
164
|
+
field.key?(key) ? field[key] : field[key.to_sym]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
private_class_method :check_typed_data, :check_type_fields, :describe_fields, :exact_fields?, :field_of
|
|
168
|
+
|
|
94
169
|
# Check 1: from = the key's own address. An absent +from+ is a mismatch, not a skip.
|
|
95
170
|
def self.check_from(from, signer)
|
|
96
171
|
return if same_address?(from, signer)
|
|
@@ -92,11 +92,16 @@ module Rail0
|
|
|
92
92
|
# operator may change any). +active: false+ on the account's only active wallet
|
|
93
93
|
# raises ApiError 422 +last_active_wallet+: login resolves the account from a
|
|
94
94
|
# wallet, so an account with none could neither act nor add one back.
|
|
95
|
+
#
|
|
96
|
+
# +active: true+ is the one write a deactivated wallet's own session may make: it
|
|
97
|
+
# switches the wallet back on when its owner switched it off. A wallet an operator
|
|
98
|
+
# switched off (+deactivated_by+ "operator", or nil on an older switch-off) raises
|
|
99
|
+
# ApiError 403 +wallet_deactivated_by_operator+: only an operator lifts it.
|
|
95
100
|
# @param account_id [String] Account UUID.
|
|
96
101
|
# @param id_or_address [String] Wallet UUID or 0x address.
|
|
97
102
|
# @param label [String, nil] New label.
|
|
98
103
|
# @param active [Boolean, nil] New active status.
|
|
99
|
-
# @return [Hash] id, address, label, active
|
|
104
|
+
# @return [Hash] id, address, label, active, deactivated_by
|
|
100
105
|
def update(account_id, id_or_address, label: nil, active: nil)
|
|
101
106
|
body = {}
|
|
102
107
|
body[:label] = label unless label.nil?
|
data/lib/rail0/types.rb
CHANGED
|
@@ -209,10 +209,11 @@ module Rail0
|
|
|
209
209
|
|
|
210
210
|
# Public-safe wallet view (the reduced set a buyer needs to discover a merchant's payment methods).
|
|
211
211
|
Wallet = Struct.new(
|
|
212
|
-
:id,
|
|
213
|
-
:address,
|
|
212
|
+
:id, # String
|
|
213
|
+
:address, # String
|
|
214
214
|
:label,
|
|
215
|
-
:active,
|
|
215
|
+
:active, # Boolean
|
|
216
|
+
:deactivated_by, # Who switched the wallet off: `owner` (a session signed in with this wallet) or `operator` (an admin session). Null while active, and on a switch-off that predates the record — treated as `operator`. A wallet an operator switched off can be switched back on only by an operator (403 `wallet_deactivated_by_operator`). Always null on GET /payment_methods, which serves active wallets only.
|
|
216
217
|
keyword_init: true
|
|
217
218
|
)
|
|
218
219
|
|
|
@@ -229,11 +230,12 @@ module Rail0
|
|
|
229
230
|
# A wallet with its token holdings nested inline. `tokens` is empty when the wallet has none — the
|
|
230
231
|
# wallet is still returned, never omitted.
|
|
231
232
|
WalletWithTokens = Struct.new(
|
|
232
|
-
:id,
|
|
233
|
-
:address,
|
|
233
|
+
:id, # String
|
|
234
|
+
:address, # String
|
|
234
235
|
:label,
|
|
235
|
-
:active,
|
|
236
|
-
:
|
|
236
|
+
:active, # Boolean
|
|
237
|
+
:deactivated_by, # Who switched the wallet off: `owner` (a session signed in with this wallet) or `operator` (an admin session). Null while active, and on a switch-off that predates the record — treated as `operator`. A wallet an operator switched off can be switched back on only by an operator (403 `wallet_deactivated_by_operator`). Always null on GET /payment_methods, which serves active wallets only.
|
|
238
|
+
:tokens, # Array
|
|
237
239
|
keyword_init: true
|
|
238
240
|
)
|
|
239
241
|
|
|
@@ -457,24 +459,25 @@ module Rail0
|
|
|
457
459
|
keyword_init: true
|
|
458
460
|
)
|
|
459
461
|
|
|
460
|
-
# One reported
|
|
461
|
-
|
|
462
|
+
# One reported configuration value.
|
|
463
|
+
ConfigSetting = Struct.new(
|
|
462
464
|
:value, # The effective value (number, boolean, string, list or map).
|
|
463
465
|
:env, # String — The environment variable that sets it; null for a constant.
|
|
464
466
|
:overridden, # Boolean — Whether that variable is set in this process.
|
|
465
|
-
:description, # String — Plain-text explanation of the entry: what it controls, which part of the gateway reads it and the effect of raising or lowering it, and its unit (from config/
|
|
467
|
+
:description, # String — Plain-text explanation of the entry: what it controls, which part of the gateway reads it and the effect of raising or lowering it, and its unit (from config/config_descriptions.yml). Every entry has one; older gateways omit the field.
|
|
466
468
|
keyword_init: true
|
|
467
469
|
)
|
|
468
470
|
|
|
469
|
-
# GET /admin/
|
|
470
|
-
|
|
471
|
+
# GET /admin/config: the effective configuration, grouped. Every leaf is a ConfigSetting.
|
|
472
|
+
ConfigReport = Struct.new(
|
|
471
473
|
:payments, # Hash
|
|
472
474
|
:recovery, # Hash
|
|
473
475
|
:retention, # Hash
|
|
474
476
|
:webhooks, # Hash
|
|
475
477
|
:settlement, # Hash
|
|
476
478
|
:rate_limit, # Hash
|
|
477
|
-
:siwe, # Hash
|
|
479
|
+
:siwe, # Hash — domains (SIWE_DOMAIN), accepted_chain_ids (1 plus the ids of the active catalog chains: the chainId values a login may carry) and nonce_ttl.
|
|
480
|
+
:session, # Hash — environment (RAIL0_ENVIRONMENT, default RACK_ENV: the scope every issued token is bound to), jwt_ttl and jwt_audience: the session token's lifetime (a constant) and audience (`rail0-gateway:<environment>`).
|
|
478
481
|
:fees, # Hash
|
|
479
482
|
:rpc, # Hash
|
|
480
483
|
:onboarding, # Hash
|
|
@@ -532,18 +535,5 @@ module Rail0
|
|
|
532
535
|
:contract_address, # String — Address (lowercase) of the RAIL0 deployment the payment is bound to, archived versions included. The sweeper accepts a receipt's event only when this contract emitted it.
|
|
533
536
|
keyword_init: true
|
|
534
537
|
)
|
|
535
|
-
|
|
536
|
-
# Per-chain indexer config.
|
|
537
|
-
SyncBlockchain = Struct.new(
|
|
538
|
-
:chain_id, # Integer
|
|
539
|
-
:start_block, # Integer
|
|
540
|
-
:required_confirmations, # Integer — Fallback burial depth, used where the chain serves no finality tag.
|
|
541
|
-
:finality_tag, # String — Which block the chain calls settled; the indexer gates every notify on it.
|
|
542
|
-
:explorer_url, # Block explorer base URL; null when the chain has none.
|
|
543
|
-
:network_type, # String — "testnet" or "mainnet"; selects which chains a deployment indexes.
|
|
544
|
-
:rpc_urls, # Array — Ordered list of public RPC endpoints tried in turn (serial fallback).
|
|
545
|
-
:contracts, # Array — Active RAIL0 contract addresses on the chain (all watched versions).
|
|
546
|
-
keyword_init: true
|
|
547
|
-
)
|
|
548
538
|
end
|
|
549
539
|
end
|
data/lib/rail0/version.rb
CHANGED
|
@@ -5,5 +5,5 @@ module Rail0
|
|
|
5
5
|
# consumed by path from a sibling checkout, where the number bought nothing: no registry
|
|
6
6
|
# ever served a 1.x, no tag was ever cut, and the one consumer resolves the working tree.
|
|
7
7
|
# Publishing from 1.2.0 would have implied two releases nobody can install.
|
|
8
|
-
VERSION = "1.7.
|
|
8
|
+
VERSION = "1.7.2"
|
|
9
9
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rail0-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.
|
|
4
|
+
version: 1.7.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Commerce Layer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: logger
|