Dynamo is a savings vault for tokenized stocks, designed to fund its own upkeep — so the activity that keeps it alive doesn't depend on subsidies that eventually run out. Robinhood's own gas subsidy ends September 29; this loop doesn't need it to keep running.
Transactions need gas. Vaults need maintenance. Positions need rebalancing. Today, those costs are usually covered by temporary incentives or a centralized subsidy — which works during launch, and stops working the moment the subsidy does.
A user deposits USDG. The contract automatically splits it across Stock Tokens at fixed weights, and anyone can trigger a rebalance once the basket drifts too far from target — without the user ever bridging, swapping, or timing the market themselves.
function deposit(uint256 usdgAmount, uint256[] calldata minOuts) external nonReentrant returns (uint256 sharesOut) { require(usdgAmount > 0, "zero deposit"); uint256 totalValueBefore = totalAssetsValueUsd(); depositAsset.safeTransferFrom(msg.sender, address(this), usdgAmount); // split the deposit across the basket at target weights for (uint256 i = 0; i < assets.length; i++) { uint256 portion = (usdgAmount * assets[i].targetBps) / BPS_DENOMINATOR; if (portion == 0) continue; depositAsset.forceApprove(address(swapRouter), portion); swapRouter.swapExactInput(address(depositAsset), assets[i].token, portion, minOuts[i], address(this)); } sharesOut = totalSupply() == 0 ? usdgAmount : (usdgAmount * totalSupply()) / totalValueBefore; _mint(msg.sender, sharesOut); emit Deposited(msg.sender, usdgAmount, sharesOut); }
Every deposit accrues a 0.50% annualized fee. Instead of sitting idle, that fee is swept, swapped to ETH, and dropped straight into the vault's own DynamoGasSponsor policy — the same policy that sponsors the keepers who call rebalance(). A bigger basket means a bigger fee, which means more sponsored keeper calls, which means the basket stays closer to target, which is what makes the vault worth holding in the first place.
accrueAndFundKeeperGas() is openrebalance() against the policyfunction accrueAndFundKeeperGas(uint256 minEthOut) external nonReentrant returns (uint256 ethFunded) { require(address(gasSponsor) != address(0), "gas sponsor not configured"); uint256 elapsed = block.timestamp - lastFeeAccrual; lastFeeAccrual = block.timestamp; if (elapsed == 0) return 0; // 0.50%/yr on TVL, pro-rated by elapsed time since the last sweep uint256 feeUsdg = (totalAssetsValueUsd() * managementFeeBps * elapsed) / (uint256(BPS_DENOMINATOR) * 365 days); if (feeUsdg == 0) return 0; // deposit() sweeps 100% of inflows into the basket, so idle USDG is // normally zero — sell a pro-rata slice of the basket first uint256 available = depositAsset.balanceOf(address(this)); if (available < feeUsdg) { _raiseUsdg(feeUsdg - available); available = depositAsset.balanceOf(address(this)); } if (feeUsdg > available) feeUsdg = available; if (feeUsdg == 0) return 0; depositAsset.forceApprove(address(swapRouter), feeUsdg); uint256 wethOut = swapRouter.swapExactInput( address(depositAsset), address(weth), feeUsdg, minEthOut, address(this) ); weth.withdraw(wethOut); gasSponsor.fundPolicy{value: wethOut}(keeperPolicyId); emit KeeperGasFunded(feeUsdg, wethOut); }
Robinhood's own gas subsidy ends September 29. This is the paymaster contract the vault funds itself against: a project registers a policy with a daily cap, funds it in ETH, and lets users and keepers transact without holding gas themselves. DynamoVault is simply its first, self-funding tenant — any other project can register a policy the same way and fund it manually instead.
function validatePaymasterUserOp( PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost ) external override onlyEntryPoint returns (bytes memory context, uint256 validationData) { bytes32 policyId = _extractPolicyId(userOp.paymasterAndData); Policy storage policy = policies[policyId]; require(policy.active, "policy inactive"); require(policy.perOpCapWei == 0 || maxCost <= policy.perOpCapWei, "exceeds per-op cap"); uint256 spendable = _spendableThisWindow(policy); require(maxCost <= spendable, "exceeds daily cap"); require(policy.balance >= maxCost, "policy underfunded"); context = abi.encode(policyId, userOp.sender); validationData = 0; }
Illustrative feed — deposits into the vault, fee sweeps into the gas policy, and the sponsored rebalances they pay for, in the order they'd emit on-chain.
0x9F1c…4Ad2 — sponsored, 0 ETH paid
—
2m ago
accrueAndFundKeeperGas() → policy balance
+0.014 ETH
14m ago
0x7Ae2…11Fb → 2,391.02 DYNAMO minted
2,400 USDG
41m ago
0x4C0a…9E71 — sponsored, 0 ETH paid
—
1h ago
0x1Bd4…77Ac → pro-rata basket assets
610.00 DYNAMO
3h ago
The next generation of onchain finance won't be judged only by how quickly it launches. It will be judged by whether it can keep operating once the incentives disappear.
That is the difference between an experiment and an economy.