SolvaDocs

Connect a reserve source

How a custodian signs reserve balances, how Solva reads balances on chain, and how each kind of reserve source is connected today.

Each cycle, the orchestrator reads your reserve figures from your reserve source. With an attested source, the custodian signs each balance and the orchestrator checks the signature before it uses the figure. With a read on chain source, the orchestrator reads the balance of your Stellar accounts from the ledger. For how much each kind asks you to trust, see Where reserve figures come from.

Source types

SourceSetting valueHow the figure arrives
Attested (custodian-signed)attestedThe custodian's service signs each balance it reports.
Read on chainonchainThe orchestrator reads the balance of Stellar accounts from Horizon.

The public demo uses a mock custodian run by Solva for two example institutions, Kestrel Anchor and Solstice Exchange, so their figures are not real reserves. Its third example institution, Harbor Wallet, holds real Testnet USDC read on chain.

What the custodian signs

For each reserve account, the custodian's service answers GET {base}/v1/accounts/{account}/balance with a JSON body:

balance response
{
  "source_id": "acct-anchor",
  "balance": "8000000",
  "currency": "USD",
  "as_of": "2026-11-04T09:00:00Z",
  "signature": "MEUCIQ..."
}
FieldMeaning
source_idThe reserve account the figure belongs to.
balanceThe balance as a decimal string of integer minor units, such as cents.
currencyThe currency code of the balance.
as_ofThe time of the balance, in RFC 3339 format.
signatureThe custodian's signature over the other four fields, base64 encoded.

The signature covers a canonical payload: the four fields as compact JSON, keys in alphabetical order, with no signature field:

canonical payload
{
  "as_of": "2026-11-04T09:00:00Z",
  "balance": "8000000",
  "currency": "USD",
  "source_id": "acct-anchor"
}

The signature scheme

PartValue
CurveP-256 (secp256r1)
DigestSHA-256 over the canonical payload bytes
SignatureECDSA, ASN.1 DER encoding of (r, s), then base64
Key fileThe custodian's public key as a PEM (PKIX) file

How the orchestrator checks a balance

On every cycle the orchestrator:

  1. Authenticates to the source with an OAuth authorization code, when a client id is set, and gets a bearer token.
  2. Reads every configured reserve account in parallel.
  3. Rebuilds the canonical payload from each response and verifies the signature with the configured public key.
  4. Uses the figure only if the signature verifies.

A bad signature fails the whole cycle at once, and the orchestrator does not retry it. A network error or a 5xx answer from the source is retried up to three times with a growing delay. If any one account fails, no partial set of reserves is used.

The orchestrator checks the signature only. It does not check the age of as_of or the currency. Make sure every reserve figure and every customer balance use the same asset and the same minor unit, because the proof adds them up as plain numbers.

Connect an attested source

A reserve source is set in the orchestrator's configuration, not in the console. A tenant that is not routed to onchain (see Connect a read on chain source) uses the attested source. The engineer who runs the orchestrator sets these values and restarts it:

SettingValue
ORCH_RESERVE_BASE_URLThe base URL of the custodian's balance service.
ORCH_RESERVE_ACCOUNTSThe reserve account ids, comma separated. Up to 4 figures fit in one proof.
ORCH_RESERVE_PUBLIC_KEY_PEMThe custodian's P-256 public key, PEM encoded. The orchestrator refuses to start without it.
ORCH_RESERVE_CLIENT_IDThe OAuth client id the orchestrator presents. Leave it empty to send no token.

Get the custodian's public key as a PEM file and the ids of the accounts that hold your reserves.

Set the four settings above on the orchestrator.

export ORCH_RESERVE_BASE_URL="https://custody.example.com"
export ORCH_RESERVE_ACCOUNTS="acct-anchor,acct-beacon,acct-cedar"
export ORCH_RESERVE_PUBLIC_KEY_PEM="$(cat custodian-public-key.pem)"
export ORCH_RESERVE_CLIENT_ID="solva-orchestrator"

Restart the orchestrator. It reads the settings at start.

Run a cycle, as in Run cycles, and check that it returns 202.

One orchestrator holds one set of attested settings. Every institution that uses the attested source on that orchestrator reads the same accounts with the same key. Real custodian connections Coming soon give each institution its own.

Connect a read on chain source

An institution whose reserves sit in Stellar accounts uses the read on chain source. Two orchestrator settings route it. The example is Harbor Wallet's configuration in the demo:

ORCH_RESERVE_SOURCES="33333333-3333-3333-3333-333333333333=onchain"
ORCH_ONCHAIN_HOLDINGS="33333333-3333-3333-3333-333333333333=GCPBHMM7KSE74LO757SPKBE3PHWYRTKKKVBCVZURBFM6B2GSOPAJAR4R|USDC|GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
SettingValue
ORCH_RESERVE_SOURCESComma-separated TENANT_ID=attested or TENANT_ID=onchain entries. A tenant not listed uses attested.
ORCH_ONCHAIN_HOLDINGSComma-separated holdings, TENANT_ID=ADDRESS for XLM or TENANT_ID=ADDRESS|CODE|ISSUER for an issued asset. A tenant can list several accounts.
ORCH_ONCHAIN_HORIZON_URLThe Horizon server to read from. Defaults to https://horizon-testnet.stellar.org.

On every cycle the orchestrator reads each holding's account from Horizon in parallel and takes the balance of the named asset. Each balance becomes one reserve figure in the asset's seven-decimal unit, so 10 USDC is 100000000. Load customer balances in the same unit. A network error or a 5xx answer from Horizon is retried up to three times. An account that does not hold the named asset fails the cycle.

The orchestrator refuses to start if an entry is malformed, if an address is not a valid G... account, or if a tenant routed to onchain has no holdings.

Reserves read on chain move with the ledger. A proof is refused when reserves grow by more than 10 percent since the last record, so add funds in smaller steps.

Connect a source in the console

Console source connections Coming soon let each institution connect its own reserve sources. The console's Sources page has a Connect a source dialog with two choices:

  • Custodian account. Choose your custodian from a list, then authorize read-only access to account balances. Solva never moves funds and never sees transactions. You can revoke access at any time.
  • On-chain wallet. Give the source a display name and enter the Stellar address (G...) that holds the reserves.

Each connected source appears on the Sources page. The dialog runs with example custodians, and no cycle reads what it connects.

Result

The orchestrator reads your reserve accounts each cycle. From an attested source it uses only figures whose signatures verify. From a read on chain source it uses the balances the ledger shows.

Next: Load what is owed.

On this page