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 | 6 | Price data, Pendle PT/YT-USD price, balances, batch balances, technical indicators, and Uniswap V4 pool key lookup |
| StateService | 29 | 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 | 13 | 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 | 1 | DEX pool analytics (TVL, volume, fees) for risk-adjusted decisions |
| PoolHistoryService | 1 | Historical pool snapshots (TVL, volume, fees over time). Feature-flagged off by default; enable via ALMANAK_GATEWAY_POOL_HISTORY_ENABLED=true |
| RateHistoryService | 8 | Lending APY (live + historical), perp funding history, DEX TWAP (single + series), DEX LWAP (liquidity-weighted spot), DEX volume history, and gas prices (VIB-4859 / W7, VIB-4948). 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) |
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")
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.
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¶
Save computed portfolio metrics (PnL, Sharpe, drawdown, etc.).
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.
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
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)
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;
}
GeckoTerminalGetOHLCV¶
Legacy-named RPC for DEX OHLCV data from CoinGecko Onchain for on-chain pool pricing.
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¶
PoolHistoryService¶
Historical pool snapshots — TVL, volume, fee revenue, and per-token reserves over time at 1h / 4h / 1d resolution.
The service is feature-flagged off by default (pool_history_enabled=False
in GatewaySettings). Set ALMANAK_GATEWAY_POOL_HISTORY_ENABLED=true on the
gateway to enable. When the flag is off the handler returns UNAVAILABLE with
a message pointing at VIB-4728; when the flag is on but providers are not yet
wired (POOL-2 → POOL-5 window) it returns UNIMPLEMENTED.
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" | "geckoterminal" (legacy key for 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 /
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).
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).
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 }.
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
}
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 |