Class: Remitmd::A2AClient

Inherits:
Object
  • Object
show all
Defined in:
lib/remitmd/a2a.rb

Overview

A2A JSON-RPC client - send payments and manage tasks via the A2A protocol.

Examples:

card   = Remitmd::AgentCard.discover("https://remit.md")
signer = Remitmd::PrivateKeySigner.new(ENV["REMITMD_KEY"])
client = Remitmd::A2AClient.from_card(card, signer)
task   = client.send(to: "0xRecipient...", amount: 10)
puts task.status.state

Constant Summary collapse

CHAIN_IDS =
{
  "base"         => 8453,
  "base-sepolia" => 84_532,
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(endpoint:, signer:, chain_id:, verifying_contract: "") ⇒ A2AClient

Returns a new instance of A2AClient.

Parameters:

  • endpoint (String)

    full A2A endpoint URL from the agent card

  • signer (#sign, #address)

    a signer for EIP-712 authentication

  • chain_id (Integer)

    chain ID

  • verifying_contract (String) (defaults to: "")

    verifying contract address



157
158
159
160
161
162
163
164
165
166
167
# File 'lib/remitmd/a2a.rb', line 157

def initialize(endpoint:, signer:, chain_id:, verifying_contract: "")
  parsed    = URI(endpoint)
  @base_url = "#{parsed.scheme}://#{parsed.host}#{parsed.port == parsed.default_port ? "" : ":#{parsed.port}"}"
  @path     = parsed.path.empty? ? "/a2a" : parsed.path
  @transport = HttpTransport.new(
    base_url:       @base_url,
    signer:         signer,
    chain_id:       chain_id,
    router_address: verifying_contract
  )
end

Class Method Details

.from_card(card, signer, chain: "base", verifying_contract: "") ⇒ A2AClient

Convenience constructor from an AgentCard and a signer.

Parameters:

  • card (AgentCard)
  • signer (#sign, #address)
  • chain (String) (defaults to: "base")

    chain name (default: "base")

  • verifying_contract (String) (defaults to: "")

Returns:



175
176
177
178
179
180
181
182
183
# File 'lib/remitmd/a2a.rb', line 175

def self.from_card(card, signer, chain: "base", verifying_contract: "")
  chain_id = CHAIN_IDS[chain] || CHAIN_IDS["base"]
  new(
    endpoint:            card.url,
    signer:              signer,
    chain_id:            chain_id,
    verifying_contract:  verifying_contract
  )
end

Instance Method Details

#cancel_task(task_id) ⇒ A2ATask

Cancel an in-progress A2A task.

Parameters:

  • task_id (String)

Returns:



230
231
232
# File 'lib/remitmd/a2a.rb', line 230

def cancel_task(task_id)
  rpc("tasks/cancel", { id: task_id }, task_id[0, 16])
end

#get_task(task_id) ⇒ A2ATask

Fetch the current state of an A2A task by ID.

Parameters:

  • task_id (String)

Returns:



223
224
225
# File 'lib/remitmd/a2a.rb', line 223

def get_task(task_id)
  rpc("tasks/get", { id: task_id }, task_id[0, 16])
end

#send(to:, amount:, memo: "", mandate: nil, permit: nil) ⇒ A2ATask

Send a direct USDC payment via message/send.

Parameters:

  • to (String)

    recipient 0x address

  • amount (Numeric)

    amount in USDC

  • memo (String) (defaults to: "")

    optional memo

  • mandate (IntentMandate, nil) (defaults to: nil)

    optional intent mandate

Returns:



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/remitmd/a2a.rb', line 191

def send(to:, amount:, memo: "", mandate: nil, permit: nil)
  nonce      = SecureRandom.hex(16)
  message_id = SecureRandom.hex(16)

  data = {
    model:  "direct",
    to:     to,
    amount: format("%.2f", amount),
    memo:   memo,
    nonce:  nonce,
  }
  data[:permit] = permit_to_h(permit) if permit

  message = {
    messageId: message_id,
    role:      "user",
    parts: [
      {
        kind: "data",
        data: data,
      },
    ],
  }

  message[:metadata] = { mandate: mandate.to_h } if mandate

  rpc("message/send", { message: message }, message_id)
end