00Summary
The idea is good and the timing works. But three things will decide whether this lives or dies, and none of them is about “whether the AI is smart.”
- The Stock Token oracle is 24/5, while the token itself trades 24/7. Saturday–Sunday the reference price is frozen while the DEX price keeps moving. Every leverage design has to be built around this fact. This isn't a detail — it's the core of the product.
- Discretionary portfolio management is a regulated activity in nearly every jurisdiction. Being non-custodial and having a user-signed mandate reduces the risk, but doesn't remove it.
- The right wedge isn't an “AI rebalancer.” The right wedge is Belay: the agent that keeps the user from getting liquidated at 3 a.m. on a Sunday. Rebalancing is the second feature, not the first.
How to read this document
Sections 2 and 4 are the core. If time is limited, read those two plus section 11. Everything else follows from those three.
01What already exists on-chain
Know the battlefield before building here.
Live infrastructure
| Layer | What's available |
|---|---|
| Chain | Robinhood Chain, Arbitrum Orbit, chain ID 4663, ~100 ms blocks, gas in ETH, FCFS sequencer (no priority-fee auction) |
| RPC | rpc.mainnet.chain.robinhood.com, Blockscout explorer, sequencer feed via WebSocket |
| Stablecoin | USDG (Paxos Global Dollar) as the liquidity anchor |
| Oracle | Chainlink — per-ticker feeds, AggregatorV3Interface, plus L2 Sequencer Uptime Feed |
| DEX & liquidity | Uniswap (dedicated deployment), Rialto & Pleiades (propAMM), Arcus, 1inch; RFQ via 0x RFQ, 1inch Fusion, LiFi |
| Lending | Morpho (backbone of Robinhood Earn, USDG ~7% APY) |
| Perps | Lighter — non-custodial perps DEX, accessible from inside Robinhood Wallet |
| Account abstraction | ERC-4337 first-class and EIP-7702; provider Alchemy (official bundler), ZeroDev, Privy |
| Bridge | Canonical Arbitrum bridge, CCIP, Stargate, Relay, Across |
What's already live on-chain
Check all of these before writing a single line of code.
- Lends (
lendspro.com) — CDP: mintleUSDagainst Stock Tokens. Borrow limit ~60% LTV, +10-point maintenance. Already supports NVDA, AAPL, TSLA. - Syndromics — P2P syndicated lending, fixed rate fixed term, 55% LTV tier and 70% liquidation.
- OpenClaw — already marketing a 24/7 LTV guardian agent, ERC-4337 session keys, approvals via Telegram.
- r0x — x402 facilitator for agent payments on this chain, plus an MCP plugin.
- Plenty of sniper bots and memecoin LPs — a signal that retail on this chain is still dominated by degens, not set-and-forget investors.
02Constraints that dictate the design
This is the part people skip most often, and the most expensive to get wrong.
2.1 Stock Tokens are not stocks
Stock Tokens are tokenised debt securities issued by Robinhood Assets (Jersey) Limited (RHJ). They give economic exposure, not legal or beneficial rights to the underlying stock. Concrete consequences for the risk engine:
- Issuer credit risk. There's a Jersey entity standing between the user and Nvidia. This risk doesn't exist with crypto collateral. The risk model needs an
issuer_riskvariable that, when triggered, forces a system-wide de-risk — not per-ticker. - No voting rights. Irrelevant to the engine, but relevant to marketing claims. Never say the user “owns stock.”
- Dividends are handled by the issuer, not via token transfer. Don't model dividends as on-chain cashflow.
2.2 Jurisdiction determines TAM
Stock Tokens are available in 120+ countries, but not for US persons, and are restricted in, among others, Canada, the UK, Switzerland, the UAE, and sanctioned jurisdictions. The official list lives in the Base Prospectus and Final Terms at docs.robinhood.com/rhj.
- Stock Tokens are not available to US persons — which happens to be Robinhood's largest user base. Any TAM assumption based on “retail users coming in through Robinhood Wallet” must account for that exclusion.
- Geo-gating and attestation are required on the front end, and ideally an allowlist at the smart-contract level for anything managed.
- Lighter perps has its own restricted list: US, UK, Canada, Switzerland, UAE, Singapore. The hedging feature has a narrower TAM than the lending feature, so product design needs to be modular per jurisdiction.
2.3 24/5 oracle vs. 24/7 token
This is the mechanic that matters most here. The Chainlink feed for tokenized equities reports Total Return Value = the underlying equity price multiplied by a multiplier read directly from the token contract. The underlying price comes from a 24/5 equity feed covering the regular session, pre-market, post-market, and overnight.
| Condition | Feed behavior | What the agent must do |
|---|---|---|
| Market open | Updates on deviation threshold or heartbeat | Normal operation |
| Overnight session | Still updates, but liquidity is thin and spreads are wide | Raise the haircut, lower max trade size |
| Weekend, holiday, or closure (marketStatus = 5) | Feed holds the last price; updatedAt stops advancing | Frozen mode: no new leverage, no action that depends on the liquidation threshold, de-risk only |
| Corporate action being processed | Oracle paused — oraclePaused() returns true | Treat as price unavailable. Not zero, not stale-but-fine |
| Sequencer down | Sequencer Uptime Feed non-zero | Full halt, plus a grace period before resuming |
Danger A — the Monday-morning gap
The oracle price is frozen at Friday's close. Monday's open, NVDA gaps down 12%. Positions whose health factor looked safe all weekend suddenly become liquidatable within seconds, and liquidation bots on a 100 ms-block chain win that race by default.
Mitigation: the agent forces LTV down before Friday's close, rather than reacting on Monday.
Danger B — DEX price vs. oracle divergence
On a weekend, news breaks, the Uniswap price moves, the oracle doesn't. Unwind logic that sizes using the oracle price but executes on the DEX can end up selling far below the assumed level.
Always size using min(oracle, dex_quote) for collateral and max(…) for debt.
2.4 ERC-8056, the corporate-action trap
Stock Tokens implement ERC-8056 (Scaled UI Amount Extension) with a uiMultiplier() function. The multiplier scales the effective amount without changing the raw balance or total supply — balanceOf() and totalSupply() stay the same through a stock split.
If a vault records user positions using raw balanceOf and never reads uiMultiplier(), the accounting will be off by 10× after a 10-for-1 split. That's a bug that wipes out user funds.
Rule
Every balance read used for valuation must be rawBalance × uiMultiplier() / SCALE — check the actual scale in the documentation. Every multiplier change must trigger a full re-index and a temporary pause.
2.5 FCFS sequencer and centralization
Sequencing is first-come-first-served: order is determined by arrival time, not gas price.
- There's no “pay more” option to win in an emergency. The competition becomes a latency race, not a fee race. Rescuing a position during a gap requires low-latency nodes and RPC to the sequencer, not just a gas bump.
- The sequencer is operated solely by Robinhood. Downtime means the agent is blind and paralyzed. This is disclosed to users.
- Withdrawals to L1 via the canonical bridge have a 7-day challenge period. Never promise instant cross-chain exit liquidity.
03System architecture
┌─────────────────────────────────────────────────────────────────┐
│ CLIENT │
│ Web app / Telegram bot / Robinhood Wallet dApp browser │
│ - Onboarding, geo-gate, risk questionnaire │
│ - Mandate signing (EIP-712) │
│ - Kill switch (one button, always visible) │
└───────────────┬─────────────────────────────────────────────────┘
│
┌───────────────▼─────────────────────────────────────────────────┐
│ AUTHORIZATION LAYER (on-chain, non-custodial) │
│ User smart account (ERC-4337) or EOA + EIP-7702 delegation │
│ ├── SessionKeyModule : agent key, expiry, revocable │
│ └── PolicyGuard : target+selector allowlist, notional cap │
│ per-tx & rolling window, max slippage │
└───────────────┬─────────────────────────────────────────────────┘
│ userOps
┌───────────────▼─────────────────────────────────────────────────┐
│ EXECUTION LAYER (off-chain, stateless workers) │
│ Executor → Bundler (Alchemy) → Sequencer │
│ - Mandatory pre-flight simulation (fork / eth_call bundle) │
│ - Idempotency key per intent, nonce management, retry policy │
└───────────────▲─────────────────────────────────────────────────┘
│ signed intent
┌───────────────┴─────────────────────────────────────────────────┐
│ DECISION LAYER │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ RISK ENGINE │──▶│ POLICY ENGINE│──▶│ INTENT VALIDATOR │ │
│ │ deterministic│ │ deterministic│ │ deterministic + sim │ │
│ └──────▲───────┘ └──────▲───────┘ └──────────────────────┘ │
│ │ │ │
│ │ ┌──────┴───────┐ │
│ │ │ SIGNAL LAYER │ ← LLM lives HERE ONLY │
│ │ │ (advisory) │ output: bounded score │
│ │ └──────────────┘ │
└─────────┼───────────────────────────────────────────────────────┘
│
┌─────────┴───────────────────────────────────────────────────────┐
│ DATA LAYER │
│ - Chainlink feeds + sequencer uptime + oraclePaused() │
│ - Position indexer (Blockscout / Alchemy / self-hosted node) │
│ - DEX depth (Uniswap pools, RFQ quotes 0x/1inch) │
│ - Market calendar (NYSE/Nasdaq holidays, half-days) │
│ - Earnings calendar, corporate action feed │
│ - Funding rate & mark price Lighter (if V4) │
│ - News/sentiment (V4) │
└─────────────────────────────────────────────────────────────────┘
Client
Web app / Telegram bot / Robinhood Wallet dApp browser
- Onboarding, geo-gate, risk questionnaire
- Mandate signing (EIP-712)
- Kill switch (one button, always visible)
Authorization layer (on-chain, non-custodial)
User smart account (ERC-4337) or EOA + EIP-7702 delegation
- SessionKeyModule — agent key, expiry, revocable
- PolicyGuard — target+selector allowlist, notional cap per-tx & rolling window, max slippage
Execution layer (off-chain, stateless workers)
Executor → Bundler (Alchemy) → Sequencer
- Mandatory pre-flight simulation (fork / eth_call bundle)
- Idempotency key per intent, nonce management, retry policy
Decision layer
- Risk engine (deterministic) → Policy engine (deterministic) → Intent validator (deterministic + sim)
Signal layer (advisory) — the only place the model lives. Output: a bounded score.
Data layer
- Chainlink feeds + sequencer uptime + oraclePaused()
- Position indexer (Blockscout / Alchemy / self-hosted node)
- DEX depth (Uniswap pools, RFQ quotes 0x/1inch)
- Market calendar (NYSE/Nasdaq holidays, half-days)
- Earnings calendar, corporate action feed
- Funding rate & mark price Lighter (if V4)
- News/sentiment (V4)
A separation that must never be violated
The Risk Engine, Policy Engine, and Validator must be 100% deterministic and reproducible. Given the same state, all three must produce the same intent. The LLM never generates calldata. The LLM can never raise a cap. The LLM can only shift parameters toward being more conservative, or produce a score consumed by a deterministic engine.
04Risk engine
4.1 Effective collateral value
Never use the raw oracle price.
V_eff(token) = qty_effective × P_conservative × haircut_total
qty_effective = rawBalance × uiMultiplier / SCALE # ERC-8056
P_conservative = min(P_oracle, P_dex_executable(size)) # for collateral
haircut_total = h_vol × h_session × h_liquidity × h_event × h_issuer
| Factor | Typical range | Basis |
|---|---|---|
h_vol | 0.75 – 0.95 | 30-day realized vol plus implied vol when available. Single-name is more aggressive than an ETF. |
h_session | 1.00 open 0.95 pre & post 0.88 overnight 0.80 closed | Underlying market hours |
h_liquidity | 0.70 – 1.00 | DEX and RFQ depth at position size. Positions above 20% of pool depth get an aggressive haircut. |
h_event | 0.70 if earnings ≤ 2 days 0.85 if ≤ 5 days | Earnings calendar |
h_issuer | 1.00 normal | Drops sharply if there's an RHJ stress signal. Manual flag from ops. |
4.2 Time-aware health factor
This is what distinguishes it from ordinary LTV monitoring.
HF_now = V_eff / debt
HF_stress = V_eff × (1 − gap_expected) / debt
gap_expected = z × σ_daily × sqrt(T_untradeable_days)
+ earnings_gap_premium
gap_expected is an estimate of the move up to the next actionable decision point — not until tomorrow.
T_untradeable_days— how many days until a position can actually be unwound with decent liquidity. Friday afternoon is about 2.6 days. Wednesday afternoon is about 0.6 days.zis set by the risk profile: Conservative 3.0 · Balanced 2.3 · Growth 1.8.earnings_gap_premium— single-name earnings gaps can be 8–15%. Don't model this with a normal distribution; use empirical per-ticker data.
Operational rules that follow from this
FRIDAY, T-90 minutes before close
target_LTV_weekend = LLTV × 0.55 (Conservative)
= LLTV × 0.65 (Balanced)
= LLTV × 0.72 (Growth)
if LTV_now > target_weekend → unwind down to target.
Mandatory. Cannot be overridden by the AI.
D-1 EARNINGS, T-60 minutes before close
target_LTV = LLTV × 0.50 for that ticker, regardless of profile.
MARKET CLOSED (marketStatus = 5)
forbidden : adding leverage, opening new positions,
optional rebalancing
allowed : repay, add collateral, unwind
(with a strict slippage cap)
ORACLE PAUSED or STALE > threshold
halt all actions on that ticker, except a full repay
using another asset.
SEQUENCER DOWN
full halt, notify user. Don't queue transactions
that would execute at an unpredictable price on resume.
4.3 A ladder of actions, not all-or-nothing
Always leave margin above the protocol threshold
On Lends, the borrow limit is 60% and maintenance is +10 points. That means the actual buffer from max borrow to liquidation is only about a 14% drop in collateral. That's one bad day for NVDA. Never let a user sit at max borrow.
4.4 Liquidity-aware execution
Before sending an unwind action:
1. Get quotes from at least 2 sources:
Uniswap pool + RFQ (0x / 1inch Fusion) + Rialto propAMM
2. If estimated slippage > slippage_cap
→ split into several clips with delays
3. If even the smallest clip > cap
→ DO NOT execute. Escalate to the user.
Selling into a market with no bid does more damage
than an orderly liquidation.
4. Log realized slippage.
Feed it back into h_liquidity for calibration.
05Where the AI is, and its limits
This is the part that's easiest to get architecturally wrong. An “AI agent” that outputs calldata directly is the fastest way to lose user funds.
Two-key architecture
LLM / model → structured proposal (JSON, strict schema)
↓
Deterministic validator
· schema valid?
· within the allowed action space?
· passes every hard rule (§4.2)?
· doesn't raise risk above the user's mandate?
↓
Simulator (fork of current state)
· does the simulation result match the prediction?
· does post-state HF improve?
· no unexpected transfers?
↓
On-chain PolicyGuard
last line of defense, cannot be bypassed off-chain
↓
Execution
Action space the model is allowed to touch
{
"risk_bias": -1.0 .. 0.0, // ONLY negative: reduces risk
"ticker_flags": {
"NVDA": { "elevated_event_risk": true, "reason": "..." }
},
"rebalance_urgency": "low | normal | high",
"narrative": "explanation for the user, not consumed by the machine"
}
Why risk_bias can never be positive
The model can never make the system more aggressive. If the model hallucinates, the worst case is the user becomes too conservative — not liquidated.
Where the LLM is genuinely valuable here
- Structured event extraction from news. “Is there a guidance cut, an SEC investigation, a CEO resignation, M&A, or delisting risk?” The output is a flag, not a trade signal.
- Classifying corporate actions from filings, to trigger a pause and re-index before the multiplier changes.
- Explaining things to the user. This is underrated. “I reduced your NVDA exposure by 18% on Friday afternoon because of Tuesday's earnings and weekend gap risk” is worth far more for retention than 30 bps of alpha.
- Onboarding — translating questionnaire answers into risk-profile parameters, with a deterministic sanity check.
Roles the model is never given
- Predicting price direction as a basis for leverage.
- Position sizing.
- Setting the slippage cap or the liquidation threshold.
- Anything that picks the target contract to call.
06Smart contracts
Keep it thin. Every line of Solidity is a liability.
PolicyGuard.sol
The security core. Installed as a module or validator on the user's smart account.
struct Policy {
uint64 expiry; // session key expiration
uint128 maxNotionalPerTx; // USD, via oracle
uint128 maxNotionalPerWindow; // rolling 24 hours
uint32 windowStart;
uint128 spentInWindow;
uint16 maxSlippageBps;
uint16 minHealthFactorBps; // minimum post-state HF
bool allowLeverageIncrease; // default FALSE
}
mapping(address target => mapping(bytes4 selector => bool)) allowedCalls;
function validate(address target, bytes4 sel, uint256 notional) external;
// reverts if: target/selector isn't allowlisted, the cap is exceeded,
// expiry has passed, or the agent tries to raise leverage when not permitted
Invariants that must hold and be formally verified
- The agent can never call
transferto an address outside the user's own account. - The agent can never modify the
Policy. Only the user can, via a direct signature. - A user revoke takes effect within one block, unconditionally.
- Post-state health factor must be ≥
minHealthFactorBps, checked on-chain at the end of execution.
OracleReader.sol
Safe price reads, used by every other contract.
function readPrice(address token) public view returns (uint256 price) {
// 1. sequencer uptime
(, int256 seq, uint256 startedAt,,) = sequencerUptimeFeed.latestRoundData();
require(seq == 0, "sequencer down");
require(block.timestamp - startedAt > GRACE_PERIOD, "grace period");
// 2. corporate action pause (advisory; staleness is still checked separately)
require(!IStockToken(token).oraclePaused(), "oracle paused");
// 3. read the feed + staleness
(, int256 answer,, uint256 updatedAt,) = feeds[token].latestRoundData();
require(answer > 0, "bad price");
require(block.timestamp - updatedAt <= maxStaleness[token], "stale");
return uint256(answer);
}
function effectiveBalance(address token, address user)
public view returns (uint256)
{
return IERC20(token).balanceOf(user)
* IStockToken(token).uiMultiplier() / MULTIPLIER_SCALE; // ERC-8056
}
maxStaleness is not a constant
When the market is open, 1 hour of staleness means something is wrong. On a weekend, 60 hours of staleness is normal. So maxStaleness is a function of the market calendar pushed on-chain by a keeper — or the system accepts a frozen price but forbids every action that increases risk. The second option is simpler and safer.
The remaining two contracts
ExecutionRouter.sol— safe batching: check pre-state, run the step, check post-state, revert if HF worsens.MandateRegistry.sol— stores the hash of the EIP-712 mandate signed by the user. This is both a legal and a technical artifact: on-chain proof that the user authorized a specific action space, at a specific time.
What not to write
A lending pool, a custom oracle, an AMM, or a bridge. All of these already exist and have already been audited.
07Tech stack
| Component | Choice | Why |
|---|---|---|
| Smart account | ERC-4337 via Alchemy (the chain's official bundler) or ZeroDev; EIP-7702 for users who already have an EOA | EIP-7702 matters: Robinhood Wallet users don't need to migrate addresses |
| Embedded wallet | Privy | Already used in the Robinhood stack, so it's familiar |
| RPC / node | Dedicated Alchemy plus a self-hosted node for redundancy | FCFS means latency is decisive; public RPC gets rate-limited |
| Sequencer feed | Direct WebSocket sequencer feed | See transactions before execution, early detection of stress conditions |
| Indexer | Ponder or Subsquid, self-hosted | Needs real-time positions and lending-protocol events |
| Backend | TypeScript (viem + permissionless.js), or Rust for the hot path | viem has the most mature account-abstraction support |
| Queue | Redis + BullMQ, with a dead-letter queue | Idempotency and retries are mandatory |
| Database | Postgres + TimescaleDB for price and HF time-series | A full audit trail is a legal requirement, not optional |
| Simulation | Local fork (anvil) refreshed every block, or Tenderly | Pre-flight is mandatory for every intent |
| Monitoring | Prometheus + Grafana + PagerDuty | User health factor is the SLA metric |
| Notifications | Telegram bot and push | Telegram is already proven for approval flows on this chain |
| Secrets | AWS KMS or an HSM for the agent's session key, on a scheduled rotation | Never put a plaintext key in an environment variable |
Latency budget for emergency de-risking
On a chain with 100 ms blocks and FCFS sequencing, a sub-one-second target is realistic — and it's what separates this from a five-minute cron job.
08Rebalancing engine (V2)
Risk profile to parameters
| Profile | Target annual vol | Max leverage | Max single-name | No-trade band | z |
|---|---|---|---|---|---|
| Conservative | 8% | 1.0× (no borrow) | 15% | ±5% absolute | 3.0 |
| Balanced | 14% | 1.3× | 25% | ±4% | 2.3 |
| Growth | 22% | 1.8× | 35% | ±3% | 1.8 |
Hard limits that apply across every profile: max leverage 2.0×, max single-name 40%, a minimum of 4 positions, and a minimum 5% USDG cash buffer for gas and emergency repayment.
Cost-aware rebalancing rule
Don't rebalance on a calendar. Rebalance when drift exceeds the band and the expected benefit exceeds the cost.
trade if |w_actual − w_target| > band
AND expected_benefit > (fee + slippage_est + gas) × 2.5
expected_benefit ≈ 0.5 × λ × (drift² × σ²) # mean-variance approximation
The 2.5 factor is a safety margin against estimation error. This will hold back around 70% of trades that weren't actually necessary — and that's a good thing, because churn is what kills retail returns.
Vol targeting
leverage_target = min(
target_vol / realized_vol_portfolio_20d,
max_leverage_profile,
leverage_allowed_by_session # weekend → forced down
)
Raise leverage gradually, at most +0.1× per day. Lower it immediately, with no rate limit on the way down. This asymmetry is intentional.
09Hedging with perps (V3/V4)
Before building this, it's worth understanding exactly what's involved.
What's available: Lighter, a non-custodial perps DEX integrated with Robinhood Wallet. In the EU, Robinhood also offers perps for commodities, ETFs, and FX — GOLD, SILVER, QQQ, EUR/USD, WTI, Brent — up to 10×. Single-name equity perps are generally not available.
The consequence
NVDA cannot be hedged with an NVDA perp — only with a proxy, such as a QQQ perp or a basket. This creates basis risk that can be larger than the risk being hedged, especially during idiosyncratic earnings events — exactly when the hedge matters most.
Rules that apply if this is built anyway
- Hedge market beta only, not single-name risk. Sell QQQ perps sized at
β_portfolio × notional × hedge_ratio. - Calculate funding costs explicitly. Sustained negative funding can eat returns within months. If
funding_annualizedexceeds the expected risk-reduction value, don't hedge. - Margin on Lighter is separate from collateral on the lending protocol, creating two places that can liquidate the user. This requires cross-venue margin management, and buffers on both.
- Perps TAM is narrower. The feature must be switchable off per user based on jurisdiction.
My recommendation: delay hedging until after V3. Even then, offer it only as an explicit opt-in for users who pass a knowledge check.
10Security
Threat model
| Threat | Mitigation |
|---|---|
| Agent session key leaked | Notional cap, selector allowlist, short 7-day expiry, instant revoke. Maximum loss is bounded by design, not by trust. |
| Backend compromised | On-chain PolicyGuard is a defense the backend can't bypass. Assume the backend will fall. |
| Oracle manipulation | Chainlink is push-based, hard to manipulate. The real risk isn't manipulation but staleness or pausing — handle it explicitly (section 4). |
| Sandwich / MEV during unwind | FCFS means no priority auction, but the sequencer feed is public. Use RFQ with locked-in pricing for large trades, not AMM. Split into clips. Randomize timing within the window. |
| Bad debt in a lending protocol in use | Diversify venues. Monitor utilization and bad debt. Have an automatic exit trigger for a stressed venue. |
| USDG depeg | Monitor continuously. Prepare an emergency conversion route. Never assume its value is 1.00. |
| RHJ issuer failure | Cannot be technically mitigated. Must be in the disclosure, with a total exposure cap per user. |
| Bug in Belay's own contracts | Audit by two firms, formal verification for PolicyGuard, bug bounty, staged TVL caps, timelock for upgrades. |
Circuit breaker — mandatory before mainnet
Automatic halt if:
· sequencer uptime feed is abnormal
· more than 3 consecutive failed transactions within 60 seconds
· realized slippage > 3× the estimate on any trade
· aggregate portfolio drawdown > 8% within 1 hour
· unexpected oracle staleness while the market should be open
· oracle vs. DEX divergence > 5% while the market is open
On halt: stop all new actions, notify every user,
enter read-only mode.
Resuming requires human approval. Always.
User kill switch
One button, always visible, no layered confirmations: revoke the session key and stop the agent. Must work even if the backend is down — a transaction goes straight from the user's wallet to PolicyGuard. This isn't a nice-to-have feature; it's what makes the product trustworthy.
11Legal & regulatory
None of this is legal advice. But these are issues that must go to a lawyer before onboarding the first user.
Core issues
- Discretionary portfolio management is a licensed activity. In the EU that's MiFID II. The fact that execution happens via smart contract and is non-custodial weakens part of the argument, but deciding what gets bought or sold on the user's behalf is likely to be viewed by many regulators as investment management. The strongest defense: the user sets the rules, Belay merely executes them mechanically. This is another reason V1 is far safer than V4.
- The underlying asset is a security. Stock Tokens are tokenised debt securities. Building a service on top of them is categorically different from building on top of a DeFi token.
- Entity and jurisdiction. Stock Tokens are issued by Robinhood Assets (Jersey) Limited (RHJ) — the issuing entity and its jurisdiction are stated plainly wherever the product is described. Belay's own operating entity and home jurisdiction get the same treatment: a clear local legal opinion, obtained before marketing begins in a given jurisdiction, not after.
- Restricted jurisdictions. Stock Tokens are unavailable to US persons and restricted in Canada, the UK, Switzerland, and the UAE. None of these are served or marketed to. Geo-blocking, IP screening, attestation, and clear language in the ToS are required. US regulators in particular have a history of cracking down on half-hearted “we don't target the US” claims.
- Taxes. Never give tax advice. Provide a complete transaction export so users can handle it themselves.
A structure that reduces risk
- Non-custodial, no exceptions. User assets or keys are never held. This isn't just a technical decision — it's the foundation of the legal argument.
- Explicit on-chain mandate. The user signs an EIP-712 message specifying the action space, cap, and expiry, stored in
MandateRegistry. - Rules the user can read. If a user can read and understand every rule the agent runs, the product is a tool, not a manager. Publish the rule set.
- No pooling. Every user has their own smart account. No shared vault. Pooling funds would put this squarely in collective-investment-scheme territory.
- Honest, unburied disclosure. Including RHJ issuer risk, sequencer centralization, the 24/5 oracle, the possibility the agent fails or errs, and that liquidation can still happen.
Marketing language to avoid
- “Set-and-forget”
- “Guaranteed,” “definitely safe”
- “Automatic profit”
- “Liquidation-free”
The phrase “set-and-forget” should never appear in marketing copy. “24/7 monitoring under rules you define” is the honest version, and it's easier to defend.
12Current status and limitations
What runs today
No position is being monitored. The position source is a fixture; not one RPC call is made anywhere in the service. Signups are still open — an address can be stored and a Telegram chat linked — but such a subscription is registered, not active: nothing is read from the chain for it, and neither an alert nor the daily heartbeat is ever sent to it. A heartbeat asserting that monitoring is running while nothing is being read would be a scheduled untruth, which is why the rule is enforced in code and asserted by test rather than left to copy. When a live indexer is confirmed reading the chain, every registered subscription becomes active and receives one message saying so; if that confirmation is later lost, they fall back and receive the degraded notice.
What is written and tested is the read-only half of the loop: scoring a position with the time-aware model in section 4, composing an alert, a degraded-mode notice or a daily heartbeat, and delivering it over Telegram. A subscription is a wallet address plus the Telegram chat id that results from pressing Start on the bot — the bot cannot message a username, only a chat that has opened it. Belay holds no keys, signs nothing, and builds no transactions; the user executes from their own wallet. Stages 3 and 4 of the design (the three gates and automated execution) are not built.
Alerts are best-effort. They can be delayed or missed if a data feed, Telegram, or the service's own infrastructure fails, and responsibility for the position remains entirely with the user. Alerts are rate-limited per address per day; the heartbeat is exempt from that budget so a quiet day is still distinguishable from an outage.
Caps
Caps apply to the execution product, which is not live. When it ships it opens with a $5,000 cap per position and a $100k total TVL cap, raised in stages only after each tier survives 30 days incident-free: $100k → $500k → $2M → $10M. Read-only monitoring has no TVL cap because it holds no value.
Audit status
Not yet complete. PolicyGuard is not written; it requires formal verification and at least two independent audits before any execution path handles user funds. A bug bounty runs alongside the audit process. Nothing in the read-only release touches funds.
Integrations
- Lending venues: Lends, Syndromics, and Morpho.
- Price and uptime data: Chainlink price feeds and the L2 Sequencer Uptime Feed.
- Execution venues: Uniswap, RFQ (0x, 1inch Fusion), and Rialto.
- Account infrastructure: ERC-4337 via Alchemy, EIP-7702 delegation.
Known limitations today
- Belay reports; it does not act. Every action is executed by the user, from their own wallet.
- Alerts depend on external feeds and notification channels, so they are best-effort rather than assured delivery.
- The buffer parameters have been calibrated and backtested against two years of daily data, and over that sample the policy is net negative against doing nothing — about −0.4% a year — even though it prevented every liquidation that occurred. The sample contains no gap large enough for the protection to pay for itself. That regime is the case for Belay, and it is not in the data.
- Hedging (perps) is not available in this version — see section 9.
- Rebalancing beyond the core liquidation-guardian action space is not yet live — see section 8.
- Coverage is limited to the lending venues listed above; a position on an unlisted venue isn't monitored.
13Recap
What it does
Belay is a non-custodial agent for Stock Token holders borrowing USDG on Robinhood Chain. It runs a time-aware risk engine that accounts for the gap between a 24/5 oracle and a 24/7 token, and holds three possible actions on a position: repay debt, add collateral, or unwind — ranked by the ladder in section 4.3.
Order of operations
Risk engine → policy engine → intent validator → on-chain PolicyGuard → execution. Every stage is deterministic except the advisory signal layer, which can only move risk_bias downward and never generates calldata (section 6).
Constraints
Non-custodial with a revocable session key. No pooled funds — one smart account per user. No leverage increase without explicit user action. Liquidation remains possible; the system reduces the odds, it doesn't remove the outcome.
This document is technical and product documentation, not legal, financial, or investment advice. The risk parameters mentioned are a starting point for calibration, not a recommendation. Verify all protocol details and parameters directly from official documentation before implementation — these things change fast. Version 1.0, updated September 2, 2026.