Docs/For APs/Subscribing (Mint)

Subscribing (Mint)

How to mint ARU by depositing USDC. Two-step flow: request with price bound, then wait for multisig approval (typically < 4h).

Subscribing (Mint)

Subscribing = depositing USDC and receiving ARU at NAV-adjacent price. You submit a request, the multisig reviews and approves within the price bound you specified, and ARU is minted to your wallet.

The flow

1. Approve USDC to the Subscription Manager
2. Call requestSubscription(usdcAmount, maxPricePerARU)
   ↓ USDC transfers from you to the manager contract (not treasury)
   ↓ Request stored with your priceBound and 48h expiry
3. Multisig reviews + approves within ≤ 4h typical, ≤ 48h max
   ↓ Price in their approval must be ≤ your maxPricePerARU
   ↓ ARU minted to your wallet; USDC moves to treasury
4. Done. Check your ARU balance.

If the multisig doesn't approve within 48h, your request expires. You (or anyone) can call cancelExpiredSubscription(id) to get your USDC back. You can also cancel at any time before approval via cancelSubscription(id).

Step 1 — Approve USDC

Grant the Subscription Manager permission to pull USDC from your wallet.

solidity// Approval is typically set once to max, then forgotten
USDC.approve(SUBSCRIPTION_MANAGER_ADDRESS, type(uint256).max);

You can approve smaller amounts per-transaction if preferred. SafeERC20 patterns are honored.

Step 2 — Submit the request

soliditybytes32 id = subscriptionManager.requestSubscription(
    100_000 * 1e6,    // usdcAmount — 100,000 USDC (6 decimals)
    1_15 * 1e16       // maxPricePerARU — 1.15 × 1e18, so you'll pay at most $1.15 per ARU
);

Parameters:

  • usdcAmount — amount you want to deposit, in USDC's 6-decimal units. Must be ≥ minimumMintAmount() (currently 10,000 USDC).
  • maxPricePerARU — the highest price per ARU you'll accept, in 18-decimal fixed-point. If the multisig approves at any price ≤ this, you get ARU at that price. If they try to settle above, the approval reverts.

The returned id (a bytes32 hash) is how you reference the request for cancel or tracking.

What happens on-chain during Step 2

  • Your USDC transfers from your wallet to the Subscription Manager contract (not the treasury — this is key for the refund guarantee; see Safeguards)
  • A Request struct is created with your ap, amount, priceBound, createdAt, expiresAt (48h from now by default), and fulfilled: false
  • SubscriptionRequested event emitted
  • Your per-AP open-request counter increments (capped at 50 open at once)

Step 3 — Wait for approval

The multisig (typically a 3-of-5 Gnosis Safe with AutoSigner participation) reviews your request. If the current NAV is within your priceBound, AutoSigner co-signs automatically. One human countersigns, and the approval executes.

Typical latency: under 4 hours during business hours. SLA ceiling: 48h, which is also your expiry.

On approval:

  • Admin calls approveSubscription(id, pricePerARU) where pricePerARU ≤ your priceBound
  • Your ARU = (usdcAmount × 1e30) / pricePerARU — standard fixed-point math for converting 6-decimal USDC to 18-decimal ARU at the given price
  • ARU is minted to your wallet
  • USDC is moved from the manager contract to the treasury
  • SubscriptionApproved event emitted with all details
  • Your open-request counter decrements

Calculating what you'll receive

At price p (in 1e18 units):

aru_received = usdc_amount × 1_000_000_000_000_000_000_000_000_000_000 / p
             = usdc_amount × 1e30 / p

Worked example: deposit 100,000 USDC (100_000 × 1e6) at price $1.10 per ARU (1.10 × 1e18 = 11e17):

aru_received = 100_000_000_000 × 1_000_000_000_000_000_000_000_000_000_000 / 1_100_000_000_000_000_000
             = 90,909.090909... ARU (18-dec)

You always receive slightly fewer ARU than USDC deposited when NAV > $1, as expected.

Cancelling your request

Before approval: you cancel

soliditysubscriptionManager.cancelSubscription(id);
  • Must be called by you (the original AP). Reverts NotYourRequest if anyone else tries.
  • USDC returns directly from the manager contract to your wallet.
  • Your open-request slot is freed.
  • The request ID becomes non-approvable — subsequent approveSubscription(id, ...) reverts AlreadyFulfilled.

You can cancel any time before the multisig approves. There's no cooldown.

After expiry (48h default): anyone can cancel

soliditysubscriptionManager.cancelExpiredSubscription(id);
  • Anyone can call. If you're unable to cancel yourself (key loss, compromised, legal freeze), a third-party keeper can trigger the refund.
  • USDC refund always goes to the original AP, never to the caller.
  • NotYetExpired reverts if you call before createdAt + requestTTL (48h default).

Things to know

You can have up to 50 open requests

The per-AP open-request cap prevents a compromised AP key from bloating contract state. Fulfillment (approval or cancel) frees a slot. At normal cadence, 50 is well above realistic concurrent flow.

Requests don't net

Each request is independent. If you submit 5 subscription requests of 10k USDC each, you've sent 50k USDC total to the contract. Netting doesn't happen.

You pay gas for your own request + cancel

Standard on-chain tx costs. Approximate:

  • requestSubscription: ~60k gas
  • cancelSubscription: ~50k gas
  • Approval by admin: ~90k gas (they pay for this)

Events to watch

Subscribe your indexer / monitoring to:

  • SubscriptionRequested(id, ap, usdcAmount, maxPrice, expiresAt) — you submitted
  • SubscriptionApproved(id, ap, usdcAmount, aruAmount, pricePerARU) — multisig approved, you got ARU
  • SubscriptionCancelled(id, ap, usdcAmount, byExpiry) — your request was cancelled (either by you or by expiry keeper)

What if the multisig approves at worse than NAV?

Your priceBound is the ceiling. If you set it at +20 bps above NAV, admin can approve anywhere up to that. Set tight bounds if you want tight pricing — e.g., NAV + 5 bps.

Remember: the multisig is operating under an AutoSigner that only co-signs approvals within configured NAV tolerance (typically 100 bps from published NAV). So approvals near your bound ceiling are unusual.

Next