Module: Mpp::Methods::Tempo::FeePayer

Defined in:
lib/mpp/methods/tempo/fee_payer_envelope.rb

Constant Summary collapse

TYPE_ID =
0x78

Class Method Summary collapse

Class Method Details

.decode(data) ⇒ Object

Decode a 0x78 fee payer envelope.

Returns [decoded_fields, sender_address_bytes, sender_signature_bytes, key_authorization_or_nil]



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/mpp/methods/tempo/fee_payer_envelope.rb', line 48

def decode(data)
  Kernel.require "rlp"

  Kernel.raise ArgumentError, "Not a fee payer envelope (expected 0x78 prefix)" unless data.getbyte(0) == TYPE_ID

  decoded = RLP.decode(data[1..])
  Kernel.raise ArgumentError, "Malformed fee payer envelope" unless decoded.is_a?(Array) && decoded.length >= 14

  sender_address = decoded[11]
  sender_signature = decoded[-1]

  # 15 fields = key_authorization present (index 13), signature at 14
  # 14 fields = no key_authorization, signature at 13
  key_authorization = (RLP.encode(decoded[13]) if decoded.length == 15)

  [decoded, sender_address.to_s.b, sender_signature.to_s.b, key_authorization]
end

.encode(signed_tx) ⇒ Object

Encode a sender-signed transaction as a 0x78 fee payer envelope. Requires the ‘rlp` gem.

Wire format: 0x78 || RLP()



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/mpp/methods/tempo/fee_payer_envelope.rb', line 16

def encode(signed_tx)
  Kernel.require "rlp"

  sender_sig = signed_tx.sender_signature
  sig_bytes = normalize_signature(sender_sig.respond_to?(:to_bytes) ? sender_sig.to_bytes : sender_sig.to_s.b)
  sender_addr = pack_hex(signed_tx.sender_address)

  fields = [
    signed_tx.chain_id,
    signed_tx.max_priority_fee_per_gas,
    signed_tx.max_fee_per_gas,
    signed_tx.gas_limit,
    signed_tx.calls.map(&:as_rlp_list),
    signed_tx.access_list.map { |entry| entry.respond_to?(:as_rlp_list) ? entry.as_rlp_list : entry },
    signed_tx.nonce_key,
    signed_tx.nonce,
    encode_optional_uint(signed_tx.valid_before),
    encode_optional_uint(signed_tx.valid_after),
    signed_tx.fee_token ? pack_hex(signed_tx.fee_token) : "".b,
    sender_addr,
    signed_tx.tempo_authorization_list.to_a
  ]

  fields << RLP.decode(signed_tx.key_authorization) if signed_tx.key_authorization
  fields << sig_bytes

  [TYPE_ID].pack("C") + RLP.encode(fields)
end

.encode_optional_uint(value) ⇒ Object



66
67
68
69
70
# File 'lib/mpp/methods/tempo/fee_payer_envelope.rb', line 66

def encode_optional_uint(value)
  return "".b unless value

  value.is_a?(Integer) ? value : value.to_i
end

.normalize_signature(signature) ⇒ Object



76
77
78
79
80
81
82
83
84
85
# File 'lib/mpp/methods/tempo/fee_payer_envelope.rb', line 76

def normalize_signature(signature)
  bytes = signature.b
  Kernel.raise ArgumentError, "signature must be 65 bytes, got #{bytes.bytesize}" unless bytes.bytesize == 65

  v = bytes.getbyte(64)
  parity = (v >= 27) ? v - 27 : v
  Kernel.raise ArgumentError, "signature parity must be 0 or 1, got #{v}" unless [0, 1].include?(parity)

  bytes[0, 64] + [parity].pack("C")
end

.pack_hex(value) ⇒ Object



72
73
74
# File 'lib/mpp/methods/tempo/fee_payer_envelope.rb', line 72

def pack_hex(value)
  [value.to_s.delete_prefix("0x")].pack("H*")
end