Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
69 lines
3.1 KiB
Solidity
69 lines
3.1 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
|
|
|
|
/// @title AereUSDC — Foundation-attested bridged USDC on AERE chain 2800
|
|
/// @notice Each AereUSDC is 1:1-backed by a USDC reserve held by AERE Foundation on
|
|
/// Ethereum mainnet. The Foundation address (currently a Trust Wallet receiver,
|
|
/// eventually a multisig) holds the real USDC. AereUSDC is minted on chain 2800
|
|
/// when the off-chain bridge watcher attests a deposit; burned when the user
|
|
/// requests withdrawal (Phase 2 — currently manual).
|
|
///
|
|
/// Decimals: 6 (matches Ethereum USDC, so 1 USDC = 1 AereUSDC numerically).
|
|
/// Symbol: aUSDC. Name: "Aere-Bridged USDC".
|
|
///
|
|
/// Roles:
|
|
/// - DEFAULT_ADMIN_ROLE: Foundation, sets bridge address, can pause minting in emergency.
|
|
/// - MINTER_ROLE: AereBridge contract only. Foundation grants on deploy.
|
|
/// - BURNER_ROLE: AereBridge contract (Phase 2 — Foundation will add for withdrawal flow).
|
|
///
|
|
/// Honest framing: this is a CUSTODIAL bridged asset. Foundation can theoretically
|
|
/// mint unbacked tokens or refuse withdrawal. Phase 2 wires trustless settlement
|
|
/// (Across/Hyperlane) when funds available for sister-chain deploys.
|
|
contract AereUSDC is ERC20, AccessControl {
|
|
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
|
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
|
|
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
|
|
|
|
bool public mintPaused;
|
|
|
|
event MintPaused(bool paused);
|
|
|
|
error MintingPaused();
|
|
|
|
/// @param initialAdmin The address that gets DEFAULT_ADMIN_ROLE at deploy time.
|
|
/// Typically the deployer, who then grants MINTER to bridge,
|
|
/// transfers admin to Foundation, and renounces own admin —
|
|
/// all in the same deploy script.
|
|
constructor(address initialAdmin) ERC20("Aere-Bridged USDC", "aUSDC") {
|
|
_grantRole(DEFAULT_ADMIN_ROLE, initialAdmin);
|
|
_grantRole(PAUSER_ROLE, initialAdmin);
|
|
}
|
|
|
|
function decimals() public pure override returns (uint8) {
|
|
return 6;
|
|
}
|
|
|
|
/// @notice Mint AereUSDC backed by an attested Ethereum USDC deposit.
|
|
/// @dev Only callable by the AereBridge contract (MINTER_ROLE).
|
|
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
|
|
if (mintPaused) revert MintingPaused();
|
|
_mint(to, amount);
|
|
}
|
|
|
|
/// @notice Burn AereUSDC (for withdrawal back to Ethereum USDC).
|
|
/// @dev Phase 2 — currently bridge has BURNER_ROLE for symmetry but withdrawal
|
|
/// processing is manual via Foundation.
|
|
function burn(address from, uint256 amount) external onlyRole(BURNER_ROLE) {
|
|
_burn(from, amount);
|
|
}
|
|
|
|
/// @notice Emergency pause for new mints. Existing balances are unaffected.
|
|
function setMintPaused(bool paused) external onlyRole(PAUSER_ROLE) {
|
|
mintPaused = paused;
|
|
emit MintPaused(paused);
|
|
}
|
|
}
|