The ARU stack is deployed on Arbitrum One (mainnet). Addresses are set via environment variables in the dashboard and updated here after each deployment.
| Contract | Purpose | Address |
|---|---|---|
ARU |
The ERC-20 token + Permit | see dashboard env / latest release |
ARUSubscriptionManager |
Per-request mint/redeem (primary market) | see dashboard env |
ARUPriceOracle |
Chainlink-compatible NAV feed | see dashboard env |
USDC (Arbitrum native) |
Collateral asset | 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 |
| Property | Value |
|---|---|
| Name | Acua Reserve Unit |
| Symbol | ARU |
| Decimals | 18 |
| ERC-20 | ✓ |
| EIP-2612 Permit | ✓ |
| Transfer hooks | None |
| Rebasing | No |
| Fee-on-transfer | No |
| Blocklist | No |
| Pause on transfers | No |
ARUSubscriptionManager — subscription (mint)solidity// Submit a mint request. Returns the request ID.
function requestSubscription(uint256 usdcAmount, uint256 maxPricePerARU) external returns (bytes32 id);
// Cancel your own pending request.
function cancelSubscription(bytes32 id) external;
// Anyone can cancel after expiry (48h default).
function cancelExpiredSubscription(bytes32 id) external;
// Read: how many of your requests are currently open.
function openSubscriptionsOf(address ap) external view returns (uint256);
// Read: request state.
function subscriptions(bytes32 id) external view returns (
address ap,
uint256 amount,
uint256 priceBound,
uint64 createdAt,
uint64 expiresAt,
bool fulfilled
);
ARUSubscriptionManager — redemption (burn)solidityfunction requestRedemption(uint256 aruAmount, uint256 minPricePerARU) external returns (bytes32 id);
function cancelRedemption(bytes32 id) external;
function cancelExpiredRedemption(bytes32 id) external;
function openRedemptionsOf(address ap) external view returns (uint256);
function redemptions(bytes32 id) external view returns (
address ap,
uint256 amount,
uint256 priceBound,
uint64 createdAt,
uint64 expiresAt,
bool fulfilled
);
solidityevent SubscriptionRequested(bytes32 indexed id, address indexed ap, uint256 usdcAmount, uint256 maxPrice, uint256 expiresAt);
event SubscriptionApproved(bytes32 indexed id, address indexed ap, uint256 usdcAmount, uint256 aruAmount, uint256 pricePerARU);
event SubscriptionCancelled(bytes32 indexed id, address indexed ap, uint256 usdcAmount, bool byExpiry);
event RedemptionRequested(bytes32 indexed id, address indexed ap, uint256 aruAmount, uint256 minPrice, uint256 expiresAt);
event RedemptionApproved(bytes32 indexed id, address indexed ap, uint256 aruAmount, uint256 usdcAmount, uint256 pricePerARU);
event RedemptionCancelled(bytes32 indexed id, address indexed ap, uint256 aruAmount, bool byExpiry);
solidityfunction isAP(address) external view returns (bool);
function minimumMintAmount() external view returns (uint256); // USDC, 6-dec
function minimumRedeemAmount() external view returns (uint256); // ARU, 18-dec
function requestTTL() external view returns (uint256); // default 48h
function subscriptionsPaused() external view returns (bool);
function redemptionsPaused() external view returns (bool);
function frozen() external view returns (bool);
function treasuryAddress() external view returns (address);
function treasuryAllowance() external view returns (uint256); // USDC allowance treasury → manager
uint256 public constant MAX_OPEN_REQUESTS_PER_AP = 50;
ARUPriceOracle implements Chainlink's AggregatorV3Interface.
solidity// Standard Chainlink-compatible read. Does NOT revert on stale data.
function latestRoundData() external view returns (
uint80 roundId,
int256 answer, // price in 8-decimal fixed point (USD per ARU × 1e8)
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
// Same tuple but reverts PriceStale if older than stalenessThreshold.
function latestRoundDataStrict() external view returns (...);
function decimals() external pure returns (uint8); // 8
function description() external pure returns (string memory); // "ARU / USD"
function stalenessThreshold() external view returns (uint256); // default 25h
For any smart contract consuming ARU price:
solidity(, int256 answer,, uint256 updatedAt,) = ARU_ORACLE.latestRoundData();
require(block.timestamp - updatedAt <= MAX_ACCEPTABLE_AGE, "ARU price stale");
require(answer > 0, "ARU price invalid");
uint256 priceScaled = uint256(answer) * 1e10; // scale 8-dec → 18-dec if needed
Or, more simply, use the strict variant:
solidity(, int256 answer,,,) = ARU_ORACLE.latestRoundDataStrict();
The Arbitrum native USDC (0xaf88d065e77c8cC2239327C5EDb3A432268e5831) is what APs must hold and approve. This is distinct from bridged USDC (USDC.e, address 0xFF970A...). Do not send bridged USDC to the Subscription Manager — it will not work.
All ABIs are exported in the aru-ap frontend at src/lib/contracts.ts (TypeScript). For other languages, generate from the compiled contracts in the aru-evm repo under out/.
https://github.com/arureserve/aru-evm
https://github.com/arureserve/aru-ap
Testnet deployments (Arbitrum Sepolia) are used for AP dry-runs before production. Contact the ARU team for current testnet addresses — they rotate with each release candidate.
All deployed contracts are verified on Arbiscan. Click through from the addresses in the dashboard to view source, read state, and interact via the block explorer UI.
Source bytecode is reproducible from the audited git commit — foundry.toml has bytecode_hash = "none" for deterministic output. The audited commit is 1153227 (Nethermind Security report NM-0902, zero findings), and it is the current master HEAD of aru-evm — so the audited source and the deployed source are identical. Anyone can verify on-chain bytecode matches the audited source by running forge inspect <Contract> bytecode from commit 1153227.