Class: Mpp::Methods::Tempo::TempoMethod

Inherits:
Object
  • Object
show all
Defined in:
lib/mpp/methods/tempo/client_method.rb

Overview

Tempo payment method implementation. Handles client-side credential creation for Tempo payments.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(account: nil, fee_payer: nil, root_account: nil, rpc_url: Defaults::RPC_URL, chain_id: nil, currency: nil, recipient: nil, decimals: 6, client_id: nil, expected_recipients: nil) ⇒ TempoMethod

Returns a new instance of TempoMethod.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/mpp/methods/tempo/client_method.rb', line 24

def initialize(account: nil, fee_payer: nil, root_account: nil,
  rpc_url: Defaults::RPC_URL, chain_id: nil, currency: nil,
  recipient: nil, decimals: 6, client_id: nil,
  expected_recipients: nil)
  @name = "tempo"
  @account = 
  @fee_payer = fee_payer
  @root_account = 
  @rpc_url = rpc_url
  @chain_id = chain_id
  @currency = currency
  @recipient = recipient
  @decimals = decimals
  @client_id = client_id
  @expected_recipients = expected_recipients&.map(&:downcase)&.to_set
  @intents = {}
end

Instance Attribute Details

#accountObject (readonly)

Returns the value of attribute account.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def 
  @account
end

#chain_idObject (readonly)

Returns the value of attribute chain_id.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def chain_id
  @chain_id
end

#client_idObject (readonly)

Returns the value of attribute client_id.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def client_id
  @client_id
end

#currencyObject (readonly)

Returns the value of attribute currency.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def currency
  @currency
end

#decimalsObject (readonly)

Returns the value of attribute decimals.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def decimals
  @decimals
end

#expected_recipientsObject (readonly)

Returns the value of attribute expected_recipients.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def expected_recipients
  @expected_recipients
end

#fee_payerObject (readonly)

Returns the value of attribute fee_payer.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def fee_payer
  @fee_payer
end

#intentsObject

Returns the value of attribute intents.



22
23
24
# File 'lib/mpp/methods/tempo/client_method.rb', line 22

def intents
  @intents
end

#nameObject (readonly)

Returns the value of attribute name.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def name
  @name
end

#recipientObject (readonly)

Returns the value of attribute recipient.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def recipient
  @recipient
end

#root_accountObject (readonly)

Returns the value of attribute root_account.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def 
  @root_account
end

#rpc_urlObject (readonly)

Returns the value of attribute rpc_url.



19
20
21
# File 'lib/mpp/methods/tempo/client_method.rb', line 19

def rpc_url
  @rpc_url
end

Instance Method Details

#create_credential(challenge, mode: nil) ⇒ Object

Create a credential to satisfy the given challenge.

mode: :pull (default) — return signed transaction for server to broadcast

:push — broadcast on-chain, return transaction hash
:proof — zero-amount transaction proving account ownership

Raises:

  • (ArgumentError)


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/mpp/methods/tempo/client_method.rb', line 47

def create_credential(challenge, mode: nil)
  raise ArgumentError, "No account configured for signing" unless @account
  raise ArgumentError, "Unsupported intent: #{challenge.intent}" unless challenge.intent == "charge"

  mode ||= :pull
  request = challenge.request
  method_details = request["methodDetails"]
  method_details = {} unless method_details.is_a?(Hash)

  validate_recipients(request, method_details) if @expected_recipients

  use_fee_payer = method_details.fetch("feePayer", false)

  nonce_key = request.fetch("nonce_key", 0)
  if nonce_key.is_a?(String)
    nonce_key = nonce_key.start_with?("0x") ? nonce_key.to_i(16) : nonce_key.to_i
  end

  memo = method_details["memo"]
  memo ||= Attribution.encode(server_id: challenge.realm, client_id: @client_id, challenge_id: challenge.id)

  # Resolve RPC URL from challenge's chainId
  resolved_rpc_url = @rpc_url
  expected_chain_id = nil
  challenge_chain_id = method_details["chainId"]
  if challenge_chain_id
    begin
      parsed_chain_id = Integer(challenge_chain_id)
      resolved = Defaults::CHAIN_RPC_URLS[parsed_chain_id]
      if resolved
        resolved_rpc_url = resolved
        expected_chain_id = parsed_chain_id
      end
    rescue ArgumentError, TypeError
      # ignore
    end
  end

  expected_chain_id ||= @chain_id

  # Proof mode: sign EIP-712 typed data (no transaction needed)
  if mode == :proof
    chain_id = expected_chain_id || @chain_id
    raise ArgumentError, "chain_id required for proof mode" unless chain_id

    signature = Proof.sign(
      account: @account,
      chain_id: chain_id,
      challenge_id: challenge.id
    )

    return Mpp::Credential.new(
      challenge: challenge.to_echo,
      payload: {"type" => "proof", "signature" => signature},
      source: Proof.source(address: @account.address, chain_id: chain_id)
    )
  end

  raw_tx, chain_id = build_tempo_transfer(
    amount: request["amount"],
    currency: request["currency"],
    recipient: request["recipient"],
    nonce_key: nonce_key,
    memo: memo,
    rpc_url: resolved_rpc_url,
    expected_chain_id: expected_chain_id,
    awaiting_fee_payer: use_fee_payer
  )

  payload = if mode == :push
    tx_hash = Rpc.call(resolved_rpc_url, "eth_sendRawTransaction", [raw_tx])
    raise TransactionError, "No transaction hash returned" unless tx_hash
    {"type" => "hash", "hash" => tx_hash}
  else
    {"type" => "transaction", "signature" => raw_tx}
  end

  Mpp::Credential.new(
    challenge: challenge.to_echo,
    payload: payload,
    source: "did:pkh:eip155:#{chain_id}:#{@account.address}"
  )
end

#transform_request(request, _credential) ⇒ Object

Transform request - adds default methodDetails if needed.



132
133
134
# File 'lib/mpp/methods/tempo/client_method.rb', line 132

def transform_request(request, _credential)
  request
end