Router security, in the open

When you hand Agripinaa's yield agent a session key, the key is scoped to one contract: the AgripinaaYieldRouter. Your funds never leave your own smart account, and the agent's only power is to move them between Aave, Venus, and idle. The published deployments are below with contract custody and a bounded permissionless activity sample. Those events prove router execution, not a managed mandate or which agent or owner signed.

Live on BNB Smart Chain since 2026-08-26, created in block 118,230,700. The rotation scan below covers every block since.

Inside the router
0.00USDT
The router is designed to custody nothing between calls. Any nonzero value here is stranded or in-flight contract balance, not managed AUM.

BNB Smart Chain·as of

Recent permissionless router activity sample

A time-stratified sample of raw calls of at least 0.01 USDT, capped per account and block window. It is not exhaustive and is not proof of a managed mandate or signer. View the complete contract log.

No display-eligible activity found between block 118,230,700 and block 118,376,103.

USDC router

Reading balances and rotation history from BNB Smart Chain.

Why a compromised agent key cannot drain these funds

A session key on BNB Smart Chain can be scoped to a target contract and a set of selectors, but not to the arguments of a call. Scope an agent to Aave's withdraw(asset, amount, to) and it picks to itself. The router exists to take that choice away. Every claim below is in contracts/src/AgripinaaYieldRouter.sol.

  • Three entrypoints, none of which takes an argument

    toAave() (0xdb1a4d6d), toVenus() (0x88b480df), and toIdle() (0x18b5e866). A key scoped to this address and these three selectors has nothing left to choose beyond which of the three to call.

  • Every recipient is hardcoded to msg.sender

    Aave mints its aTokens straight to the calling account, the Venus vTokens minted in a call are transferred back to it, and an unwind sends the stablecoin back to it. The contract has no address parameter anywhere for a caller to point at itself.

  • Delta accounting, so a donation cannot be swept

    _collectUsdt records the router's balance on entry and pays out only what that call brought in. Anything sitting in the router beforehand, whether a stray transfer or a deliberate donation, stays where it is. This is the fix for audit finding L-1, and it is why the router being empty is a property rather than a coincidence.

  • No owner, no admin, no upgrade path

    No owner variable, no privileged role, no proxy, no delegatecall, no selfdestruct. Runtime bytecode cannot change after deployment, so a security fix requires a new address instead of silently changing either contract above.

What the fuzzers checked

contracts/test/fuzz/RouterFuzz.sol drives deposits, rotations, withdrawals, and out-of-band donations across three independent actors, against mocks of BSC USDT, Aave V3, and Venus. It asserts two properties:

  • echidna_no_actor_exceeds_deposits: no actor ever holds more value than they deposited, so an attacker who deposited nothing ends with nothing, and nobody sweeps another actor's principal.
  • echidna_router_holds_only_donations: the router never custodies more than what was donated to it.

The repository runs stateful Medusa properties alongside fork tests against BNB Smart Chain state, including donated balances, ordinary venue debt, Venus VAI debt, same-target no-ops, and zero-share mint protection.

Debt guard deployment status

A compromised session key cannot move funds anywhere except back to their owner. That is the property the design above enforces and the fuzzing covers, and it is the whole claim: not that a compromised key is harmless, only that it has nowhere to send anything.

The published 2026-08-26 addresses are debt-guard version 3. They cover Aave aggregate debt, ordinary Venus market borrows, and Venus's separate VAI debt ledger. Their runtime hashes are pinned in the shared manifest and checked against live bytecode before activation or runner execution. Superseded version-2 and version-1 addresses remain owner-recovery-only; an old session cannot authorize either active replacement address.

Source: contracts/src/AgripinaaYieldRouter.sol, contracts/test/AgripinaaYieldRouter.t.sol, and contracts/test/fuzz/RouterFuzz.sol in this repository. Contract custody and raw calls on this page are read from BNB Smart Chain, not from a managed-session indexer.