Core Contracts Reference
Technical reference for the V2 core contracts: USDx (the token) and the market contract, USDxMarket + MarketConfig. Axis is a market protocol, not a stablecoin-minting protocol: USDxMarket is a market contract, not a minting contract, it exposes buy/sell (market-order) settlement of USDx, the set of supported assets, EIP-712 signature verification, and the per-block max-mint / max-redeem limits. Minting and redemption are simply the buy and sell sides of that market. For design rationale, see Architecture. For the yield-token vault and its ERC-7540 staking functions, see Staking Contracts. For the full role map, see Access Control. For at-launch addresses, see Contract Addresses. Terminology follows the canonical Protocol Taxonomy.
All three contracts are upgradeable behind TransparentUpgradeableProxy (transparent proxy + ProxyAdmin); each implementation disables its initializers in the constructor and exposes a one-shot initialize that runs once behind the proxy and grants DEFAULT_ADMIN_ROLE. Supply, settlement policy, and capacity accounting are split across the three contracts so that no single surface holds both execution and configuration authority.
USDx
Verified source: read on Etherscan Inherits: Initializable, IUSDx, ERC20PermitUpgradeable, AccessControlUpgradeable
The Axis Dollar: an upgradeable ERC-20 (with ERC20Permit) synthetic dollar with role-gated supply, bridge, pause, and restriction controls. Every balance-changing path, transfer, mint, burn, funnels through _update, the single enforcement point for pause and blacklist checks. Supply changes are approved primary market or bridge flows, never open user actions. Issuer: Coordinate Origin Limited. 18 decimals (ERC-20 default).
Roles
Role identifiers are defined once protocol-wide and exposed as public constants on the token.
MARKET_ROLE
Primary market supply authority, the only role that can call mint. Held by the USDxMarket contract so all issuance flows through settled orders. The only live launch supply authority.
BRIDGE_ROLE
Cross-chain supply authority for bridgeMint / bridgeBurn. Defined in code but intentionally not granted at initialization, no live holder at V2 launch.
RESTRICTION_ROLE
Sets and clears the blacklist via blacklist / unBlacklist. Can restrict but never mint, burn, or seize.
PAUSER_ROLE
Emergency pause/unpause of all token balance changes via pause / unpause.
DEFAULT_ADMIN_ROLE
Admin over every other role (grant/revoke). Granted to the governance admin at initialize. See Access Control for the launch key model.
State Variables
_paused
bool
Global pause flag (read via paused()).
_blacklisted
mapping(address => bool)
Per-account restriction flag (read via isBlacklisted()).
Functions
initialize
Sets token metadata (name "USDx", symbol "USDx", ERC20Permit name "USDx") and grants DEFAULT_ADMIN_ROLE to admin. Runs exactly once behind the proxy.
Reverts: ZeroAddress(), admin == address(0).
mint
Mint amount USDx to to. Only callable by the MARKET_ROLE holder (USDxMarket). Routes through _update, so it reverts while paused or when to is blacklisted.
Reverts: ZeroAddress(), to == address(0); plus _update guards (OperationPaused, RestrictedAddress).
Events: ERC-20 Transfer(address(0), to, amount).
burn
Destroys amount USDx from the caller's own balance. Permissionless on the caller's balance, redemption burns are effected by the market spending an approval via burnFrom. Routes through _update.
burnFrom
Spends the caller's allowance over from, then burns amount USDx from from. Used by USDxMarket to settle redemptions. Rejects a blacklisted spender before spending the allowance.
Reverts: RestrictedAddress(spender), caller is blacklisted; ZeroAddress(), from == address(0); plus _update guards.
transferFrom
Standard ERC-20 transferFrom, additionally rejecting a blacklisted spender (msg.sender) before delegating to the base implementation.
Reverts: RestrictedAddress(spender), caller is blacklisted; plus _update guards.
bridgeMint
Cross-chain supply primitive: mints amount USDx to to on this chain. Moves supply between chains without changing global supply, each chain's totalSupply() is local only; global supply is reconciled offchain. BRIDGE_ROLE has no live holder at launch.
Reverts: ZeroAddress(), to == address(0).
Events: BridgeMint(msg.sender, to, amount).
bridgeBurn
Cross-chain supply primitive: burns amount USDx from the bridge caller.
Events: BridgeBurn(msg.sender, msg.sender, amount).
blacklist / unBlacklist
Set or clear account's restriction flag. Circle-compatible adapter, enforced centrally in _update: a blacklisted address is blocked from sending, receiving, minting, and burning, and cannot be a spender. Deliberately omits USDT-style seizure, funds are frozen, never taken.
Reverts: ZeroAddress(), account == address(0).
Events: Blacklisted(account) / UnBlacklisted(account).
pause / unpause
Halt or restore all USDx balance changes. While paused, _update, approve, and permit all revert.
Events: Paused(msg.sender) / Unpaused(msg.sender).
paused / isBlacklisted
Read the pause flag and per-account restriction flag.
approve / permit / nonces
Standard ERC20 / ERC20Permit surface. approve and permit additionally revert while the token is paused (_requireNotPaused). nonces returns the permit nonce for owner.
_update (internal)
The single balance-change guard for every transfer, mint, and burn. Reverts OperationPaused() while paused, and RestrictedAddress(from) / RestrictedAddress(to) if either party is blacklisted, before delegating to the base ERC-20 update.
Events
Blacklisted
address account
UnBlacklisted
address account
Paused
address account
Unpaused
address account
BridgeMint
address caller, address to, uint256 amount
BridgeBurn
address caller, address from, uint256 amount
(Plus standard ERC-20 Transfer / Approval.)
Errors
ZeroAddress()
Zero address where a non-zero one is required
RestrictedAddress(address)
A blacklisted party in a transfer, mint, burn, or spend
OperationPaused()
Any balance change, approve, or permit while paused
USDxMarket
Verified source: read on Etherscan Inherits: Initializable, IUSDxMarket, AccessControlUpgradeable
The market contract, not a minting contract: it validates signed EIP-712 market orders and settles them exactly once, executing the buy side (mint) or sell side (redeem) of USDx against approved routes, channels, and capacity limits. Order validation, nonce use, cap checks, and asset movement are sequenced so a failed settlement consumes neither a nonce nor capacity. USDxMarket holds MARKET_ROLE on USDx (to mint / burnFrom) and SETTLEMENT_MANAGER_ROLE on MarketConfig (to consume capacity); it reads all routing, whitelist, and capacity policy from MarketConfig.
Roles
MINT_OPERATOR_ROLE
May settle orders whose side == MINT. Execution authority only.
REDEEM_OPERATOR_ROLE
May settle orders whose side == REDEEM. Execution authority only.
SETTLEMENT_MANAGER_ROLE
May cancelOrder (tombstone an order hash). Manage-vs-execute is deliberately split from the operator roles.
DEFAULT_ADMIN_ROLE
Admin over the operator/manager roles; granted at initialize.
Operators execute pre-authorized orders; they cannot change what an order means. Delegation and cancellation are separated from execution.
State Variables
usdx
IUSDx
The USDx token contract.
marketConfig
IPrimaryMarketConfig
Policy/capacity registry (MarketConfig).
_orders
mapping(bytes32 => OrderRecord)
Per-order-hash lifecycle: {bool settled; bool cancelled; bytes32 proofId}.
_nonceBitmaps
mapping(bytes32 => mapping(uint256 => uint256))
Nonce bitmap keyed per accountId (not per signer).
_delegatedSigners
mapping(address => mapping(address => SignerStatus))
signer => source => status.
Types
The EIP-712 type string is fixed in ORDER_TYPEHASH; the domain is EIP712Domain(name="USDxMarket", version="1", chainId, verifyingContract).
Functions: Settlement
settle
Executes a valid signed order exactly once. Re-runs the full precheck (_checkSettlement), enforces the side-appropriate operator role, marks the nonce used, records the settlement proof, consumes capacity, and moves assets. Emits OrderSettled plus the side event.
Authorization: requires MINT_OPERATOR_ROLE when side == MINT, else REDEEM_OPERATOR_ROLE. Reverts AccessControlUnauthorizedAccount otherwise.
Order of operations (all-or-nothing):
_checkSettlement, order shape, status (not settled/cancelled), nonce unused, signature, whitelist,accountIdmatch, token pause/blacklist, route/channel, block limits, and multi-scope capacity. Any failure reverts via_revertForReasonbefore state changes.Operator role check.
Mark
order.nonceused in theorder.accountIdbitmap (irreversible on success).Record proof:
proofId = keccak256(orderHash, address(this), chainId, block.number); set_orders[orderHash] = {settled: true, proofId}.marketConfig.consumeCapacityandconsumeBlockCapacity.MINT: transfer
inputAmountofinputAssetfromsignerto the channeldestination, thenusdx.mint(receiver, minOutputAmount). REDEEM:usdx.burnFrom(signer, inputAmount), then transferminOutputAmountofoutputAssettoreceiver.
Events: OrderSettled(...); then Mint(msg.sender, signer, receiver, inputAsset, inputAmount, minOutputAmount) or Redeem(msg.sender, signer, receiver, outputAsset, minOutputAmount, inputAmount).
mint / redeem
Thin side-guarded wrappers over settle: mint reverts InvalidOrder() unless side == MINT, redeem unless side == REDEEM, then delegate to settle (which enforces the operator role and all checks).
checkSettlement
Non-mutating preview of whether an order can settle under current policy, routing, nonce, signature, and capacity. Returns {allowed, reasonCode, orderHash, routeId, channelId, availableNotionalAmount, requiredNotionalAmount}. settlementData is ignored by the preview. Execution re-runs every check before state changes.
cancelOrder
Tombstones an unsettled order hash so it can never settle. Cancellation does not consume the nonce; the order is invalidated via _orders[orderHash].cancelled. Signature verification is not part of cancellation.
Reverts: InvalidNonce(), the order is already settled or cancelled.
Events: OrderCancelled(orderHash, order.accountId).
Functions: Delegation
Delegation is a two-step process: the source account initiates, and the delegate confirms. A delegate cannot sign until it has accepted.
Reverts: InvalidAddress(), zero signer; SignerNotInitiated(), confirming a relationship that is not PENDING.
Events: DelegatedSignerInitiated(signer, source), DelegatedSignerAdded(signer, source), DelegatedSignerRemoved(signer, source).
Functions: Verification (view)
hashOrder(Order)
EIP-712 typed-data hash over DOMAIN_SEPARATOR() and the order struct hash.
verifyOrder(Order, Signature)
Order hash if currently valid; reverts via _revertForReason otherwise.
verifyNonce(bytes32 accountId, uint256 nonce)
(slot, bitmap, bit) if the nonce is non-zero and unused; reverts InvalidNonce() otherwise.
isNonceUsed(bytes32 accountId, uint256 nonce)
true if the nonce bit is set.
orderState(bytes32 orderHash)
(settled, cancelled, proofId).
proofOfOrder(bytes32 orderHash)
The linked proofId (the full receipt is reconstructed offchain from OrderSettled).
checkMint(Order, Signature) / checkRedeem(Order, Signature)
OrderCheck{valid, code, orderHash, signer, nonceUsed, availableBlockCapacity} for the matching side.
DOMAIN_SEPARATOR() / eip712Domain()
The EIP-712 domain over name USDxMarket, version 1, chain id, and this contract.
Functions: Registry reads (proxied to MarketConfig)
route, channel, isRouteEnabled, isChannelEnabled, isSupportedAsset, getSupportedAssets, getCustodians, isCustodian, isWhitelisted, signerAccount, checkChannel, cap, capUsage, checkCapacity, maxCapacity, getCurrentBlockCapacity, getMintingState, getUserLimit, getUserBlockCapacity, all read policy from marketConfig. delegatedSigner(signer, source) reads the market's own delegation registry.
Events
OrderSettled
proofId, orderHash, accountId, routeId, channelId, destination, channelHash, settlementHash
Mint
caller, signer, receiver, inputAsset, inputAmount, outputAmount
Redeem
caller, signer, receiver, outputAsset, outputAmount, inputAmount
OrderCancelled
orderHash, accountId
DelegatedSignerInitiated / DelegatedSignerAdded / DelegatedSignerRemoved
signer, source
Errors
InvalidUSDxAddress()
Zero USDx address in initialize
InvalidAddress()
Zero config/admin/signer address
InvalidOrder()
Malformed order or mint/redeem side mismatch
InvalidSignature()
Signer is not the account, an accepted delegate, or a valid ERC-1271 signer
SignatureExpired()
block.timestamp > order.deadline
InvalidNonce()
Nonce used/zero, or order already settled/cancelled
NotWhitelisted()
Signer/receiver not whitelisted, accountId mismatch, or a restricted token party
InvalidRoute()
Route disabled, side/asset mismatch, or amount below route minimum
InvalidChannel()
Channel disabled, channel/route mismatch, or custodian not approved
CapacityExceeded(bytes32 code)
A global/asset/route/account/channel cap is exceeded
MaxMintPerBlockExceeded() / MaxRedeemPerBlockExceeded()
Same-block circuit breaker hit
SignerNotInitiated()
Confirming a delegation that is not PENDING
MarketConfig
Verified source: read on Etherscan Inherits: Initializable, IPrimaryMarketConfig, AccessControlUpgradeable
The policy and capacity registry USDxMarket reads during settlement. Admins configure routes, channels, caps, whitelists, and signer→account bindings; the market holds SETTLEMENT_MANAGER_ROLE and is the only expected capacity consumer. Configuration follows the risk-direction rule, risk-down changes (pause capacity, disable mint/redeem) may execute immediately via EMERGENCY_ROLE; risk-up changes (re-enable, raise caps, add routes/channels) require DEFAULT_ADMIN_ROLE.
Roles
DEFAULT_ADMIN_ROLE
Full configuration authority: routes, channels, caps, whitelist, signer accounts, block limits, re-enabling flows.
SETTLEMENT_MANAGER_ROLE
May consumeCapacity and consumeBlockCapacity. Held by USDxMarket so external callers cannot move cap usage.
EMERGENCY_ROLE
Risk-down only: pauseCapacity and disabling mint/redeem via setMintRedeemEnabled. Cannot re-enable or raise limits.
State Variables
mintEnabled / redeemEnabled
bool
Global mint/redeem settlement switches.
maxMintPerBlock / maxRedeemPerBlock
uint256
Same-block USDx notional circuit breakers.
mintedPerBlock / redeemedPerBlock
mapping(uint256 => uint256)
Per-block-number usage counters.
Internal mappings hold routes, channels, caps, cap usage, supported assets, custodians, the whitelist, signer→account bindings, and per-cap pause flags.
Types
A route (RouteState) defines a side, input/output asset pair, SettlementMode, minimum amounts, and an enabled flag, what may trade. A channel (ChannelState) binds a route to a concrete custodian and destination with its own enabled flag and channelHash, where it settles. A cap (CapConfig) sets a notional cap, WindowType, and windowSize for a CapKey (scope + subject).
Functions: Initialization
Enables mint and redeem, sets the per-block limits, grants DEFAULT_ADMIN_ROLE to admin, and registers usdx as a supported asset.
Reverts: InvalidAddress(), zero usdx or admin.
Functions: Configuration (DEFAULT_ADMIN_ROLE)
setRoute(RouteState)
Register/update a route; auto-registers its input/output assets. Emits RouteSet.
setChannel(ChannelState)
Register/update a channel on an existing route with an approved custodian/destination; auto-registers the custodian. Emits ChannelSet (and CustodianAdded).
setChannelStatus(bytes32 channelId, bool enabled)
Enable/disable a channel. Emits ChannelStatusSet.
setWhitelist(address account, bool allowed)
Allow/deny an account as signer or receiver. Emits WhitelistSet.
setSignerAccount(address signer, bytes32 accountId)
Bind/clear the accountId a signer may use. Emits SignerAccountSet.
setCap(CapKey, CapConfig)
Configure a global/asset/route/account/channel cap (fixed windows require non-zero windowSize). Emits CapSet.
unpauseCapacity(CapKey)
Restore a paused cap. Emits CapacityUnpaused.
setMaxMintPerBlock / setMaxRedeemPerBlock
Update the same-block circuit-breaker limits. Emits MaxMintPerBlockChanged / MaxRedeemPerBlockChanged.
Functions: Emergency (risk-down)
pauseCapacity disables a configured cap immediately (emits CapacityPaused). setMintRedeemEnabled lets EMERGENCY_ROLE turn flows off immediately, but re-enabling a disabled flow requires DEFAULT_ADMIN_ROLE, an emergency holder that tries to risk up reverts AccessControlUnauthorizedAccount.
Functions: Capacity accounting (SETTLEMENT_MANAGER_ROLE)
Called by USDxMarket during settle to record usage across every enabled cap scope and the same-block counter after validation passes. Restricted so no external caller can move cap usage.
Functions: Reads
route, channel, isRouteEnabled, isChannelEnabled, isSupportedAsset, getSupportedAssets, getCustodians, isCustodian, isWhitelisted, signerAccount, getCurrentBlockCapacity, cap, capUsage, checkChannel, checkCapacity, maxCapacity. checkCapacity walks the caps in scope order (global → asset → route → account → channel) and returns the first failing reason code with the tightest remaining availability.
Events
RouteSet, ChannelSet, ChannelStatusSet, CustodianAdded, WhitelistSet, SignerAccountSet, CapSet, CapacityConsumed, CapacityPaused, CapacityUnpaused, MaxMintPerBlockChanged, MaxRedeemPerBlockChanged, AssetAdded, AssetRemoved.
Errors
InvalidAddress()
Zero address where non-zero required
InvalidRoute()
Malformed route (zero id or asset)
InvalidChannel()
Channel with no matching route, zero custodian, or zero destination
InvalidAssetAddress()
Zero asset in the supported-asset set
InvalidAmount()
Invalid cap key/window, or capacity consumed without passing checks
AccessControlUnauthorizedAccount(address, bytes32)
Caller lacks the required role (including emergency risk-up attempts)
Last updated

