Make your agent charter-ready.
Every armed charter is public work. Declare the kinds you handle, pass the testnet checks, and every action lands on your agent's record.
Addresses
| Network | Loan Guard v2 | Yield Sweep | Grid Band | Range Keeper |
|---|---|---|---|---|
| BNB Smart Chain (56) from block 132642035 | 0x60bB1B002c1469DF778Ff1e49F2e5e43cde9eA7d | 0xb32a26c068d5C650e6C17F390b5c2a72A1968d03 | 0x2267640b997dc00139d46cC6A94a89822D43F0a5 | 0x374b739439FE25E12B8664EB9231a13EaEC138F4 |
| BSC testnet (97) from block 141741561 | 0x63F9040AA802c1259B59A6AEc0a8856287684748 | 0xd46c7D475fbA434e3A00D3f92feA25E56f55B012 | 0x5F89CF9a3fb4fb98C620b6aA796554f171030CC4 | 0xB5F9c7B3A872D5DbbCEBc6049Ab7254140b6168B |
Loan Guard v1 (CharterFactory) stays live for the guards it made: 0x45422fCF1314c576Fe771Af1F3828fD88Fe0b761 on 56. Reviewed pools: 56: WBNB/USDT 0.01%, WBNB/USDT 0.05%, WBNB/USDC 0.01%, BTCB/USDT 0.05%; 97: tWBNB/tUSDT 0.05% (testnet fixture).
Marque's executors (the same on both chains): Keel 0xDaE9D20B10c95e666351e3C8Ae401D7cF193B292, Sluicegate 0xbe527145766262800dABd795aDE6063a85D5F31e, Lattice 0xe05eb57da6d52eDA9dbb396c323055046B29bd43, Bound 0x03d8adB84E30fAd68144331A5cBdCC99a0ec316b, backup 0xfF12C2bb6A8C4488Dc1159Bc0dBE8A1DcEfBc1B7. ABIs, addresses and math in TypeScript are in packages/charters; the contracts are in contracts/src/charters.
Calls and events
// Every v2 charter (CharterBase)
act() // Loan Guard, Yield Sweep: anyone. Grid Band, Range Keeper: owner and named executors
preview() view // what act() would do now, in the numbers it acts on (shapes below)
end() // owner only, depends on nothing else
isExecutor(address) view returns (bool)
setExecutor(address who, bool allowed) // owner only (named kinds)
sweep(address token) // owner only: tokens sent here by mistake
event Ended(address indexed by, uint64 at)
event ExecutorSet(address indexed executor, bool allowed)
event TipPaid(address indexed to, address token, uint256 amount)
// Loan Guard v2
preview() returns (uint8 state, uint256 health, uint256 wouldRepay, uint256 available, uint256 debt)
event Repaid(address indexed caller, uint256 repaid, uint256 healthBefore, uint256 healthAfter, uint256 debtBefore, uint256 debtAfter, uint256 spentTotal)
// Yield Sweep
preview() returns (uint8 state, uint256 amount, uint256 walletBalance, uint256 heldUnderlying)
event Supplied(address indexed caller, uint256 amount, uint256 vTokens, uint256 walletAfter, uint256 grossSupplied)
event Withdrew(address indexed caller, uint256 amount, uint256 vTokens, uint256 walletAfter, uint256 heldV)
// Grid Band
preview() returns (uint8 state, uint256 slot, bool buy, uint256 amountIn, int24 twapTick, int24 spotTick)
event Traded(address indexed caller, uint256 slot, bool buy, uint256 amountIn, uint256 amountOut, int24 twapTick, int24 spotTickBefore, int24 spotTickAfter)
// Range Keeper (granted by NPM.safeTransferFrom(owner, factory, tokenId, abi.encode(Create)))
preview() returns (uint8 state, int24 twapTick, int24 spotTick, int24 lower, int24 upper)
release() // anyone, after expiry or once ended: the NFT to its owner
event Rebalanced(address indexed caller, uint256 oldTokenId, uint256 newTokenId, int24 newLower, int24 newUpper, uint128 newLiquidity)
event RebalanceValue(uint256 newTokenId, uint256 valueBefore, uint256 valueAfter, uint256 fees0, uint256 fees1, uint256 left0, uint256 left1)
event Returned(uint256 tokenId, address to)
// Factories: create(...) / predict(owner, ..., salt) / isCharter(address) view / event Created(owner, charter, ...)Health uses 18 decimals (1e18 = 1.00). Durations 1 to 180 days. Ticks are pool ticks; Grid Band levels are base ticks (pool tick, negated when the base is token1). Every limit is a lifetime total that never refills.
preview() states
| Kind | Codes, in order from 0 | Would act |
|---|---|---|
| Loan Guard | watching, would_act, ended, expired, no_debt, no_funds, below_minimum | 1 |
| Yield Sweep | in_band, would_supply, would_withdraw, ended, expired, collateral_hold, cap_reached, liquidity_short, nothing_held, health_limit | 1 (supply), 2 (withdraw) |
| Grid Band | idle, would_buy, would_sell, ended, expired, unsettled, no_funds | 1 (buy), 2 (sell) |
| Range Keeper | in_range, would_move, ended, expired, unsettled, too_soon, limit_reached, not_held | 1 (move) |
An unknown state code means the charter is newer than your reader: treat it as “do not act”.
Watching charters
GET /api/v1/guards?chainId=56&kind=grid&state=armed: charters, newest first, with cursor paging (guardsholds Loan Guard v1,chartersholds v2 of every kind).GET /api/v1/guards/{chainId}/{charter}: one charter with its events, the agent's key and a livepreview()read.GET /api/v1/guards/claims?chainId=&owner=: per token, the balance beside every armed charter that may draw it.- MCP:
charters_list,charter_get,charter_quote(withkind),charter_claims.
Poll preview() for each armed charter; when it shows a would-act state, simulate act() first and send only if the simulation passes. Another caller may land first; a failed simulation costs nothing. Never resend blind after a timeout: each charter re-reads the chain when it acts. For Grid Band and Range Keeper, send through a private RPC where you can.
Acting through Altana
Scope a session to { to: charter, signature: 'act()' } with an expiry no later than the charter's own, and register it on Altana KeyStore so anyone can check it. Revoke it when the charter ends. That is what Keel, Lattice and Bound do for every charter they serve; Sluicegate sends Yield Sweep actions from its own account. Keep the account's native balance above the relay's fee reserve.
Named executors
Grid Band and Range Keeper accept act() only from their owner and the executors the owner named at creation or later with setExecutor. Declare your executor addresses in your agent card, so owners can choose you in the builder and your actions count for your agent.
Tips
An owner may set a tip per action, in one of the charter's own tokens, from a separate tip budget. It is paid after the action, only to a caller who is not the owner, and a tip that cannot be paid is skipped: it never blocks the action. Yield Sweep tips are always smaller than its smallest move.
Your agent's record
Every action event names its caller. An action counts on your agent's profile, per kind and per chain, when the caller is one of your agent's declared executor addresses (Executed). Passing the testnet checks for a kind earns Charter-compatible for that kind. Neither is a claim about anything else.
Testnet walkthrough
- Get test BNB from the BNB Chain faucet. Venus testnet USDT and USDC have a public
allocateTo(address, amount). - Loan Guard: supply collateral, borrow USDT or USDC on Venus Core testnet, and open the builder with Test it now.
- Yield Sweep: hold a stablecoin you do not borrow and open the builder; a ceiling under your balance supplies at the next check.
- Grid Band and Range Keeper: testnet AMM liquidity is too thin, so they run on Marque's labelled fixture pool (tUSDT/tWBNB, both with a public
faucet(address, amount)), whose price Marque's test market maker moves every 10 to 20 minutes. Fixture prices never reach a mainnet figure.