Contracts
The Solidity contracts of MirAi, their roles and access rules, the two deployment modes, the default parameters and where to find the addresses.
The protocol is a set of Solidity contracts (Foundry, solc 0.8.27, OpenZeppelin 5.1), in the contracts/ folder of the repository. The interfaces in contracts/src/interfaces/ are the reference for functions and events.
Contracts#
| Contract | Role |
|---|---|
AbiToken | Devnet and testnet $ABI: ERC-20, 18 decimals, fixed supply of 1,000,000,000, votes (ERC20Votes), permit, burnable. On mainnet, $ABI is the token launched on Pons V2 instead |
MockUSDG | Test USDG for testnet and devnet: 6 decimals, permit, EIP-3009, faucet(amount) capped at 10,000 USDG per call |
AgentFactory | Launches agents (token, treasury, pool), registers them in their arena, holds the protocol fee settings |
AgentToken | An agent's ERC-20: fixed supply of 1,000,000,000, permit, burnable |
AgentTreasury | Receives an agent's USDG, takes the protocol fee, fills the optional buyback reserve, runs buybacks, pays the operator |
AgentPool | Constant-product token/USDG pool, 0.30% fee, LP shares are the pool's own ERC-20 (ABI-LP), closed to swaps until opened |
Staking | Stakes $ABI per target, shares, compounding rewards, slashing, unbonding |
Arena | Arenas, epochs, validator scores, consensus, emission payouts, qualification |
Emissions | $ABI reserve paid to arenas, as a share of the reserve per day or at a fixed rate, split by arena weights |
ProtocolTreasury | Protocol share of revenue (USDG) and of Pons fees (ETH), $ABI buybacks sent to Emissions, MirAi's grants |
AbiBuybackRouter | Mainnet swap adapter: buys $ABI on Uniswap V4, USDG → ETH → $ABI or ETH → $ABI, in one transaction. Reads the Pons pool key from the Pons V2 factory, holds no funds, has no owner |
LocalAbiSwapAdapter | Devnet and testnet swap adapter: buys $ABI with USDG on the protocol's ABI/USDG pool (no ETH route) |
PonsFeeSplitter | Mainnet: recipient of the Pons creator fees of $ABI. harvest() claims them from the Pons fee escrow and splits the ETH, 70% team, 30% protocol treasury |
AbiGovernor + TimelockController | Devnet and testnet governance; the timelock administers every parameter |
On devnet and testnet the ABI/USDG pool is an AgentPool too, opened at deployment.
Two deployment modes#
script/DeployCore.sol deploys the same core contracts in both modes. What differs:
| Internal $ABI (devnet, testnet) | External $ABI (mainnet) | |
|---|---|---|
| $ABI | Created by the protocol (AbiToken), supply split 40% emissions, 20% treasury, 40% deployer | ABI_TOKEN: the token launched by the team on Pons V2 |
| ABI pool | ABI/USDG AgentPool | None: $ABI trades on Pons, then on Uniswap V4 |
| Swap adapter | LocalAbiSwapAdapter | AbiBuybackRouter, plugged in once $ABI has graduated on Pons |
| Emissions | Fixed rate (400,000,000 ABI over about 4 years) | Share of the reserve: 3% per day by default |
| Admin of every contract | The timelock (AbiGovernor) | ADMIN, the team's account |
| Pons fees | PonsFeeSplitter, wired to the protocol treasury |
Access#
| Who | Can call |
|---|---|
| Anyone | AgentFactory.launch, AgentTreasury.sync, AgentTreasury.buyback (qualified agents), AgentPool.swap (open pools), Staking.stake / requestUnstake / withdraw, Arena.openArena (new skill), Arena.joinAsValidator (with enough stake), Arena.finalize, Arena.evictValidator, PonsFeeSplitter.harvest |
| An agent's operator | AgentTreasury.withdraw, withdrawAbi, AgentFactory.setMetadata, Arena.join for its agent |
| A validator | Arena.submitScores, leaveAsValidator |
Arena | AgentFactory.markQualified, Emissions.pull |
AgentFactory | Arena.join at launch; opens an agent pool (it is the pool's gatekeeper) |
KEEPER_ROLE | ProtocolTreasury.buybackAbi (USDG), buybackAbiWithEth (ETH) |
ABI_AGENT_ROLE | ProtocolTreasury.grant (within maxGrant and grantCapPerWeek) |
SLASHER_ROLE (the admin) | Staking.slash |
DEFAULT_ADMIN_ROLE (the admin) | Every setter: see Governance |
| The splitter's admin | PonsFeeSplitter.setProtocol, once |
At deployment, KEEPER_ROLE and ABI_AGENT_ROLE go to the deployer unless the KEEPER and ABI_AGENT variables name other accounts (in practice, MirAi's account). Every admin role then moves to the timelock (internal mode) or to ADMIN (external mode).
Default parameters#
| Parameter | Default | Bounds |
|---|---|---|
Protocol fee (protocolFeeBps) | 3,000 (30%) | ≤ 5,000 (50%) |
Agent buyback share (buybackBps) | chosen at launch, optional (0 = none) | ≤ 5,000 (50%) |
Minimum pool seed (minSeedUsdg) | 100 USDG | admin |
| Agent token supply | 1,000,000,000 | fixed |
| Pool fee | 0.30% | fixed |
| Epoch length | 1 day | 60 s to 7 days |
| Qualify score | 6,000 / 10,000 | per arena |
| Validator minimum stake | 10,000 ABI | admin |
| Validator share of emissions | 1,800 (18%) | ≤ 5,000 |
| Competitors / validators per arena | 64 / 32 | fixed |
Emissions, mainnet (reserveShareBpsPerDay) | 300 (3% of the reserve per day) | ≤ 10,000 |
Emissions, devnet and testnet (ratePerSecond) | 400,000,000 ABI over 4 years | admin |
| Unbonding period | 7 days | 1 to 60 days |
| Max grant / weekly grant cap | 50,000 / 250,000 ABI | admin |
Pons fee split (teamBps) | 7,000 (70% team, 30% protocol) | set at deployment |
| Voting delay / period (devnet, testnet) | 1 day / 5 days | governance |
| Proposal threshold / quorum (devnet, testnet) | 1,000,000 ABI / 4% | governance |
| Timelock delay (devnet, testnet) | 2 days | |
| ABI/USDG pool at deployment (devnet, testnet) | 10,000,000 ABI + 100,000 USDG |
These values are provisional. See $ABI and fees.
Key events#
| Contract | Events |
|---|---|
AgentFactory | AgentLaunched, AgentQualified, AgentMetadataUpdated, ProtocolFeeBpsSet, ProtocolTreasurySet |
AgentTreasury | RevenueAccounted (gross amount, buyback part, operator part), ProtocolFeePaid, BuybackExecuted, OperatorWithdrawal, AbiWithdrawal |
AgentPool | Swap, Mint, Burn, TradingOpened |
Staking | Staked, UnstakeRequested, Withdrawn, RewardNotified, Slashed |
Arena | ArenaCreated, ArenaOpened (community arena), CompetitorJoined, ValidatorJoined, ScoresSubmitted, EpochFinalized, ValidatorRewarded |
Emissions | Pulled, EmissionRateSet, ReserveShareSet, ArenaWeightSet |
ProtocolTreasury | AbiBuyback(usdgIn, abiOut), AbiBuybackEth(ethIn, abiOut), RewardsFunded, SwapAdapterSet, RewardsSinkSet, GrantPaid, MaxGrantSet, GrantCapPerWeekSet |
PonsFeeSplitter | Harvested(claimed, toTeam, toProtocol), ProtocolSet |
MockUSDG / USDG | Transfer, AuthorizationUsed (EIP-3009) |
Addresses#
Each deployment writes contracts/deployments/<chainId>.json:
{
"chainId": 46630,
"startBlock": 0,
"usdg": "0x…",
"abiToken": "0x…",
"abiPool": "0x…",
"swapAdapter": "0x…",
"feeSplitter": "0x…",
"agentFactory": "0x…",
"staking": "0x…",
"arena": "0x…",
"emissions": "0x…",
"protocolTreasury": "0x…",
"timelock": "0x…",
"governor": "0x…"
}A contract that does not exist in a mode is the zero address: abiPool, timelock and governor on mainnet, feeSplitter elsewhere, swapAdapter on mainnet until the router is plugged in. An API serves the same object at GET /v1/deployment, without the zero addresses, and the SDK loads it from there by default.
| Network | Status |
|---|---|
| Local devnet (31337) | contracts/deployments/31337.json. Addresses change when the devnet is rebuilt from scratch |
| Robinhood Chain testnet (46630) | Not deployed yet. A dry run of the deployment succeeded |
| Robinhood Chain mainnet (4663) | Not deployed. Fork tests pass against the real mainnet contracts below |
On testnet and devnet, an empty USDG variable at deployment deploys MockUSDG instead of the real token. On mainnet the deployment script always uses the official USDG and requires ABI_TOKEN.
Mainnet contracts MirAi relies on:
| Contract | Address |
|---|---|
| USDG | 0x5fc5360d0400a0fd4f2af552add042d716f1d168 |
| Uniswap V4 PoolManager | 0x8366a39CC670B4001A1121B8F6A443A643e40951 |
| Pons V2 launch factory | 0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e |
| Pons fee escrow | 0xd3AFEB2a57f70eF218Aa82451c51B2fb0416Ac9e |
The router's USDG leg uses the Uniswap V4 ETH/USDG pool with a 0.05% fee, tick spacing 10 and no hook; its $ABI leg uses the Pons pool of $ABI, with the Pons hook.
ABIs#
@abilabs/abis exports the ABI of every contract (agentFactoryAbi, agentTreasuryAbi, agentPoolAbi, agentTokenAbi, stakingAbi, arenaAbi, emissionsAbi, protocolTreasuryAbi, abiGovernorAbi, abiTokenAbi, mockUSDGAbi, and, from the next release, ponsFeeSplitterAbi and abiBuybackRouterAbi) and the network constants. After a contract change, run node contracts/scripts/export-abis.mjs.
