MinterV0
Inherits: IMinterV0, AccessManaged, EIP712, Pausable
Title: MinterV0
Handles minting of apxUSD tokens and enforces protocol controls
Implements EIP-712 for structured data signing and delegates delay enforcement to AccessManager Features:
- Order-based minting with beneficiary signatures
- AccessManager-enforced delays for compliance
- Configurable max mint size
- Nonce tracking per beneficiary to prevent replay attacks
- EIP-712 typed structured data hashing
State Variables
apxUSD
The apxUSD token contract
ApxUSD public immutable apxUSD
nonce
Mapping of beneficiary => nonce for replay protection
mapping(address => uint48) public nonce
pendingOrders
Mapping of operationId => Order for pending mints
mapping(bytes32 => Order) internal pendingOrders
maxMintAmount
Maximum amount that can be minted in a single order
uint208 public maxMintAmount
rateLimitAmount
Maximum amount that can be minted within the rate limit period
uint256 public rateLimitAmount
rateLimitPeriod
Duration of the rate limit period in seconds (e.g., 86400 for 24 hours)
uint48 public rateLimitPeriod
mintHistory
Queue of recent mints for rate limiting (stores encoded MintRecord)
Should this be moved to it's own storage location?
DoubleEndedQueue.Bytes32Deque mintHistory
MAX_RATE_LIMIT_PERIOD
Maximum duration of the rate limit period
Mint history records are only pruned against this ceiling, not the current rateLimitPeriod. This ensures that if rateLimitPeriod is extended, historical records are still available for accurate rate limit accounting.
uint48 public constant MAX_RATE_LIMIT_PERIOD = 14 days
ORDER_TYPEHASH
EIP-712 type hash for Order struct
bytes32 public constant ORDER_TYPEHASH =
keccak256("Order(address beneficiary,uint48 notBefore,uint48 notAfter,uint48 nonce,uint208 amount)")
Functions
constructor
Initializes the MinterV0 contract
constructor(
address initialAuthority,
address _apxUSD,
uint208 _maxMintAmount,
uint208 _rateLimitAmount,
uint48 _rateLimitPeriod
) AccessManaged(initialAuthority) EIP712("ApxUSD MinterV0", "1");
Parameters
| Name | Type | Description |
|---|---|---|
initialAuthority | address | Address of the AccessManager contract |
_apxUSD | address | Address of the ApxUSD token contract |
_maxMintAmount | uint208 | Maximum amount that can be minted in a single order (e.g., 10_000e18 for $10k) |
_rateLimitAmount | uint208 | Maximum amount that can be minted within the rate limit period |
_rateLimitPeriod | uint48 | Duration of the rate limit period in seconds (e.g., 86400 for 24 hours) |
DOMAIN_SEPARATOR
Returns the EIP-712 domain separator
function DOMAIN_SEPARATOR() public view returns (bytes32);
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | The domain separator for this contract |
structHashOrder
Returns the EIP-712 struct hash for an order
Returns the struct hash according to EIP-712 standard
function structHashOrder(Order calldata order) public pure returns (bytes32);
Parameters
| Name | Type | Description |
|---|---|---|
order | Order | The mint order to hash |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | The struct hash |
hashOrder
Returns the EIP-712 typed hash for an order
This returns the full EIP-712 digest that should be signed
function hashOrder(Order calldata order) public view returns (bytes32);
Parameters
| Name | Type | Description |
|---|---|---|
order | Order | The mint order to hash |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | The EIP-712 compliant digest |
validateOrder
Validates an order without executing it (reverts if invalid)
function validateOrder(Order calldata order, bytes calldata signature) public view;
Parameters
| Name | Type | Description |
|---|---|---|
order | Order | The mint order to validate |
signature | bytes | The beneficiary's signature over the order |
requestMint
Requests a mint by validating the order and scheduling with AccessManager
function requestMint(Order calldata order, bytes calldata signature)
external
restricted
whenNotPaused
returns (bytes32 operationId);
Parameters
| Name | Type | Description |
|---|---|---|
order | Order | The mint order containing beneficiary, notBefore, notAfter, nonce, and amount |
signature | bytes | The beneficiary's signature over the order |
Returns
| Name | Type | Description |
|---|---|---|
operationId | bytes32 | The unique identifier for this scheduled operation |
executeMint
Executes a scheduled mint operation via AccessManager
function executeMint(bytes32 operationId) external restricted whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
operationId | bytes32 | The unique identifier of the scheduled operation |
cancelMint
Cancels a scheduled mint operation
Only callable through AccessManager with MINT_GUARD_ROLE
This is critical for recovering from the 256 operation limit - expired orders must be cancelled to free up operation IDs in AccessManager
function cancelMint(bytes32 operationId) external restricted;
Parameters
| Name | Type | Description |
|---|---|---|
operationId | bytes32 | The unique identifier of the scheduled operation |
pendingOrder
Returns the details of a pending order
function pendingOrder(bytes32 operationId) public view returns (Order memory);
Parameters
| Name | Type | Description |
|---|---|---|
operationId | bytes32 | The unique identifier of the scheduled operation |
Returns
| Name | Type | Description |
|---|---|---|
<none> | Order | order The pending order details |
mintStatus
Returns the status of a mint operation
Useful for front-ends and monitoring systems to determine order state
function mintStatus(bytes32 operationId) external view returns (MintStatus);
Parameters
| Name | Type | Description |
|---|---|---|
operationId | bytes32 | The unique identifier of the operation |
Returns
| Name | Type | Description |
|---|---|---|
<none> | MintStatus | status The current status of the operation: - NotFound: Order not in storage (never existed, executed, or cancelled) - Scheduled: Order pending but not yet ready (AccessManager delay not passed or before notBefore) - Ready: Order pending and ready to execute (AccessManager delay passed, after notBefore, before notAfter) - Expired: Order pending but expired (after notAfter time) |
setMaxMintAmount
Updates the maximum mint amount
function setMaxMintAmount(uint208 newMaxMintAmount) external restricted;
Parameters
| Name | Type | Description |
|---|---|---|
newMaxMintAmount | uint208 | New maximum amount for a single mint order |
setRateLimit
Updates the rate limit configuration
function setRateLimit(uint256 newAmount, uint48 newPeriod) external restricted;
Parameters
| Name | Type | Description |
|---|---|---|
newAmount | uint256 | New maximum amount that can be minted within the rate limit period |
newPeriod | uint48 | New duration of the rate limit period in seconds |
rateLimit
Returns the current rate limit configuration
function rateLimit() external view returns (uint256 amount, uint48 period);
Returns
| Name | Type | Description |
|---|---|---|
amount | uint256 | Maximum amount that can be minted within the rate limit period |
period | uint48 | Duration of the rate limit period in seconds |
rateLimitMinted
Returns the total amount minted in the current rate limit period
Iterates from newest to oldest records and breaks early when cutoff is reached
function rateLimitMinted() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Total amount minted in the current period |
rateLimitAvailable
Returns the amount available to mint without exceeding the rate limit
function rateLimitAvailable() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Amount that can still be minted in the current period |
cleanMintHistory
Manually cleans up to n expired mint records from the history queue
Only callable through AccessManager with MINTER_ROLE
Useful for gas management when queue grows large
Uses MAX_RATE_LIMIT_PERIOD as the cutoff ceiling instead of rateLimitPeriod. This ensures that records are retained long enough to support any valid rateLimitPeriod value, preventing under-counting when the period is extended.
function cleanMintHistory(uint32 n) external restricted returns (uint32 cleaned);
Parameters
| Name | Type | Description |
|---|---|---|
n | uint32 | Maximum number of records to attempt cleaning |
Returns
| Name | Type | Description |
|---|---|---|
cleaned | uint32 | Number of records actually removed |
pause
Pauses the minting process
function pause() external restricted;
unpause
Unpauses the minting process
function unpause() external restricted;
_encodeOrderData
Encodes order data for AccessManager scheduling/execution
function _encodeOrderData(Order memory order) internal view returns (bytes memory);
Parameters
| Name | Type | Description |
|---|---|---|
order | Order | The order to encode |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes | Encoded calldata with nonce appended for uniqueness |
_cleanMintHistory
Cleans expired mint records from the queue
function _cleanMintHistory() internal;
_cleanMintHistoryUpTo
Internal helper to clean up to n expired mint records from the queue
function _cleanMintHistoryUpTo(uint32 n) internal returns (uint32 cleaned);
Parameters
| Name | Type | Description |
|---|---|---|
n | uint32 | Maximum number of records to clean (type(uint32).max for unlimited) |
Returns
| Name | Type | Description |
|---|---|---|
cleaned | uint32 | Number of records actually removed |
_encodeMintRecord
Encodes mint record into bytes32: [timestamp:48][amount:208]
function _encodeMintRecord(uint48 timestamp, uint208 amount) internal pure returns (bytes32);
_decodeMintRecord
Decodes bytes32 ([timestamp:48][amount:208]) into mint record
function _decodeMintRecord(bytes32 data) internal pure returns (MintRecord memory);