Sidecars

Witness

Distinguish transaction observation, exact-byte evidence and independently verified recipient credit.

0.4.0-alpha.2Alpha capabilityDeclared targets: Windows, Androiduk.capp.sidecar.solana-witness

What it does

Witness observes a recorded attempt, retains compact evidence and assembles receipts. It also provides an independent payment-verification path that reads transaction bytes and recipient balance changes against trusted saved request terms.

Use it to answer distinct questions: what state did the provider observe; is it the same signed transaction; did this recipient receive the requested payment? Those are different checks. A receipt object or a signature string alone does not answer all three.

Use independently

Select uk.capp.sidecar.solana-witness. Choose arena-peer for a labelled simulation, or conduit-peer for supported live observations. Use window.capp.solana.witness or the portable client.

Keep operation, attempt, signature, network and known digests together. Locally appended evidence and trace() do not need RPC, but they also do not turn caller-supplied claims into independently observed facts.

Provider dependencies

OperationDependencyWhat it proves
appendEvidence() / trace() / readReceipt()Local storeA retained local record or supplied evidence digest.
observe() / receipt() in arena-peerArenaA simulated recorded outcome, never a live payment.
observe() / receipt() in conduit-peerMatching ConduitOne RPC signature-status observation and a receipt assembled from it.
External observationConfigured HTTPS adapterIts explicitly live, matching observation; qualify that service separately.
transactionEvidence()conduit-peer, retained signed bytes and exact operation/attempt/signatureObserved transaction bytes match the recorded transaction.
verifyPayment()conduit-peer, trusted saved payment request and signatureSupported transaction/recipient-credit verification, not business fulfilment.

independentPaymentVerification in status describes an API capability; the selected mode still matters. Independent verification is not available through Arena or an arbitrary observer adapter. A generic receipt() may use supplied digest fields when the observation does not contain them; it is not equivalent to transactionEvidence() or verifyPayment().

First successful observation

  1. Start with a known saved Arena outcome or a real recorded signature on the intended live network.
  2. Call observe() once. Show unknown, submitted, confirmed, failed and finalised distinctly, including simulation status.
  3. Ask for receipt() when useful and check commitmentMet, commitment, finality and exact identity. A receipt can legitimately describe an unmet commitment.
  4. For exact submitted bytes, use transactionEvidence() with the retained signed transaction. For a merchant payment, use verifyPayment() with the merchant-owned request.
  5. Persist the resulting business decision separately. Witness does not claim an invoice, prevent another device from fulfilling it or deliver an order.

Read a simulated receipt without executing again

Copy the client module beside this module. First create a labelled simulation through Arena or Dispatch. Pass its retained operation and attempt IDs; this helper never calls execution or submission.

js
import {createSolanaClient} from './solana-client.mjs';
const client = createSolanaClient(() => window.capp?.solana);

export async function readArenaReceipt({operationId, attemptId}) {
  const status = await client.call('witness', 'status');
  if (!status.ready || status.providerMode !== 'arena-peer') {
    throw new Error('This example requires Witness backed by Arena');
  }
  const receipt = await client.call('witness', 'receipt', {operationId, attemptId, network: 'demo'});
  if (receipt.simulated !== true || receipt.operationId !== operationId || receipt.attemptId !== attemptId) {
    throw new Error('Receipt does not match this simulated attempt');
  }
  return receipt; // Inspect commitmentMet; existence is not success.
}

export async function verifySavedPayment(paymentRequest, signature) {
  const status = await client.call('witness', 'status');
  if (!status.ready || status.providerMode !== 'conduit-peer') {
    throw new Error('Independent payment verification requires Conduit');
  }
  return client.call('witness', 'verifyPayment', {
    paymentRequest, signature, commitment: 'confirmed'
  });
}

The second helper is a separate read-only live verification action, not a continuation of the Arena example. Its paymentRequest must come from your trusted saved request, not customer-supplied recipient/amount claims. A client-side successful result is useful to the UI; a merchant should verify at its trusted service boundary and record fulfilment durably. See independent payment verification.

What each evidence level establishes

ResultInspectDoes not establish
observe()Network, signature, observed state, error, simulation flagExact recipient/amount or success just because a signature exists.
receipt()Identity/digests, evidence list, commitmentMet, finality, simulationAuthenticity of an imported receipt or truth of arbitrary locally appended metadata.
transactionEvidence()wireVerified, expected/observed transaction digests, signature and bindingA merchant invoice/amount/recipient claim beyond the recorded bytes.
verifyPayment()paid, exact request digest, credited recipient, asset, atomic amount, reference, genesis, slot and commitmentDelivery, invoice claim uniqueness, or a cross-device business transaction.

Independent payment verification checks the supported payment's signatures/bytes, reference and optional memo, requested asset/amount and actual credited recipient balance, including token account identity. Sender-to-self movement is not accepted as the requested credit. It enforces the request's validity window against observed block time; request timestamps are seconds.

Token-2022, wrapped SOL, unknown/extra instructions and unsupported lookup-table layouts are rejected rather than accepted as approximate matches. Symbols/logos do not replace mint, program and decimals. paid: true remains accompanied by authorises: false and fulfilmentRecorded: false.

Scope and limitations

Independent payment verification reads RPC bytes and recipient balance changes against a trusted saved request. It does not trust imported receipts, fulfil an order or replace a merchant's durable invoice/signature claim. The RPC/provider remains part of the trust boundary; this is not a self-contained consensus/light-client proof.

Observation is a single query, not a subscription or wait-until-finalised operation. A missing historical signature returns unknown, not proof of failure. Poll deliberately with an application-level interval/budget and stop scheduling new reads when the view closes; do not invent a cancel() or event subscription API.

appendEvidence() keeps selected compact fields only, with a 16 KB payload bound and per-operation limits. A SHA-256 digest provides content identity, not authentication. receiptRetention: false still returns a receipt but does not make it available through a later local readReceipt(). With retention on, use the exact receiptDigest for a specific snapshot; a broad operation lookup can return a newer observation.

Application API

The owning interface is window.capp.solana.witness. The portable client calls the same methods. This table describes main arguments, not a stricter typed guarantee than the current provider implements. Exact transaction/provider bindings must be preserved; unsupported state or arguments are rejected.

js
import {createSolanaClient} from './solana-client.mjs';
const client = createSolanaClient(() => window.capp?.solana);
const status = await client.call('witness', 'status');

status

client.call('witness', 'status', input)

Main input: No arguments required.

Read observation-provider readiness, commitment and evidence capacity.

observe

client.call('witness', 'observe', input)

Main input: operationId, attemptId and/or signature with matching network and digests.

Observe a recorded attempt through the configured live or simulation provider. Returned evidence remains explicitly labelled.

appendEvidence

client.call('witness', 'appendEvidence', input)

Main input: operationId and bounded evidence payload; optional attempt identity.

Append compact local evidence with a digest. Locally supplied evidence is not automatically chain verification.

receipt

client.call('witness', 'receipt', input)

Main input: Recorded operation/attempt/signature binding.

Observe and assemble a receipt with matching evidence and commitment status.

readReceipt

client.call('witness', 'readReceipt', input)

Main input: operationId, signature or receiptDigest; optional attemptId.

Read a matching retained receipt. Missing identity or receipt is an error.

trace

client.call('witness', 'trace', input)

Main input: operationId.

Read the local evidence trace and count for an operation.

transactionEvidence

client.call('witness', 'transactionEvidence', input)

Main input: operationId, attemptId, network, signature, signedTransactionBase64; optional transactionDigest.

Obtain transaction evidence for the recorded bytes. Use the prepared Edge operation to retain the full binding.

verifyPayment

client.call('witness', 'verifyPayment', input)

Main input: paymentRequest, signature; optional commitment: confirmed or finalized.

Independently check trusted saved request terms against RPC bytes and credited recipient balance. Does not claim or fulfil an order.

Troubleshooting

Symptom or errorNext step
unknown observationQuery the same signature later or through your approved history provider. Do not send another payment.
commitmentMet: falseKeep the result pending at the requested commitment; simulation remains simulation.
TRANSACTION_PENDINGExact successful transaction bytes are not available yet; reconcile the same signature.
BINDINGPreserve the conflicting records and compare operation, attempt, network, signature and digests.
PAYMENT_PENDINGInspect whether the transaction is absent/pending or explicitly failed; do not treat the exception as a paid invoice.
RECEIPT_NOT_FOUNDCheck exact identifiers and retention settings; reading is not a new observation.
Unsupported payment layoutUse a supported payment request/transaction, not a permissive fallback parser.

Verify your integration

Test missing, processed, confirmed, finalised and failed observations; a changed signature; wrong recipient/amount/reference; self-transfer; and unsupported token/instruction layouts. Verify exact receipt lookup and disabled retention. Keep fulfilment in a separate durable service transaction that prevents the same payment/request from being claimed twice.

Integration recipes

Composition · Devnet payment · Recovery · Typed client · Schemas

These schemas describe payload shape, not evidence of approval or successful execution. Match the version in your payload; older versions remain listed for compatibility.

Configuration reference

These are the selected package's configuration fields. String credential values and installation-specific defaults are never published here. A field's presence does not bypass its runtime policy.

FieldTypeMeaning and constraints
providerModeselectSelect the implementation this build will use. Configuring an endpoint does not verify its connection or behavior.. Choices: arena-peer, conduit-peer, external-adapter
networkselectMust match the live provider and requests. Arena and demo confirmation always use simulation.. Choices: devnet, testnet, mainnet-beta, demo
commitmentselectTarget Solana commitment Witness should observe before considering the requested observation satisfied.. Choices: processed, confirmed, finalized
receiptRetentioncheckboxWhether compact receipts are retained locally after creation.
maxReceiptsnumberMaximum local records. At the limit, new records stop; existing history is preserved. Increase the limit or archive and reconcile the workspace.. Bounds: 1 to 2048
maxEvidenceItemsnumberMaximum local records. At the limit, new records stop; existing history is preserved. Increase the limit or archive and reconcile the workspace.. Bounds: 1 to 512
externalAdapterUrltextAbsolute HTTPS endpoint, or loopback HTTP for development. Keep private credentials on the backend; packaged configuration is visible to users.

Agent interfaces

These names are declared by the package for host/Agent integration, not JavaScript methods to invoke directly. The host must register a tool, grant its scope and enforce its approval policy. A manifest declaration alone does not prove availability in every Agent catalogue. Prefer the application API above when integrating your own app.

ToolDeclared riskApproval requirement
solana.witness.statuslowmode-policy

Component changelog

baseline0.4.0-alpha.2Permalink

Witness

Observe transactions and independently verify a saved payment request against the recipient’s credited balance.

Documentation snapshot, not a historical release date.
View component notes →
↑ ↓ to navigate · Enter to open · Esc to close. Search stays in your browser.