Maintenance and bots
Two categories of upkeep:
- Permissionless bounded upkeep — MaintenanceHub
- Opt-in compounding — per-user best-effort keepers
Policy: No official crown-taking bot shipped.
Self-run agents (bot-owned wallets)
A self-run agent plays from its own wallet (EOA or smart contract):
- no DelegationHub sessions
- no custody of user funds
- simplest integration surface (agent owns positions and rewards)
Recommended tooling:
- SDK entrypoint:
agents/sdk/ - Dev manual: Agents and automation
Operational defaults:
- simulate before sending
- cap spend for takeovers
- use conservative slippage floors and short deadlines
Opt-in delegated bots (DelegationHub sessions)
DelegationHub enables session-based delegation for user opt-in automation.
Why this exists:
- a bot can execute actions for a user address without taking custody
- sessions are time-limited and revocable
- protocol contracts enforce permissions onchain via
DelegationHub.isAuthorized(...)
Session shape:
delegate(bot executor)perms(bitmask)expiry(unix seconds)
Common delegated tasks:
| Task | Contract method | Required permission |
|---|---|---|
| Take over Crown for a user | MineCore.takeoverFor(user) | P_TAKEOVER_FOR |
| Update reign payout routing | MineCore.setCurrentReignRecipients(...) | P_SET_REIGN_ETH_RECIPIENT / P_SET_REIGN_ETH_RECIPIENT_TO_CALLER_ONLY and/or P_SET_REIGN_CLAIM_RECIPIENT / P_SET_REIGN_CLAIM_RECIPIENT_TO_USER_ONLY |
| Claim Barons rewards | ClaimAllHelper.claimShareholderForUser(user, ...) | P_CLAIM_SHAREHOLDER_FOR |
| Withdraw King fallback bucket | ClaimAllHelper.withdrawKingBalanceForUser(user) | P_WITHDRAW_KING_BUCKET_FOR |
| Claim all (bundle) | ClaimAllHelper.claimAllFor(user, ...) | P_CLAIM_ALL_FOR |
| Enter Furnace for a user (bot pays) | Furnace.enterWithEthFor(user, ...) | P_FURNACE_ENTER_ETH_FOR |
| Maintain veCLAIM lock (extend) | VeClaimNFT.extendLockForUser(user, tokenId, ...) | P_VE_EXTEND_LOCK_FOR |
| Maintain veCLAIM locks (merge) | VeClaimNFT.mergeLocksForUser(user, fromTokenId, intoTokenId) | P_VE_MERGE_LOCKS_FOR |
| Unlock expired veCLAIM lock | VeClaimNFT.unlockExpiredForUser(user, tokenId) | P_VE_UNLOCK_EXPIRED_FOR |
| Update King auto-lock config | MineCore.setKingAutoLockConfigForUser(user, ...) | P_SET_KING_AUTO_LOCK_CONFIG_FOR |
| Update Barons auto-compound config | ShareholderRoyalties.setAutoCompoundConfigForUser(user, ...) | P_SET_SHAREHOLDER_AUTOCOMPOUND_CONFIG_FOR |
| Update vault auto-compound config | LpStakingVault7D.setAutoCompoundConfigForUser(user, ...) | P_SET_LP_AUTOCOMPOUND_CONFIG_FOR |
Notes:
- Delegated takeover defaults to routing the dethroned-King 75% ETH payout to the bot executor (to support looping).
- King-stream mined CLAIM stays with the user unless the session grants
P_ROUTE_REIGN_CLAIM_TO_CALLER. - Under contention, reverts are normal. Read price right before sending and avoid leaving txs pending for long.
Next reads:
- Full permission map: Bot sessions (DelegationHub)
- SDK examples:
agents/sdk→example:delegation,example:agent -- --acting-for <user> - Example: Run a Crown bot (takeover at 30 minutes)
MaintenanceHub.poke
Signature: poke(PokeArgs args)
PokeArgs (ABI order):
| Field | Purpose |
|---|---|
offerIds: uint256[] | Buy intent IDs (bonus target escrows) to execute |
maxOffers: uint256 | Clamped to MAX_MAINTENANCE_OFFERS_PER_CALL=25 |
deadline: uint256 | Aerodrome swap deadline |
minClaimOutStaking: uint256 | Slippage for staking harvest swap |
What poke does (best-effort, never reverts on subcall failure):
- MarketRouter:
executeAutoFurnacefor up to N escrowIds - VeClaimNFT:
checkpointGlobalState()+checkpointTotalVe() - ShareholderRoyalties:
flushPendingShareholderETH() - Furnace:
tick()— accrues LP rewards stream and overflow drip - LpStakingVault7D:
harvestFeesToRewards(deadline, minClaimOut) - Forward any WETH bounty to caller
Keeper patterns
| Task | Method | Bound |
|---|---|---|
| Shareholder auto-compound | ShareholderRoyalties.compoundForMany(users[]) | 25 users/call |
| Vault auto-compound | LpStakingVault7D.compoundForMany(users[]) | 25 users/call |
| Settle listed locks | MarketRouter.sellListedLockToFurnace(tokenId) | 25 listings/sweep |
| Cancel expired listings | MarketRouter.cancelExpiredListing(tokenId) | 25 listings/sweep |
| Expire buy intents (bonus target escrows) | MarketRouter.cancelExpiredBonusTargetEscrow(offerId) | 25 intents/sweep |
Sweep listings task
Settles Market listings (limit sells) when the net payout meets or exceeds the seller’s Minimum payout (minClaimOut):
- Scan for
LockListedevents to find active listings (trackexpiresAtTime) - If
block.timestamp > expiresAtTime: callcancelExpiredListing(tokenId)(permissionless cleanup) - Otherwise, compute a net payout from the live quote (after duration penalty) and check if
claimOutNet >= minClaimOut - Call
sellListedLockToFurnace(tokenId)to settle
Expire buy intents task
Cancels expired Buy intents (bonus target escrows) and refunds remaining budget to buyers:
- Scan for active buy intents via bonus target escrow events
- Check if
block.timestamp > intent.expiresAt - Call
cancelExpiredBonusTargetEscrow(offerId)to refund
Guidance:
- Treat compound calls as best-effort
- Surface pause reasons in UX
- Use conservative minVeOut from Furnace quotes
Slippage and deadlines
| Concept | Usage |
|---|---|
minClaimOut | Aerodrome swaps (harvest paths) |
minVeOut | Furnace entry / compounding paths |
Typical defaults:
- Swap slippage: 0.5–1%
- ve slippage: 0.5–1%
- Deadline:
now + 120s