Skip to content

Verify a Wallet Signed Transaction in Rails

pzupan edited this page Jul 5, 2026 · 1 revision

Verify a Wallet-Signed Transaction in Rails

Server-side handling of the Wallet Standard signTransaction interface. A browser wallet (Phantom, Backpack, Solflare, …) signs a transaction and returns wire bytes; Rails decodes those bytes and verifies every Ed25519 signature without broadcasting — because Solana addresses are Ed25519 public keys, no additional key lookup is required.

# app/controllers/payments_controller.rb
require 'base64'

WS = Solana::Ruby::Kit::WalletStandard
TX = Solana::Ruby::Kit::Transactions

class PaymentsController < ApplicationController
  # POST /payments/verify
  # Body: { signed_transaction: "<base64 wire bytes from wallet>" }
  def verify
    wire_bytes = Base64.strict_decode64(params[:signed_transaction])

    # 1. Decode the wallet output and verify every present signature.
    #    Raises WalletStandard::SIGNATURE_VERIFICATION_FAILED on any mismatch.
    tx = WS.verify_signed_transaction!(wire_bytes)

    # 2. Assert all required signers have signed (no nil slots remain).
    TX.assert_fully_signed_transaction!(tx)

    # 3. Confirm the expected wallet address actually signed.
    wallet_address = Solana::Ruby::Kit::Addresses::Address.new(params[:wallet_address])
    render json: { error: 'wrong signer' }, status: :unprocessable_entity and return \
      unless WS.signed_by?(tx, wallet_address)

    # 4. Optionally broadcast through your own RPC node instead of the browser.
    rpc      = Solana::Ruby::Kit.rpc_client
    wire_b64 = Base64.strict_encode64(TX.wire_encode_transaction(tx))
    sig      = rpc.send_transaction(wire_b64, encoding: 'base64')

    render json: { signature: sig.value }
  rescue Solana::Ruby::Kit::SolanaError => e
    render json: { error: e.message, code: e.code }, status: :unprocessable_entity
  end
end

Wallet Standard feature constants

Use these when building frontend metadata or documenting required wallet capabilities:

WS = Solana::Ruby::Kit::WalletStandard

WS::SIGN_TRANSACTION          # => 'solana:signTransaction'
WS::SIGN_AND_SEND_TRANSACTION # => 'solana:signAndSendTransaction'
WS::SIGN_MESSAGE              # => 'solana:signMessage'
WS::CONNECT                   # => 'standard:connect'

See also: Build a Transaction for Browser Signing for the server-side counterpart that produces the unsigned transaction this controller verifies.


← Back to guides

Clone this wiki locally