Class: X402::BSV::BRC105Gateway
- Inherits:
-
Object
- Object
- X402::BSV::BRC105Gateway
- Defined in:
- lib/x402/bsv/brc105_gateway.rb
Overview
BRC-105 gateway for BSV settlement-gated HTTP.
Unlike PayGateway/ProofGateway, this does NOT inherit from Gateway. BRC-105 uses a fundamentally different pattern: no partial tx template, no OP_RETURN binding, no payTo HMAC. Key derivation (BRC-42/43) via KeyDeriver replaces the template-based approach.
Implements the three-method gateway interface required by Middleware:
challenge_headers(rack_request, route) → Hash
proof_header_names → Array
Constant Summary collapse
- PROTOCOL_ID =
[2, "3241645161d8"].freeze
- PROOF_HEADER =
"x-bsv-payment"- PROTOCOL =
"wallet payment"- COMPRESSED_PUBKEY_HEX =
/\A0[23][0-9a-f]{64}\z/- MAX_DERIVATION_BYTES =
64- PRINTABLE_ASCII =
/\A[\x20-\x7E]+\z/
Instance Method Summary collapse
-
#challenge_headers(rack_request, route) ⇒ Hash
Issue a 402 challenge with BRC-105 headers.
-
#initialize(key_deriver:, prefix_store:, wallet:) ⇒ BRC105Gateway
constructor
A new instance of BRC105Gateway.
-
#proof_header_names ⇒ Array<String>
Header names that carry the proof/payment from the client.
-
#settle!(_header_name, proof_payload, rack_request, route) ⇒ SettlementResult
Verify and internalise a BRC-105 payment.
Constructor Details
#initialize(key_deriver:, prefix_store:, wallet:) ⇒ BRC105Gateway
Returns a new instance of BRC105Gateway.
32 33 34 35 36 |
# File 'lib/x402/bsv/brc105_gateway.rb', line 32 def initialize(key_deriver:, prefix_store:, wallet:) @key_deriver = key_deriver @prefix_store = prefix_store @wallet = wallet end |
Instance Method Details
#challenge_headers(rack_request, route) ⇒ Hash
Issue a 402 challenge with BRC-105 headers.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/x402/bsv/brc105_gateway.rb', line 43 def challenge_headers(rack_request, route) prefix = SecureRandom.hex(16) begin @prefix_store.store!(prefix) rescue PrefixStore::StoreFullError raise VerificationError.new("server at capacity — try again later", status: 503) end headers = { "x-bsv-payment-version" => "1.0", "x-bsv-payment-satoshis-required" => route.resolve_amount_sats.to_s, "x-bsv-payment-derivation-prefix" => prefix } # The 402 challenge is issued before the client authenticates (no # x-bsv-auth-identity-key yet). Include the server's identity key so # the client knows who to derive the payment address for. When BRC-103 # mutual auth is already established, the client already has this key. headers["x-bsv-payment-identity-key"] = @key_deriver.identity_key unless validated_brc103_key(rack_request) headers end |
#proof_header_names ⇒ Array<String>
Header names that carry the proof/payment from the client.
69 70 71 |
# File 'lib/x402/bsv/brc105_gateway.rb', line 69 def proof_header_names [PROOF_HEADER] end |
#settle!(_header_name, proof_payload, rack_request, route) ⇒ SettlementResult
Verify and internalise a BRC-105 payment.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/x402/bsv/brc105_gateway.rb', line 80 def settle!(_header_name, proof_payload, rack_request, route) # §7.1: fail fast if unauthenticated — before parsing untrusted payload counterparty = resolve_counterparty(rack_request) required_sats = route.resolve_amount_sats payment = parse_payment(proof_payload) prefix = payment["derivationPrefix"] suffix = payment["derivationSuffix"] validate_prefix_and_suffix!(prefix, suffix) subject_tx = parse_beef_transaction(payment["transaction"]) log_derivation_inputs(prefix, suffix, counterparty) expected_script = derive_payment_script(prefix, suffix, rack_request) log_expected_script(expected_script) log_tx_outputs(subject_tx, required_sats, expected_script) paid_sats, output_index = verify_payment_output!(subject_tx, required_sats, expected_script) consume_prefix!(prefix) internalize_payment!( transaction_b64: payment["transaction"], output_index: output_index, derivation_prefix: prefix, derivation_suffix: suffix, sender_identity_key: counterparty ) log_settlement_success(subject_tx, paid_sats, required_sats) build_settlement_result(subject_tx, paid_sats) end |