Class: Remitmd::CliSigner

Inherits:
Object
  • Object
show all
Includes:
Signer
Defined in:
lib/remitmd/cli_signer.rb

Overview

Signer backed by the remit sign CLI command.

No key material in this process -- signing happens in a subprocess. Address is cached at construction time via remit address.

Examples:

signer = Remitmd::CliSigner.new
wallet = Remitmd::RemitWallet.new(signer: signer, chain: "base")

Constant Summary collapse

CLI_TIMEOUT =

Default timeout for CLI subprocess calls (seconds).

10

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Signer

#sign_hash

Constructor Details

#initialize(cli_path: "remit") ⇒ CliSigner

Create a CliSigner, fetching and caching the wallet address.

Parameters:

  • cli_path (String) (defaults to: "remit")

    path or name of the remit CLI binary (default: "remit")

Raises:

  • (RemitError)

    if the CLI fails or returns an invalid address



25
26
27
28
# File 'lib/remitmd/cli_signer.rb', line 25

def initialize(cli_path: "remit")
  @cli_path = cli_path
  @address = fetch_address
end

Instance Attribute Details

#addressString (readonly)

The cached Ethereum address (0x-prefixed).

Returns:

  • (String)


61
62
63
# File 'lib/remitmd/cli_signer.rb', line 61

def address
  @address
end

Class Method Details

.available?(cli_path: "remit") ⇒ Boolean

Check conditions for CliSigner activation.

  1. CLI binary found on PATH (via which / where)
  2. Meta file at ~/.remit/keys/default.meta (keychain — no password needed), OR
  3. Keystore file at ~/.remit/keys/default.enc AND REMIT_SIGNER_KEY env var set

Parameters:

  • cli_path (String) (defaults to: "remit")

    path or name of the remit CLI binary

Returns:

  • (Boolean)


78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/remitmd/cli_signer.rb', line 78

def self.available?(cli_path: "remit")
  # 1. CLI binary on PATH
  which_cmd = Gem.win_platform? ? "where" : "which"
  _out, _err, st = Open3.capture3(which_cmd, cli_path)
  return false unless st.success?

  keys_dir = File.join(Dir.home, ".remit", "keys")

  # 2. Keychain meta file — no password needed
  return true if File.exist?(File.join(keys_dir, "default.meta"))

  # 3. Encrypted keystore + password
  keystore = File.join(keys_dir, "default.enc")
  return false unless File.exist?(keystore)

  password = ENV["REMIT_SIGNER_KEY"] || ENV["REMIT_KEY_PASSWORD"]
  return false if password.nil? || password.empty?

  true
end

Instance Method Details

#inspectObject Also known as: to_s

Never expose internals in inspect/to_s output.



64
65
66
# File 'lib/remitmd/cli_signer.rb', line 64

def inspect
  "#<Remitmd::CliSigner address=#{@address}>"
end

#sign(digest_bytes) ⇒ String

Sign a 32-byte digest (raw binary bytes). Pipes the hex-encoded digest to remit sign --digest on stdin. Returns a 0x-prefixed 65-byte hex signature.

Parameters:

  • digest_bytes (String)

    32-byte binary digest

Returns:

  • (String)

    0x-prefixed 130-char hex signature (65 bytes)

Raises:

  • (RemitError)

    on CLI failure or invalid output



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/remitmd/cli_signer.rb', line 37

def sign(digest_bytes)
  hex = digest_bytes.unpack1("H*")
  stdout, stderr, status = run_cli("sign", "--digest", stdin_data: hex)

  unless status.success?
    raise RemitError.new(
      RemitError::SERVER_ERROR,
      "CliSigner: signing failed: #{stderr.strip}"
    )
  end

  sig = stdout.strip
  unless sig.start_with?("0x") && sig.length == 132
    raise RemitError.new(
      RemitError::SERVER_ERROR,
      "CliSigner: invalid signature from CLI: #{sig}"
    )
  end

  sig
end