Gateway API Reference¶
This document describes the gRPC API exposed by the Almanak Gateway.
Services Overview¶
| Service | Methods | Description |
|---|---|---|
| Health | 3 | Standard gRPC health checks and chain registration |
| MarketService | 10 | Price data, provider-exact reference prices, Pendle PT/YT-USD price, balances, batch balances, technical indicators, Uniswap V4 pool key lookup, and verified lending/perpetual-market resolution |
| StateService | 31 | Strategy state persistence, portfolio snapshots/metrics, transaction ledger, accounting events, position events, accounting outbox, atomic ledger+registry writes, and cutover migration state |
| ExecutionService | 3 | Intent compilation and transaction execution |
| ObserveService | 4 | Logging, alerts, metrics, and timeline events |
| RpcService | 7 | JSON-RPC proxy to blockchains with typed queries |
| IntegrationService | 14 | Third-party data (Binance, CoinGecko, TheGraph, CoinGecko Onchain, Zerion) |
| DashboardService | 22 | Operator dashboard data, actions, transaction ledger, PnL/cost stack, audit posture, trade tape, activity feed, positions, reconciliation report, and operator reconciliation actions |
| FundingRateService | 2 | Perpetual funding rates and spreads |
| SimulationService | 1 | Transaction bundle simulation (Tenderly/Alchemy) |
| PoolAnalyticsService | 2 | DEX pool analytics (TVL, volume, fees) + product-distinct token-pool listing |
| PoolHistoryService | 1 | Historical pool snapshots (TVL, volume, fees over time). Disabled by default; hosted rollout enables via ALMANAK_GATEWAY_POOL_HISTORY_ENABLED=true deployment config |
| RateHistoryService | 12 | Lending APY (live + historical), perp funding and venue-native index-price history, DEX TWAP (single + series), exact-pool state series, DEX LWAP (liquidity-weighted spot), DEX volume history, gas prices, and provider-exact oracle prices (current + historical). Strategy-side RateMonitor / backtesting rate providers are thin gRPC clients of this service. |
| PolymarketService | 20 | Polymarket CLOB API proxy (market data, orders, positions, price history, trade tape) |
| EnsoService | 4 | Enso Finance routing and bundling |
| TokenService | 4 | Token resolution and on-chain metadata |
| LifecycleService | 6 | Agent state management, heartbeat, and commands |
| TeardownService | 23 | Hosted teardown state routing (V2 deployments): teardown requests, execution state, and operator approvals |
| PositionService | 1 | Position registry reconciliation against on-chain truth (T24 / VIB-4210) |
| PerpFillService | 3 | Executed perp fills, funding settlements, and single-order status (by cloid) for a wallet; backs the perp accounting path and the fill-reconciliation reject-detection pump (VIB-5595 / VIB-5616) |
Health¶
Check¶
Check if the service is healthy (liveness probe).
Watch¶
Watch for health status changes (streaming readiness probe).
RegisterChains¶
Pre-initialize execution orchestrators and compilers for specified chains. Call this at startup to warm up chain-specific resources.
Request:
message RegisterChainsRequest {
repeated string chains = 1; // Chain names to pre-initialize (e.g., "arbitrum", "base")
string wallet_address = 2; // Wallet address for orchestrator initialization
}
Response:
message RegisterChainsResponse {
bool success = 1;
repeated string initialized_chains = 2; // Chains successfully initialized
string wallet_address = 3; // Wallet address derived from gateway private key
string error = 4;
map<string, string> chain_wallets = 5; // Per-chain wallet addresses resolved from wallet registry
}
MarketService¶
GetPrice¶
Get the current price of a token.
Request:
message PriceRequest {
string token = 1; // Token symbol or address
string quote = 2; // Quote currency (default: "USD")
}
Response:
message PriceResponse {
string price = 1; // Decimal as string (precision preserved)
int64 timestamp = 2;
string source = 3;
double confidence = 4; // 0.0-1.0
bool stale = 5;
}
Example:
from almanak.framework.data.price import GatewayPriceOracle
oracle = GatewayPriceOracle(gateway_client)
price = await oracle.get_price("ETH", "USD")
GetReferencePrice¶
Get a named non-crypto reference price from one gateway-verified feed. Unlike
GetPrice, this RPC never aggregates same-symbol crypto assets. The gateway
owns the exact feed selection, provider timestamp and heartbeat evaluation, and
reference-market session status. Unsupported pairs and unavailable, malformed,
stale, or errored observations fail closed without a numeric price.
Request:
message ReferencePriceRequest {
string instrument = 1; // e.g. XAU
string quote = 2; // USD only in the initial contract
string chain = 3; // Chain hosting the verified feed
}
Response:
message ReferencePriceResponse {
string instrument = 1;
string quote = 2;
string chain = 3;
string price = 4; // Empty when unavailable; never "0" as a sentinel
ReferencePriceAvailability availability = 5;
double confidence = 6;
string source = 7; // Provider, pair, and verified feed address
int64 observed_at = 8; // Provider updatedAt, not gateway wall clock
bool stale = 9; // Evaluated against the provider heartbeat
ReferenceMarketStatus market_status = 10;
int64 market_status_as_of = 11;
string market_status_source = 12;
string reason = 13;
}
Availability and market status:
enum ReferencePriceAvailability {
REFERENCE_PRICE_AVAILABILITY_UNSPECIFIED = 0;
REFERENCE_PRICE_AVAILABILITY_AVAILABLE = 1;
REFERENCE_PRICE_AVAILABILITY_UNMEASURED = 2;
REFERENCE_PRICE_AVAILABILITY_ERRORED = 3;
}
enum ReferenceMarketStatus {
REFERENCE_MARKET_STATUS_UNSPECIFIED = 0;
REFERENCE_MARKET_STATUS_OPEN = 1;
REFERENCE_MARKET_STATUS_CLOSED = 2;
REFERENCE_MARKET_STATUS_UNKNOWN = 3;
}
Only REFERENCE_PRICE_AVAILABILITY_AVAILABLE carries a measured price. Clients
must also enforce their own maximum age and require an open reference market
before using the observation to authorize a trade.
GetPtPrice¶
Get the composed USD price of a Pendle PT (Principal Token) or YT (Yield Token).
The gateway is the price authority: PT/USD is composed gateway-side as
pt_to_asset_rate × underlying/USD (it is not fetched from a direct Pendle feed).
The PT/YT symbol is the canonical identity and cross-boundary join key.
Request:
message PtPriceRequest {
string symbol = 1; // Canonical PT/YT symbol — the identity + join key
string chain = 2;
string quote = 3; // Quote currency (default: "USD")
int64 maturity_ts = 4; // Optional maturity hint; 0 = gateway resolves it
}
Response:
message PtPriceResponse {
string symbol = 1;
string chain = 2;
string quote = 3;
string price = 4; // Decimal as string; ABSENT (empty) when unmeasured — never "0"
PtPriceAvailability availability = 5; // Wire-level Empty != Zero (see below)
double confidence = 6; // 0.0-1.0
PtPriceConfidenceBand confidence_band = 7; // Coarse band — combine with `stale` (field 12) for ValueConfidence
string underlying_price = 8; // Composition transparency (optional)
string pt_to_asset_rate = 9; // Composition transparency (optional)
string source = 10; // e.g. "composition:getPtToAssetRate×<oracle>"
int64 timestamp = 11;
bool stale = 12;
int64 maturity_ts = 13;
int32 days_to_maturity = 14;
}
Availability (Empty ≠ Zero): price is a measured number only when
availability == AVAILABLE. Any other state carries an empty price string — never
the literal "0" (which would be a measured zero). Consumers gate on availability,
not on string emptiness, and must treat the zero-value enum as unmeasured (fail closed):
enum PtPriceAvailability {
PT_PRICE_AVAILABILITY_UNSPECIFIED = 0; // old gateway / unknown -> UNMEASURED (fail closed)
PT_PRICE_AVAILABILITY_AVAILABLE = 1; // composed OK -> price is MEASURED
PT_PRICE_AVAILABILITY_UNMEASURED = 2; // expected: PT not priceable + no composition leg -> NO price
PT_PRICE_AVAILABILITY_ERRORED = 3; // a read raised -> NO price
}
enum PtPriceConfidenceBand {
PT_PRICE_CONFIDENCE_BAND_UNSPECIFIED = 0; // old gateway / unknown -> UNAVAILABLE
PT_PRICE_CONFIDENCE_BAND_HIGH = 1; // all inputs measured
PT_PRICE_CONFIDENCE_BAND_ESTIMATED = 2; // a fallback was used (e.g. rate defaulted at-par)
PT_PRICE_CONFIDENCE_BAND_UNAVAILABLE = 3; // cannot be valued
}
Confidence band ≠ ValueConfidence (not 1:1): PtPriceConfidenceBand carries only
the three origination bands (HIGH / ESTIMATED / UNAVAILABLE). The framework
ValueConfidence enum has a fourth member, STALE, which is not a band here —
staleness is carried separately by the stale bool (field 12). Consumers MUST combine
confidence_band and stale to derive the final ValueConfidence; mapping
band→enum directly would silently render a stale price as HIGH and drop the staleness
signal.
GetBalance¶
Get token balance for a wallet.
Request:
message BalanceRequest {
string token = 1; // Token symbol or address
string chain = 2;
string wallet_address = 3;
}
Response:
message BalanceResponse {
string balance = 1; // Human-readable units as string
string balance_usd = 2;
string address = 3;
int32 decimals = 4;
string raw_balance = 5; // Wei/raw units as string
int64 timestamp = 6;
bool stale = 7;
string error = 8;
}
BatchGetBalances¶
Get token balances across multiple chains in a single call.
Request:
Response:
GetIndicator¶
Calculate a technical indicator.
LookupV4PoolKey¶
Resolve a Uniswap V4 bytes32 pool id back to its structured PoolKey. Useful for receipt parsers and indexers that observe on-chain events whose log payload carries the bytes32 id rather than the structured key. The gateway populates the cache from observed PoolManager.Initialize events; unknown ids return NOT_FOUND.
ListLendingMarkets¶
Verified lending-market resolution (VIB-5985), Morpho-first via the connector-owned GatewayLendingMarketDiscoveryCapability — no protocol branches in the servicer; an unsupported protocol returns INVALID_ARGUMENT listing the supported ones. Returns ALL curated-catalog CANDIDATES matching the filters (paginated). It NEVER ranks or auto-picks: zero matches is an explicit empty page the caller must treat as an error to act on, and multiple matches means the caller chooses. Token filters are address-resolved before matching (symbols are spoofable). Candidate records are verified=false / source=CURATED_CATALOG — the curated catalog is a candidate source, not proof; verify a chosen id with GetLendingMarket before pinning it into a config.
Request:
message ListLendingMarketsRequest {
string protocol = 1; // connector slug (e.g. "morpho_blue")
string chain = 2;
string collateral_token = 3; // symbol OR address; empty = no filter
string loan_token = 4; // symbol OR address; empty = no filter
int64 lltv_bps = 5; // exact LLTV filter in bps; 0 = no filter
int32 page_size = 6; // 0 = server default
string page_token = 7; // opaque continuation token; empty = first page
}
Response:
message ListLendingMarketsResponse {
repeated LendingMarket markets = 1; // ALL matches on this page; never auto-ranked
string next_page_token = 2; // empty when this is the last page
int32 total_matches = 3; // total matches across all pages
bool success = 4;
string error = 5;
}
GetLendingMarket¶
Verifies one exact market_id on-chain. The gateway reads idToMarketParams(id) through its own RPC path, RECOMPUTES the market id from the returned params (keccak of the params tuple, exactly as the protocol defines it) and compares it to the requested id. Only a match returns verified=true / source=ONCHAIN_VERIFY; a recompute mismatch is a hard INVALID_ARGUMENT error and a non-existent market is NOT_FOUND — never a fabricated record. This is the only surface that may promote a market_id into a config. Immutable market params only (tokens, oracle, IRM, LLTV) — live supply/borrow state is out of scope.
Request:
message GetLendingMarketRequest {
string protocol = 1;
string chain = 2;
string market_id = 3; // exact bytes32 hex to verify on-chain
}
Response:
message LendingMarketResponse {
LendingMarket market = 1; // populated only when success && verified
bool success = 2;
string error = 3;
}
The shared LendingMarket message (Empty ≠ Zero: string fields absent when unresolvable, never fabricated):
message LendingMarket {
LendingMarketKind kind = 1; // Morpho = ISOLATED_PAIR
string protocol = 2;
string chain = 3;
string market_id = 4;
string collateral_token = 5; // address; absent if n/a
string collateral_symbol = 6; // absent when unresolvable
string loan_token = 7;
string loan_symbol = 8;
int64 lltv_bps = 9; // 9150 = 91.5%
string oracle = 10;
string irm = 11;
bool verified = 12; // true only after on-chain recompute+compare
LendingMarketSource source = 13;
}
GetPerpMarket¶
Resolves one perpetual market through the connector-owned discovery capability and
verifies its market/index/long/short token tuple on-chain before returning it. Exact
market addresses and connector-defined labels are accepted. An unknown market returns
NOT_FOUND; unsupported routing or ambiguous/unverified metadata fails closed.
Request:
message GetPerpMarketRequest {
string protocol = 1; // connector slug (for example, "gmx_v2")
string chain = 2;
string market = 3; // canonical label, full venue name, or exact address
}
Response:
message PerpMarketResponse {
PerpMarket market = 1; // populated only after on-chain tuple verification
bool success = 2;
string error = 3;
}
message PerpMarket {
string protocol = 1;
string chain = 2;
string label = 3;
string market_token = 4;
string index_token = 5;
string index_symbol = 6;
int32 index_token_decimals = 7;
string long_token = 8;
string long_token_symbol = 9;
string short_token = 10;
string short_token_symbol = 11;
bool verified = 12;
}
StateService¶
LoadState¶
Load strategy state from storage.
Request:
Response:
message StateData {
string deployment_id = 1;
int64 version = 2;
bytes data = 3; // JSON-serialized state
int32 schema_version = 4;
string checksum = 5; // SHA-256 hex
int64 created_at = 6;
int64 updated_at = 7;
string loaded_from = 8; // "hot", "warm"
}
SaveState¶
Save strategy state to storage.
Request:
message SaveStateRequest {
string deployment_id = 1;
int64 expected_version = 2; // For optimistic locking (0 = new state)
bytes data = 3; // JSON-serialized state
int32 schema_version = 4;
}
Response:
message SaveStateResponse {
bool success = 1;
int64 new_version = 2;
string error = 3;
string checksum = 4;
}
DeleteState¶
Delete strategy state.
SavePortfolioSnapshot¶
Save a portfolio snapshot for tracking valuation over time.
GetLatestSnapshot¶
Get the most recent portfolio snapshot.
GetSnapshotsSince¶
Get all portfolio snapshots since a given timestamp.
SavePortfolioMetrics¶
Legacy update lane for an already-established metrics row. An omitted positions field preserves that row's complete stored list. A present markerless full list may replace only an existing markerless row when the initial value is identical; it cannot touch a sealed row. Neither shape can establish a row or add/remove provenance. Provenance-bearing requests are rejected and current sealed clients use the version-fenced method below.
SavePortfolioMetricsWithProvenance¶
Version-fenced save for a metrics baseline carrying immutable provenance. A
client first checks PortfolioMetricsData.baseline_provenance_supported; an
older gateway cannot dispatch this RPC and returns UNIMPLEMENTED without
entering the legacy mutation handler. Every first row must carry exactly one
valid provenance record.
GetPortfolioMetrics¶
Retrieve stored portfolio metrics.
SaveLedgerEntry¶
Persist a single structured trade record to the transaction ledger.
Request:
message SaveLedgerEntryRequest {
string id = 1; // UUID primary key (idempotent ON CONFLICT target)
string cycle_id = 2;
string deployment_id = 3;
string deployment_id = 4;
string execution_mode = 5; // "live" | "paper" | "dry_run"
int64 timestamp = 6; // Unix epoch seconds
string intent_type = 7;
string token_in = 8;
string amount_in = 9; // Decimal string
string token_out = 10;
string amount_out = 11; // Decimal string
string effective_price = 12; // Decimal string, "" when not applicable
optional double slippage_bps = 13;
int64 gas_used = 14;
string gas_usd = 15; // Decimal string, "" when unknown
string tx_hash = 16;
string chain = 17;
string protocol = 18;
bool success = 19;
string error = 20;
bytes extracted_data_json = 21; // Serialised extracted_data dict
}
Response:
GetLedgerEntry¶
Retrieve a single ledger entry by id (for re-derivation and audit lookups).
SumLedgerGasUsd¶
Sum transaction_ledger.gas_usd across a deployment for the
portfolio_metrics.gas_spent_usd aggregate (VIB-4247). The gateway performs the
read because hosted strategy containers cannot access Postgres directly.
GetLedgerEntriesMeasured¶
Read a deployment's transaction_ledger rows WITH a measured backend_status
signal (VIB-5416). The teardown swap-back clamp folds NO_ACCOUNTING ledger rows
(STAKE→wstETH, WRAP→WETH, CDP MINT→stablecoin — primitives that write a ledger row
but no accounting event) into its tracked inventory. Mirrors GetAccountingEvents'
Empty ≠ Zero contract: an ABSENT/ERRORED/UNSPECIFIED status is UNMEASURED, so
the clamp drops the NO_ACCOUNTING lane (the token strands — the safe under-sweep
direction) rather than treating an empty read as measured-zero. limit=0 means
full history. Read-only; no stored column.
rpc GetLedgerEntriesMeasured(GetLedgerEntriesMeasuredRequest) returns (GetLedgerEntriesMeasuredResponse)
SaveAccountingEvent¶
Persist a typed accounting event (Layer 5 accounting). Writers must route through
the accounting outbox; direct calls from connectors or the runner hot path are
forbidden (see docs/internal/blueprints/27-accounting.md).
GetAccountingEvents¶
Retrieve typed accounting events for a strategy or ledger entry.
HasAccountingEventsForLedger¶
Idempotency check: returns whether typed events already exist for a given ledger entry (used by the outbox processor to avoid double-writes).
rpc HasAccountingEventsForLedger(HasAccountingEventsForLedgerRequest) returns (HasAccountingEventsForLedgerResponse)
SavePositionEvent¶
Persist an LP or perp position lifecycle event (open/close/collect-fees).
Lending intents (SUPPLY, BORROW, REPAY, WITHDRAW) are intentionally
not routed through this RPC — lending positions are fungible (no stable
position_id) and are tracked via Layer 5 typed accounting events instead.
SavePositionStateSnapshots¶
Persist per-iteration position state snapshots (tied to a parent
portfolio_snapshots.id, one row per open position). Backs accountant cells
G14 / G15 / L2 / L3 / L5. Non-blocking writes — logged and swallowed in
non-live modes; raises AccountingPersistenceError in live via the runner's
mode-aware caller. The hosted Postgres path returns UNIMPLEMENTED until the
metrics-database migration adds position_state_snapshots (PRD T-DRAFT-25,
Infra-owned).
rpc SavePositionStateSnapshots(SavePositionStateSnapshotsRequest) returns (SavePositionStateSnapshotsResponse)
GetPositionHistory¶
Retrieve the lifecycle event history for a single position.
UpdatePositionAttribution¶
Update lot-level attribution metadata (FIFO matching policy results) on an existing position event.
rpc UpdatePositionAttribution(UpdatePositionAttributionRequest) returns (UpdatePositionAttributionResponse)
SaveOutboxEntry¶
Enqueue a typed-event payload onto the accounting outbox for the async processor (VIB-3467).
GetOutboxEntry¶
Read a single outbox entry by id.
GetOutboxPending¶
Fetch the next batch of pending outbox entries for the processor to drain.
UpdateOutboxEntry¶
Mark an outbox entry as processed, failed, or retry-pending.
SaveLedgerAndRegistry¶
Atomic single-transaction commit of transaction_ledger, position_registry, and (when
supplied) the position handle mapping. Replaces the legacy SaveLedgerEntry →
SavePositionEvent sequence with a single atomic write so a gateway crash between rows
cannot orphan a registry handle or strand a phantom position (GH bug #2130).
Wire mode field (SaveLedgerAndRegistryRequest.mode):
| Wire value | Behavior |
|---|---|
"" (proto3 default) |
Equivalent to "commit". Backwards-compatible for clients that don't set the field. |
"commit" |
Full atomic three-write: ledger INSERT + registry UPSERT + handle backfill. |
"registry_reconciliation" |
Registry UPSERT + handle backfill only — ledger is NOT touched. Used exclusively by PositionService.Reconcile when apply=true. Writing a synthesized ledger row on this path would pollute the immutable intent history (reconciliation discovers chain-only positions with no corresponding intent). |
Any other value (including the framework-side CommitMode Literal values
"accounting_only" and "registry") is rejected with INVALID_ARGUMENT. The Python
framework wrapper (almanak/framework/accounting/commit.py:save_ledger_and_registry)
exposes a higher-level CommitMode = Literal["accounting_only", "registry",
"registry_reconciliation"] API where "accounting_only" is routed through
SaveLedgerEntry instead and "registry" is translated to the wire's "commit".
Ticket: VIB-4197 (local SQLite) / VIB-4205 / T19 (hosted Postgres) / VIB-4210 / T24 (reconciliation mode). See Blueprint 28 §4.
UpsertMigrationState¶
Insert or update the migration_state row for a (deployment_id, primitive, cutover_key)
tuple. Drives the registry-mode cutover boot guard (Blueprint 06 §"Migration State Table").
Part of T22 / VIB-4208 (SQLite half).
GetMigrationState¶
Read the current migration_state row for a (deployment_id, primitive, cutover_key).
Returns null when no row exists — interpreted as "cutover not yet deployed for this
surface" (raises RegistryCutoverNotDeployedError at boot if mode='registry' write is
attempted).
UpdateMigrationState¶
Partial-update of a migration_state row (e.g. recording backfill progress, watermarks).
Distinct from MarkBackfillComplete which is the terminal one-shot flip.
MarkBackfillComplete¶
One-shot atomic flip of the migration_state.complete flag from 0 to 1. Gates the
boot guard against RegistryBackfillIncompleteError: until this RPC fires for a surface,
registry-mode writes are refused in all execution modes (live, paper, dry_run).
GetPositionEventsFiltered¶
Read position_events rows filtered by (deployment_id, primitive, opened_after_block,
status, …). Used by the cutover backfill job to project historical position lifecycle
into position_registry. Distinct from GetPositionHistory which targets a single
position lifecycle.
rpc GetPositionEventsFiltered(GetPositionEventsFilteredRequest) returns (GetPositionEventsFilteredResponse)
GetPositionRegistryOpenRows¶
Enumerate currently-open rows in position_registry for a (deployment_id, chain,
primitive) tuple. Used by PositionService.Reconcile to compute the diff vs on-chain
truth, and by the cutover backfill job to detect duplicates before insert.
rpc GetPositionRegistryOpenRows(GetPositionRegistryOpenRowsRequest) returns (GetPositionRegistryOpenRowsResponse)
ExecutionService¶
CompileIntent¶
Compile a strategy intent into an action bundle.
Request:
message CompileIntentRequest {
string intent_type = 1; // Case-insensitive with aliases: "swap", "lp_open", etc.
bytes intent_data = 2; // JSON-serialized intent
string chain = 3;
string wallet_address = 4;
map<string, string> price_map = 5; // Token symbol -> USD price string (empty = use placeholder prices)
}
Response:
message CompilationResult {
bool success = 1;
bytes action_bundle = 2; // JSON-serialized ActionBundle
string error = 3;
string error_code = 4; // Structured error code
}
Execute¶
Execute an action bundle (sign, submit, confirm).
GetTransactionStatus¶
Get the status of a submitted transaction.
ObserveService¶
Log¶
Send log entries to the platform.
Alert¶
Send an alert to configured channels (Slack, Telegram).
Request:
message AlertRequest {
string severity = 1; // info, warning, error, critical
string title = 2;
string message = 3;
string deployment_id = 4;
}
RecordMetric¶
Record a custom metric.
RecordTimelineEvent¶
Record a timeline event for a strategy (trades, rebalances, errors, state changes).
Request:
message RecordTimelineEventRequest {
string deployment_id = 1;
string event_type = 2; // "TRADE", "REBALANCE", "ERROR", "STATE_CHANGE", etc.
string description = 3;
string tx_hash = 4; // Optional: transaction hash
string chain = 5; // Optional: chain name
string details_json = 6; // Optional: JSON-encoded details
int64 timestamp = 7; // Optional: uses server time if 0
}
Response:
RpcService¶
Call¶
Make a single JSON-RPC call to a blockchain.
Request:
message RpcRequest {
string chain = 1; // Must be in allowed list
string method = 2; // Must be in allowed list
string params = 3; // JSON-encoded params
string id = 4;
}
Response:
message RpcResponse {
bool success = 1;
string result = 2; // JSON-encoded result
string error = 3; // JSON-encoded error
string id = 4;
}
Allowed Chains:
EVM chains:
- ethereum, arbitrum, base, optimism, polygon, avalanche, bsc, bnb, sonic, plasma, linea, blast, mantle, berachain, monad, xlayer, zerog, hyperevm, robinhood
Non-EVM chains:
- solana
Allowed Methods (EVM):
- eth_call
- eth_getBalance
- eth_getTransactionCount
- eth_getTransactionReceipt
- eth_getBlockByNumber
- eth_getBlockByHash
- eth_blockNumber
- eth_chainId
- eth_gasPrice
- eth_estimateGas
- eth_getLogs
- eth_getCode
- eth_getStorageAt
- eth_sendRawTransaction
- net_version
Allowed Methods (Solana):
- getBalance
- getTokenAccountsByOwner
- getTokenAccountBalance
- getTransaction
- getSignaturesForAddress
- getAccountInfo
- getMultipleAccounts
- getLatestBlockhash
- getSlot
- getBlockHeight
- getEpochInfo
- getMinimumBalanceForRentExemption
- sendTransaction
- simulateTransaction
- getRecentPrioritizationFees
- isBlockhashValid
Blocked Methods:
- debug_* - Debugging methods
- admin_* - Admin methods
- personal_* - Personal key management
- miner_* - Mining control
- txpool_* - Transaction pool access
BatchCall¶
Make multiple JSON-RPC calls in parallel.
Request:
QueryAllowance¶
Query ERC-20 token allowance (typed convenience method).
Solana: Returns allowance = MAX_UINT64 and success = true. SPL tokens don't use ERC-20-style allowances.
QueryBalance¶
Query token balance (typed convenience method).
Solana: Returns an error directing callers to use MarketService.GetBalance() instead, which routes to the Solana-native balance provider.
QueryPositionLiquidity¶
Query LP position liquidity (typed convenience method).
Solana: Returns "not applicable for Solana". Solana LP positions use different on-chain structures.
QueryPositionTokensOwed¶
Query tokens owed to an LP position (typed convenience method).
Solana: Returns "not applicable for Solana".
QueryV4PositionState¶
Read live Uniswap V4 LP position state on-chain for HIGH-confidence valuation
(VIB-5024). Performs read-only eth_calls against connector-supplied addresses:
PositionManager.getPositionLiquidity / getPoolAndPositionInfo,
StateView.getSlot0, and — for V3-parity uncollected fees —
StateView.getPositionInfo / getFeeGrowthInside. Returns success=False on any
partial / inconsistent read so the valuer falls back to the ESTIMATED tier rather
than ever emitting an incomplete HIGH value (the never-wrong-HIGH guarantee).
Solana: Returns "not applicable for Solana".
IntegrationService¶
BinanceGetTicker¶
Get 24-hour ticker data from Binance.
Request:
Response:
message BinanceTickerResponse {
string symbol = 1;
string price = 2;
string price_change = 3;
string price_change_percent = 4;
string high_24h = 5;
string low_24h = 6;
string volume_24h = 7;
string quote_volume_24h = 8;
int64 timestamp = 9;
}
BinanceGetKlines¶
Get candlestick/kline data from Binance.
Request:
message BinanceKlinesRequest {
string symbol = 1;
string interval = 2; // 1m, 5m, 15m, 1h, 4h, 1d, etc.
int32 limit = 3; // Max 1000
int64 start_time = 4;
int64 end_time = 5;
}
BinanceGetOrderBook¶
Get order book depth from Binance.
CoinGeckoGetPrice¶
Get token price from CoinGecko.
Request:
message CoinGeckoGetPriceRequest {
string token_id = 1; // e.g., "bitcoin", "ethereum"
repeated string vs_currencies = 2; // e.g., ["usd", "eur"]
}
CoinGeckoGetPrices¶
Get prices for multiple tokens.
CoinGeckoGetMarkets¶
Get market data with rankings.
TheGraphQuery¶
Execute a GraphQL query on a subgraph.
Request:
message TheGraphQueryRequest {
string subgraph_id = 1; // e.g., "uniswap-v3-arbitrum"
string query = 2; // GraphQL query (max 10KB)
string variables = 3; // JSON-encoded variables
}
Note: Introspection queries (__schema, __type) are blocked.
CoinGeckoGetHistoricalPrice¶
Get historical price at a specific date.
rpc CoinGeckoGetHistoricalPrice(CoinGeckoHistoricalPriceRequest) returns (CoinGeckoHistoricalPriceResponse)
CoinGeckoGetMarketChartRange¶
Get price chart data for a date range.
rpc CoinGeckoGetMarketChartRange(CoinGeckoMarketChartRangeRequest) returns (CoinGeckoMarketChartRangeResponse)
CoinGeckoResolveContract¶
Resolve a chain-scoped contract address to its CoinGecko coin ID. The gateway owns the vendor request, API key, caching, and rate-limit handling; a configured backtest sidecar never falls back to direct CoinGecko HTTP for this lookup.
rpc CoinGeckoResolveContract(CoinGeckoResolveContractRequest) returns (CoinGeckoResolveContractResponse)
Request:
message CoinGeckoResolveContractRequest {
string asset_platform = 1; // CoinGecko platform ID, e.g. "base"
string contract_address = 2; // EVM contract address
}
Response:
message CoinGeckoResolveContractResponse {
string coin_id = 1; // Empty when found=false
bool found = 2; // False only for an explicit contract miss
string source = 3; // "coingecko_api" or "gateway_cache"
}
Gateway transport, authentication, rate-limit, and malformed-upstream failures are returned as typed gRPC errors rather than being reported as contract misses.
CoinGeckoGetOHLCV¶
Get CEX-reference OHLCV candles from CoinGecko (VIB-4847). Second CEX-capable
provider in the OHLCV router's cex_primary failover chain. Candles are
price-only (no volume); 1h/4h/1d timeframes only — sub-hour requests are
below CoinGecko's 30m native floor.
Request:
message CoinGeckoOHLCVRequest {
string token = 1; // Token symbol (e.g., "WETH", "ARB")
string timeframe = 2; // Candle timeframe (1h, 4h, 1d)
int32 limit = 3; // Number of candles (most-recent N)
string quote = 4; // Quote currency (default "USD"; CoinGecko OHLC is fiat-quoted)
}
Response:
message CoinGeckoOHLCVCandle {
int64 timestamp = 1; // Unix timestamp in seconds (candle start)
string open = 2;
string high = 3;
string low = 4;
string close = 5;
// No volume field: CoinGecko OHLC carries price-only candles.
}
message CoinGeckoOHLCVResponse {
repeated CoinGeckoOHLCVCandle candles = 1;
}
CoinGeckoOnchainGetOHLCV¶
DEX OHLCV data from CoinGecko Onchain for on-chain pool pricing. Pool-level
candles with volume — distinct from CoinGeckoGetOHLCV, which serves
token-level, price-only CEX-reference candles.
GetWalletPortfolio¶
Get aggregated wallet portfolio valuation via Zerion.
GetWalletPositions¶
Get detailed wallet positions (DeFi protocol positions) via Zerion.
DashboardService¶
Provides data and actions for the operator dashboard.
ListStrategies¶
List strategies with optional filters.
Request:
message ListStrategiesRequest {
string status_filter = 1;
string chain_filter = 2;
bool include_position = 3;
}
GetStrategyDetails¶
Get detailed information about a strategy including timeline and PnL history.
Request:
message GetStrategyDetailsRequest {
string deployment_id = 1;
bool include_timeline = 2;
bool include_pnl_history = 3;
int32 timeline_limit = 4;
}
GetTimeline¶
Get timeline events for a strategy.
GetStrategyConfig¶
Get strategy configuration.
GetStrategyState¶
Get strategy state.
ExecuteAction¶
Execute an operator action on a strategy.
Request:
message ExecuteActionRequest {
string deployment_id = 1;
string action = 2; // PAUSE, RESUME, BUMP_GAS, CANCEL_TX, EMERGENCY_UNWIND
string reason = 3;
map<string, string> params = 4;
}
RegisterStrategyInstance¶
Register a new strategy instance in the persistent registry.
UpdateStrategyInstanceStatus¶
Update the status of a registered strategy instance.
rpc UpdateStrategyInstanceStatus(UpdateInstanceStatusRequest) returns (UpdateInstanceStatusResponse)
ArchiveStrategyInstance¶
Archive a strategy instance (soft delete).
PurgeStrategyInstance¶
Permanently remove a strategy instance from the registry.
GetTransactionLedger¶
Retrieve the transaction ledger for a strategy instance.
GetPnLSummary¶
Aggregated PnL summary (realized, unrealized, lifetime) for the operator
dashboard. Sourced from portfolio_metrics and accounting_events.
GetCostStack¶
Per-strategy cost decomposition (gas, slippage, protocol fees, MEV).
GetAuditPosture¶
Audit-readiness snapshot: lot-policy version coverage, missing receipts, outbox lag, and reconciliation drift signals.
GetTradeTape¶
Time-ordered tape of executed trades for the dashboard timeline view.
GetActivityFeed¶
Time-ordered feed of strategy lifecycle events (intent emitted, compiled, executed,
teardown, alerts) for the dashboard activity view. Distinct from GetTradeTape which
shows only trade fills.
GetPositions¶
Registry-authoritative position identity (position_registry) joined with snapshot-authoritative valuation (portfolio_snapshots + position_state_snapshots). Replaces SQLite-direct reads in framework/dashboard/pages/detail.py. Carries cutover_state per accounting_category so renderers can split authoritative positions from pre-cutover "Unverified Holdings". (VIB-4493)
GetPositionRangeHistory¶
Per-position range / fee / balance history. Source-routes by primitive: LP/PERP from position_events, lending from accounting_events. Swap/prediction return empty + stub_message (history concept N/A). (VIB-4493)
rpc GetPositionRangeHistory(GetPositionRangeHistoryRequest) returns (GetPositionRangeHistoryResponse)
GetReconciliationReport¶
Three-way diff across transaction_ledger / portfolio_snapshots / position_registry. Read-only. LP-only in v1; non-LP primitives surface per-primitive stubs (pending VIB-4202/4209/4501). 5s TTL cache. (VIB-4493)
rpc GetReconciliationReport(GetReconciliationReportRequest) returns (GetReconciliationReportResponse)
PreviewReconcile¶
Dry-run reconciliation. Thin wrapper over PositionService.Reconcile(apply=false). Returns a preview_token bound to current registry/ledger state hashes — pass to ApplyReconcile to apply. Operator-only; requires the x-operator-token second-factor header when ALMANAK_GATEWAY_OPERATOR_TOKEN is set. (VIB-4493)
ApplyReconcile¶
Applies a previously-issued preview. Fails with STATE_DRIFT if registry/ledger state changed since the preview was issued. Operator-only; requires the x-operator-token second-factor header when ALMANAK_GATEWAY_OPERATOR_TOKEN is set. (VIB-4493)
RefreshRegistryFromChain¶
Forces fresh on-chain reads for every position in position_registry for the strategy. Updates on_chain_verified_at, re-emits divergent events. Rate-limited at the DashboardService layer to one in-flight per strategy. Operator-only; requires the x-operator-token second-factor header when ALMANAK_GATEWAY_OPERATOR_TOKEN is set. (VIB-4493)
rpc RefreshRegistryFromChain(RefreshRegistryFromChainRequest) returns (RefreshRegistryFromChainResponse)
FundingRateService¶
Provides perpetual funding rate data from venues like GMX V2 and Hyperliquid.
GetFundingRate¶
Get current funding rate for a market on a specific venue.
Request:
message FundingRateRequest {
string venue = 1; // gmx_v2, hyperliquid
string market = 2; // e.g., ETH-USD, BTC-USD
string chain = 3;
}
Response:
message FundingRateResponse {
string venue = 1;
string market = 2;
string rate_hourly = 3;
string rate_8h = 4;
string rate_annualized = 5;
int64 next_funding_time = 6;
string open_interest_long = 7;
string open_interest_short = 8;
string mark_price = 9;
string index_price = 10;
bool is_live_data = 11;
bool success = 12;
string error = 13;
}
GetFundingRateSpread¶
Get the funding rate spread between two venues.
Request:
message FundingRateSpreadRequest {
string market = 1;
string venue_a = 2;
string venue_b = 3;
string chain = 4;
}
SimulationService¶
Simulate transaction bundles before execution using Tenderly or Alchemy.
SimulateBundle¶
Request:
message SimulateBundleRequest {
string chain = 1;
repeated SimulateTransaction transactions = 2;
repeated SimulateStateOverride state_overrides = 3;
string simulator = 4; // "tenderly", "alchemy", or empty for auto-select
}
Response:
message SimulateBundleResponse {
bool success = 1;
bool simulated = 2;
repeated int64 gas_estimates = 3;
string revert_reason = 4;
repeated string warnings = 5;
string simulation_url = 6;
string simulator_used = 7;
string error = 8;
}
PoolAnalyticsService¶
Aggregated DEX pool analytics (TVL, volume, fees) sourced through the gateway's analytics providers. Used by risk-adjusted strategies that gate position size on pool depth or 24h turnover.
GetPoolAnalytics¶
ListTokenPools¶
List pools where a token is base or quote, with product-distinct dex ids
sourced from CoinGecko Onchain (aerodrome-base vs aerodrome-slipstream*,
where aggregator labels cannot distinguish the products). Serves symbolic
pool resolution for product-ambiguous venue families (Aerodrome/Velodrome
classic vs Slipstream) in the backtest LP adapter.
Request:
message TokenPoolsRequest {
string chain = 1; // Required. Chain name (canonical or registered alias).
string token_address = 2; // Required. Token address (EVM case-insensitive; Solana case-sensitive).
int32 page = 3; // 0 (default) = ATOMIC bounded fetch (gateway pages upstream on
// raw row counts, one consistent snapshot, `complete` set).
// >=1 = single upstream page (compat/diagnostic).
}
Response:
message TokenPoolsResponse {
string chain = 1; // Echoed-back, canonicalized.
string token_address = 2; // Echoed-back, chain-normalized.
repeated TokenPoolRow pools = 3;
string source = 4; // "coingecko_onchain"
int64 observed_at = 5; // Unix seconds when the gateway fetched the data.
bool success = 6;
string error = 7;
bool complete = 8; // True when the set is complete per upstream RAW row
// counts; false when the page bound was hit with more
// upstream data. Consumers select by RANK-ORDER within
// the returned window (first exact match = the canonical
// pool) — never a deepest-of-all claim over a truncated
// window; a pair with no in-window match fails closed.
}
Each TokenPoolRow carries the pool address (chain-normalized and
syntactically validated — non-address identities are dropped), the
product-distinct dex_id, the pool name, reserve_usd as decimal-as-string
(Empty ≠ Zero: absent or non-finite readings are "", never "NaN"), and
the base/quote token addresses (chain-normalized + validated; "" when
omitted or invalid). Identity handling is chain-aware throughout: EVM
addresses lower-case, Solana-family base58 preserves case. Atomic fetches
page the upstream on raw row counts (a sanitized junk row never truncates
the search) up to a 5-page bound. Results are TTL-cached gateway-side
atomically per snapshot (60s positive, 30s negative; the cache is bounded and
swept), with single-flight deduplication of concurrent identical misses.
Errors follow the dual-channel envelope: provider/schema failures return
structured UNAVAILABLE, never UNKNOWN.
PoolHistoryService¶
Historical pool snapshots — TVL, volume, fee revenue, and per-token reserves over time at 1h / 4h / 1d resolution.
The service is disabled by default (pool_history_enabled=False in
GatewaySettings): the hosted rollout enables it via
ALMANAK_GATEWAY_POOL_HISTORY_ENABLED=true as deployment config once
provider egress and keys are provisioned (VIB-4730 + VIB-4863). When the
flag is off the handler returns UNAVAILABLE with a message pointing at
VIB-4728.
GetPoolHistory¶
Return a time-series of PoolSnapshot rows for a single pool. Provider fallback
order is dispatcher policy (VIB-4753 / POOL-5):
- 1h / 4h: TheGraph → CoinGecko Onchain (DefiLlama is skipped — daily-only).
- 1d: TheGraph → DefiLlama → CoinGecko Onchain.
Returns UNAVAILABLE when all eligible providers fail or when the pool is not
found anywhere — never fake-success with an empty snapshots array.
Request:
message PoolHistoryRequest {
string pool_address = 1; // EVM: case-insensitive; Solana: case-sensitive base58
string chain = 2; // e.g. "arbitrum", "ethereum", "base"
string protocol = 3; // e.g. "uniswap_v3", "aerodrome"
int64 start_ts = 4; // Unix seconds, UTC
int64 end_ts = 5; // Unix seconds, UTC (rejected if in the future)
Resolution resolution = 6; // RESOLUTION_1H | RESOLUTION_4H | RESOLUTION_1D
}
Response:
message PoolHistoryResponse {
repeated PoolSnapshot snapshots = 1; // Ascending by timestamp, one row per aligned bucket
TruncationReason truncation_reason = 2; // CAP_EXCEEDED | PROVIDER_PAGE_CAP | PROVIDER_RETENTION
int64 next_start_ts = 3; // Re-chunk hint for paged backfill
string source = 4; // "the_graph" | "defillama" | "coingecko_onchain"
bool finalized_only = 5; // false if any row is provisional within the finality cutoff
bool success = 6;
string error = 7;
}
Soft caps are operator-tunable via ALMANAK_GATEWAY_POOL_HISTORY_MAX_DAYS_{1H,4H,1D}
(defaults: 90, 180, 730 days). When a request exceeds a cap the handler returns
a CAP_EXCEEDED truncation and a next_start_ts hint for the next chunk.
RateHistoryService¶
VIB-4859 / W7 of epic VIB-4851. Lending APY (live + historical), perpetual
funding-rate history, DEX TWAP (single observation + series), and DEX trading
volume history. Replaces the strategy-side HTTP / GraphQL / Web3 egress that
used to live in framework/data/rates/{monitor,history}.py and
framework/backtesting/pnl/providers/{lending_apy,twap,dex/*} — all of which
violated the gateway-boundary rule. After W7, those framework readers are
thin gRPC clients of this service.
Dispatcher pattern mirrors FundingRateService / PoolAnalyticsService: the
servicer resolves (protocol, venue, dex) → capability provider at
construction time (O(1) lookup per request), validates the request shape, and
delegates to the connector. Connectors implement
GatewayLendingRateHistoryCapability / GatewayFundingHistoryCapability /
GatewayPerpPriceHistoryCapability /
GatewayDexTwapCapability / GatewayDexVolumeCapability. Adding a new
implementer is a connector-folder change with zero gateway-service edits.
Error semantics — dual-channel wire shape:
status OK + success=true→ fresh data in the envelope.status OK + success=false→ framework raisesDataSourceUnavailable(no silent zero-fill, no default-rate fallback).- non-OK status (
INVALID_ARGUMENT/UNAVAILABLE/ …) → framework raisesDataSourceUnavailable;__cause__preserves thegrpc.RpcError.
GetLendingRateCurrent¶
Single-point live lending rate (supply or borrow APY + utilisation) via the
connector's on-chain path (e.g. Aave V3's
AaveProtocolDataProvider.getReserveData(asset)).
Request:
message GetLendingRateCurrentRequest {
string protocol = 1; // e.g. "aave_v3", "compound_v3", "morpho_blue"
string chain = 2; // e.g. "ethereum", "arbitrum"
string asset_symbol = 3; // e.g. "USDC", "WETH"
string side = 4; // "supply" or "borrow"
}
Response: LendingRatePointResponse { protocol, chain, asset_symbol, side, point: LendingRatePoint, source, is_live_data, success, error }.
GetLendingRateHistory¶
Time-series of lending APY / utilisation over [start_ts, end_ts).
Migrated body of framework/data/rates/history.py (TheGraph crawl with
DefiLlama fallback).
GetFundingRateHistory¶
Historical funding-rate series for a perp (venue, market). Sibling of
FundingRateService.GetFundingRate (which serves the live rate only).
GetPerpPriceCandles¶
Return one bounded page of venue-native perpetual index-price candles. The
gateway resolves the caller's market label/address through the connector's live
catalogue and verifies its address tuple on-chain before deriving the vendor
symbol. The request timeframe is exact; the gateway never substitutes a
coarser value. Backtest auto negotiation is framework-side and probes this RPC
finest-to-coarsest for complete coverage.
Every successful page repeats market_token, index_token, index_symbol,
and timeframe so pagination can reject identity drift. OHLC decimals are
strings. Volume is intentionally absent: this is the index/mark price plane,
not venue execution volume.
GetDexTwap¶
Single TWAP observation for a Uniswap-V3-style pool (or a V3 fork with the
same observe(secondsAgos) ABI). secs_ago_start is the older boundary,
secs_ago_end is the newer boundary — matches the on-chain
observe(secondsAgos) convention. Pass as_of_block > 0 to pin the
observation to an archive block; leave as_of_block = 0 for current head.
GetDexTwapSeries¶
TWAP series at interval_secs spacing over [start_ts, end_ts).
GetDexPoolStateSeries¶
Historical exact-address pool state at interval_secs spacing over the
inclusive [start_ts, end_ts] grid. The gateway resolves each grid timestamp
to the latest block at-or-before it and reads that pool's slot0, liquidity,
fee, immutable token identities/decimals, and token balances from archive
state. It never discovers a substitute pool or derives state from token/USD
prices.
rpc GetDexPoolStateSeries(GetDexPoolStateSeriesRequest) returns (DexPoolStateHistoryResponse)
message GetDexPoolStateSeriesRequest {
string dex = 1;
string chain = 2;
string pool_address = 3;
int64 start_ts = 4;
int64 end_ts = 5;
int64 interval_secs = 6;
}
message DexPoolStatePoint {
int64 timestamp = 1;
int64 block_number = 2;
string sqrt_price_x96 = 3;
int64 tick = 4;
string liquidity = 5;
string token0 = 6;
string token1 = 7;
int32 token0_decimals = 8;
int32 token1_decimals = 9;
int32 fee_tier = 10;
string reserve0_raw = 11;
string reserve1_raw = 12;
}
GetDexLwap¶
Liquidity-weighted spot price across the supplied Uniswap-V3-style pools
(LWAP = Σ(price·liquidity) / Σ(liquidity) over each pool's pool-native
token1/token0 spot). The framework resolves the candidate pool addresses; the
gateway reads slot0() + liquidity() + token0/token1 per pool server-side.
When base_token / quote_token addresses are supplied, pools not containing
exactly that pair are dropped before weighting, so a stale or foreign-pair pool
address cannot poison the aggregate. Fails closed (success=false) when no pool
is readable, the requested pair matches nothing, or total in-range liquidity is
zero — it never emits an empty or fabricated price. The caller
(MarketSnapshot.lwap) re-orients the returned native price to the requested
quote/base (VIB-4948 / ALM-2770).
GetDexVolumeHistory¶
Historical trading-volume series for a DEX pool (USD volume at the requested bucket spacing).
GetGasPriceAt¶
Current or historical gas-price observation for an EVM chain. timestamp = 0
uses the gateway-owned explorer gas oracle. timestamp > 0 reads
baseFeePerGas from the gateway's archive RPC path; the returned
GasPricePoint.timestamp is the actual observed block timestamp, not the
requested timestamp.
Request:
message GetGasPriceAtRequest {
string chain = 1; // EVM chain name, e.g. "ethereum", "arbitrum", "base"
int64 timestamp = 2; // Unix seconds; 0 means current gas oracle
}
Response: GasPricePointResponse { chain, point: GasPricePoint, source, success, error }.
GetOraclePrice¶
Return the current observation from one explicitly requested oracle provider.
This is provider-exact data rather than MarketService.GetPrice's aggregated
price policy, so freshness and divergence checks preserve their provenance.
Request: GetOraclePriceRequest { provider, chain, token }.
Response: OraclePriceResponse { provider, chain, token, point: OraclePricePoint, success, error }.
OraclePricePoint.observation_id is the provider-native identifier; Chainlink
returns its uint80 round ID as a decimal string.
GetOraclePriceHistory¶
Return a bounded provider-exact oracle series over the half-open interval
[start_ts, end_ts). The caller must supply max_points in [1, 10000]; the
gateway also rejects windows longer than 366 days. Provider-specific archive
RPC selection, decoding, and historical traversal remain gateway-owned.
Request: GetOraclePriceHistoryRequest { provider, chain, token, start_ts, end_ts, max_points }.
Response: OraclePriceHistoryResponse { provider, chain, token, points: OraclePricePoint[], success, error }.
Wire conventions — Decimal fields are encoded as strings (mirrors
PoolHistoryService / FundingRateService). Empty string means
"unmeasured by this provider for this row"; the framework boundary maps it
to Python None — never Decimal("0"). Per-side selection on lending
(e.g. side="supply") returns the borrow field as the empty string, NOT
zero.
PolymarketService¶
Proxy for the Polymarket CLOB API. Provides market data, order management, and position tracking.
GetMarket¶
Fetch metadata for a single Polymarket market (tokens, condition id, status).
GetMarkets¶
List markets with optional filters (category, status, cursor pagination).
GetMidpoint¶
Return the current midpoint price for a token (CLOB outcome).
GetPrice¶
Return the current best bid or ask price for a token, depending on the requested side.
GetSimplifiedMarkets¶
List condensed market summaries optimized for discovery flows.
rpc GetSimplifiedMarkets(PolymarketGetSimplifiedMarketsRequest) returns (PolymarketSimplifiedMarketsResponse)
GetOrderBook¶
Return the full bid / ask book for a token.
GetTickSize¶
Return the minimum price increment (tick size) accepted for a token.
GetSpread¶
Return the current bid-ask spread for a token.
GetPriceHistory¶
Return time-bucketed historical prices for a token (used for backtesting and charts).
GetTradeTape¶
Return a time-ordered trade tape across markets (most-recent first).
GetBalanceAllowance¶
Return the funder's USDC balance and CLOB exchange allowance.
rpc GetBalanceAllowance(PolymarketBalanceAllowanceRequest) returns (PolymarketBalanceAllowanceResponse)
GetOpenOrders¶
List open orders for the configured funder, optionally filtered by market.
GetOrder¶
Return details for a single order by id.
GetTradesHistory¶
List historical fills for the funder, with cursor pagination.
GetPositions¶
List the funder's current Polymarket outcome-token positions.
CancelOrder¶
Cancel a single open order by id.
CancelOrders¶
Cancel multiple open orders in a single call.
CancelAll¶
Cancel every open order for the funder.
CreateAndPostOrder¶
Sign a limit order against the funder's key and POST it to the CLOB in a single RPC. Returns the order id and CLOB acknowledgement payload.
CreateAndPostMarketOrder¶
Sign and submit a market order in a single RPC (fills against the resting book).
EnsoService¶
Proxy for Enso Finance routing and bundling, supporting cross-chain swaps.
GetRoute¶
Get an optimized swap route.
Request:
message EnsoRouteRequest {
string chain = 1;
string token_in = 2;
string token_out = 3;
string amount_in = 4;
string from_address = 5;
string receiver = 6;
int32 slippage_bps = 7;
string routing_strategy = 8;
int32 max_price_impact_bps = 9;
int32 destination_chain_id = 10;
string refund_receiver = 11;
}
GetQuote¶
Get a price quote without generating calldata.
GetApproval¶
Get the approval transaction for a token.
GetBundle¶
Bundle multiple DeFi actions into a single transaction.
TokenService¶
Provides token resolution and on-chain metadata lookups.
ResolveToken¶
Resolve a token by symbol or address to get its full metadata.
GetTokenMetadata¶
Get metadata for a token by address.
GetTokenDecimals¶
Get the decimal precision for a token.
BatchResolveTokens¶
Resolve multiple tokens in a single call.
LifecycleService¶
Agent state management and command dispatch for V2 deployments.
WriteState¶
Write the current agent state (INITIALIZING, RUNNING, PAUSED, ERROR, STOPPING, TERMINATED).
ReadState¶
Read the current agent state.
Heartbeat¶
Send a heartbeat to update the last activity timestamp and increment the iteration count.
ReadCommand¶
Read the most recent unprocessed command for an agent (PAUSE, RESUME, STOP).
AckCommand¶
Acknowledge (mark processed) a command.
WriteCommand¶
Write a command to an agent.
TeardownService¶
Hosted teardown state routing for V2 deployments. Splits into two halves: the request half (teardown_requests) which tracks operator-issued teardown signals through their lifecycle (acknowledged → started → progress → completed / failed / cancelled), and the adapter half (teardown_execution_state + teardown_approvals) which persists the in-flight intent state machine and operator approvals required for risk-elevated teardown steps. See docs/internal/blueprints/14-teardown-system.md.
CreateTeardownRequest¶
Insert a new operator-issued teardown request. This is the row that
almanak strat teardown request -s <deployment_id> writes; the runner's polling
query picks it up by deployment_id.
GetTeardownRequest¶
Fetch a single teardown request by id.
GetActiveTeardownRequest¶
Fetch the active (non-terminal) teardown request for a strategy, if any.
GetPendingTeardownRequests¶
List teardown requests not yet acknowledged by any runner (used by the runner polling loop and the operator dashboard's pending queue).
GetAllActiveTeardownRequests¶
List every non-terminal teardown request across all strategies (operator dashboard).
GetAllTeardownRequests¶
List every teardown request (administrative / audit endpoint).
UpdateTeardownRequest¶
Generic update of a teardown request (mode, slippage tolerance, operator note).
AcknowledgeTeardownRequest¶
Mark a request as acknowledged by the runner that owns the strategy. Until this
fires, the request is in pending.
MarkTeardownStarted¶
Transition the request to started once the teardown manager begins executing
intents (this is the state almanak strat teardown request --wait reports).
UpdateTeardownProgress¶
Stream per-step progress (current intent index, status, last tx_hash). Read by
teardown request --wait to print the live progress feed.
MarkTeardownCompleted¶
Terminal success state — every teardown intent completed and the strategy is fully unwound.
MarkTeardownFailed¶
Terminal failure state with an error code + message. The on-chain state may be
partially unwound; check the latest transaction_ledger rows for the strategy.
RequestTeardownCancel¶
Operator-issued cancellation signal (cooperative — the runner stops at the next safe checkpoint).
MarkTeardownCancelled¶
Terminal cancellation state — the runner halted teardown at a safe checkpoint.
DeleteTeardownRequest¶
Hard-delete a request row (administrative endpoint).
SaveTeardownState¶
Persist a snapshot of the teardown intent state machine. Used by the runner to survive restarts mid-teardown.
LoadTeardownState¶
Restore the teardown state machine on runner restart.
DeleteTeardownState¶
Clear persisted teardown state after a terminal transition.
CreateApprovalRequest¶
Block teardown on operator approval for risk-elevated steps (e.g., HARD-mode
slippage bumps). The runner waits on a matching GetApprovalResponse /
WriteApprovalResponse pair.
GetApprovalResponse¶
Poll for an operator's response to an approval request by approval id.
WriteApprovalResponse¶
Operator writes an approve / deny decision against an approval id.
GetLatestPendingApproval¶
Fetch the most recent pending approval for a strategy (operator UI lookup when approval id is not known).
rpc GetLatestPendingApproval(GetLatestPendingApprovalRequest) returns (GetLatestPendingApprovalResponse)
WriteApprovalResponseByStrategy¶
Approve / deny by strategy id (used when the operator UI does not yet have the approval id but has the strategy context).
rpc WriteApprovalResponseByStrategy(WriteApprovalResponseByStrategyRequest) returns (BoolMutationResponse)
PositionService¶
Control-plane reconciliation of position_registry against on-chain truth. v1 scope is
UniV3 LP only (T24 / VIB-4210). Backs the almanak ax positions reconcile operator CLI.
Closes user-facing bug GH #2131 (phantom-missing rows after partial-write outages).
Reconcile¶
Re-derive registry rows for a deployment by querying chain state and diffing against the
current position_registry contents. Reports four diff categories:
matched— on-chain and registry agree.phantom_missing— on-chain has a position, registry doesn't (the GH #2131 case).stranded— registrystatus='open', chain absent. Never auto-closed — operator must run a teardown for the position.rebuilt— phantom-missing rows just written (only when requestapply=true).
When apply=false (default), the RPC is dry-run and returns the diff without writing.
When apply=true, phantom-missing rows are inserted into position_registry via
SaveLedgerAndRegistry(mode='registry_reconciliation') (registry-only write; ledger is
NEVER touched on the reconciliation path).
Request:
message ReconcileRequest {
string deployment_id = 1; // ClassName:hash
string chain = 2;
string wallet_address = 3;
repeated string primitives = 4; // v1: "lp" only
repeated string physical_identity_hashes = 5; // optional filter
bool apply = 6; // default false (dry-run)
int64 max_age_blocks = 7; // 0 = no check; v1: rejected if > 0 on first-page requests (no page_cursor)
bytes page_cursor = 8; // Opaque pagination cursor (v1: honored only for stale-cursor validation; single-page contract)
int32 page_size = 9; // Max rows per page (default 64, cap 256; v1: clamped but does not slice)
string operator_note = 10; // ≤ 256 bytes
string trigger = 11; // operator_cli | hosted_boot | dashboard | ci
}
PerpFillService¶
Executed fills and funding settlements for a wallet on a perp venue (VIB-5595). Backs the
perp accounting path: taker fees are routed via ProtocolFees.perp_fee_usd, and realized
PnL / funding via PerpAccountingEvent. HTTP egress to the venue (e.g. the Hyperliquid
Info API userFills / userFunding) happens server-side only; the framework reader is a
thin gRPC client. Empty≠Zero: a venue field that is not reported stays unmeasured (empty
string) and is never coerced to "0".
GetUserFills¶
Executed fills for a wallet, optionally filtered to a coin and a start time.
Request:
message UserFillsRequest {
string venue = 1; // one per perp connector; unknown -> INVALID_ARGUMENT
string wallet_address = 2; // account whose fills to read (EVM address)
string coin = 3; // optional coin filter (e.g. "BTC"). Empty = all
int64 start_time_ms = 4; // optional lower bound, epoch ms. 0 = no bound
}
Response:
message PerpFill {
string coin = 1; // market symbol (e.g. "BTC")
string px = 2; // fill price (decimal string; empty = unreported)
string sz = 3; // fill size, base asset absolute (empty = unmeasured)
string dir = 4; // venue direction label ("Open Long", ...)
string fee = 5; // fee paid, USD (empty = unmeasured, never "0")
string closed_pnl = 6; // realized PnL on closing fills (empty = unmeasured)
string oid = 7; // venue order id
string cloid = 8; // client order id (correlation key to the intent)
int64 time_ms = 9; // fill time, epoch ms
bool crossed = 10; // true iff taker (crossed the spread). Advisory
string fee_token = 11; // fee token symbol (e.g. "USDC"); empty = unreported
}
message UserFillsResponse {
repeated PerpFill fills = 1;
bool success = 2;
string error = 3;
}
GetUserFunding¶
Funding settlements (deltas) for a wallet over the same window.
Request:
message UserFundingRequest {
string venue = 1;
string wallet_address = 2;
string coin = 3; // optional coin filter. Empty = all coins
int64 start_time_ms = 4; // optional lower bound, epoch ms. 0 = no bound
}
Response:
message PerpFundingDelta {
string coin = 1; // market symbol
string usdc = 2; // signed funding in USDC (- paid / + received; empty = unmeasured)
string funding_rate = 3; // rate applied for this settlement (empty = unmeasured)
int64 time_ms = 4; // settlement time, epoch ms
}
message UserFundingResponse {
repeated PerpFundingDelta deltas = 1;
bool success = 2;
string error = 3;
}
GetOrderStatus¶
Status of a single submitted order, addressed by its client order id (cloid). This is the
reject-detection signal the fill-reconciliation pump needs (VIB-5616): userFills alone
cannot tell "not filled yet" (async settlement lag) from "rejected" — both leave the fills
book empty — so a genuinely rejected open would otherwise stall a continuous perp strategy
in PENDING until teardown. The gateway runs the connector's pure parser and returns the
typed verdict; the strategy container never re-parses raw venue JSON. Empty≠Zero: a
transport / decode fault returns success=false (the read could not complete); an order
the venue does not know (unknownOid) is a measured response — success=true with an
UNMEASURED status — so the pump stays PENDING but never fabricates a fill or reject.
Request:
message OrderStatusRequest {
string venue = 1; // one per perp connector; unknown -> INVALID_ARGUMENT
string wallet_address = 2; // account that submitted the order (EVM address)
string cloid = 3; // client order id as a decimal uint128 string. Required
string chain = 4; // chain hint (Hyperliquid is chain-agnostic)
}
Response:
message OrderStatusResponse {
string status = 1; // FillStatus: "filled"/"partially_filled"/"resting"/"rejected"/"unmeasured"
string filled_size = 2; // base-asset size filled (decimal string; empty = unmeasured)
string avg_fill_price = 3; // average fill price (decimal string; empty = unmeasured)
string detail = 4; // human-readable note (raw status / error) for observability
bool success = 5; // false -> UNMEASURED (never a fabricated verdict)
string error = 6;
}
Error Codes¶
| gRPC Code | HTTP | Description |
|---|---|---|
| INVALID_ARGUMENT | 400 | Invalid request parameters |
| NOT_FOUND | 404 | Resource not found |
| PERMISSION_DENIED | 403 | Operation not allowed |
| RESOURCE_EXHAUSTED | 429 | Rate limit exceeded |
| FAILED_PRECONDITION | 412 | Chain not configured |
| INTERNAL | 500 | Internal server error |
| UNAVAILABLE | 503 | Service temporarily unavailable |
Rate Limits¶
| Service | Limit |
|---|---|
| RpcService (EVM chains) | 300 req/min per chain |
| RpcService (Solana) | 100 req/min |
| IntegrationService.Binance | 1200 req/min |
| IntegrationService.CoinGecko | 50 req/min (free tier) |
| IntegrationService.TheGraph | 100 req/min |