|
| 1 | +--- |
| 2 | +title: Check Direct Minting Limits |
| 3 | +tags: [intermediate, fassets] |
| 4 | +slug: fassets-direct-minting-limits |
| 5 | +description: Read the live hourly and daily direct-minting rate limits and compute the maximum mint that fits both windows. |
| 6 | +keywords: [fassets, fxrp, direct-minting, rate-limits, flare-network, xrpl] |
| 7 | +sidebar_position: 16 |
| 8 | +--- |
| 9 | + |
| 10 | +import CodeBlock from "@theme/CodeBlock"; |
| 11 | +import FAssetsDirectMintingLimits from "!!raw-loader!/examples/developer-hub-javascript/fassetsDirectMintingLimits.ts"; |
| 12 | + |
| 13 | +## Overview |
| 14 | + |
| 15 | +This guide reads the on-chain [direct minting](/fassets/direct-minting#rate-limits) rate limits, replays the tumbling-window state off-chain, and prints the maximum amount a single mint can request right now without being delayed. |
| 16 | + |
| 17 | +Direct minting is throttled by the `MintingRateLimiter` library: an hourly and a daily window cap how much FXRP can be minted before the asset manager starts pushing new mintings into a future window via [`DirectMintingDelayed`](/fassets/reference/IAssetManagerEvents#directmintingdelayed). |
| 18 | +A pre-flight check lets a frontend or executor avoid surprising the user with a delay. |
| 19 | + |
| 20 | +The complete runnable example is available in the [flare-viem-starter](https://github.com/flare-foundation/flare-viem-starter/blob/main/src/fassets/direct-minting-limits.ts) repository. |
| 21 | + |
| 22 | +## How the windows work |
| 23 | + |
| 24 | +`MintingRateLimiter` library uses **clock-aligned tumbling windows**, not rolling windows. |
| 25 | +On initialization, the window start is snapped to a multiple of `windowSizeSeconds`: |
| 26 | + |
| 27 | +```text |
| 28 | +windowStartTimestamp = block.timestamp - block.timestamp % windowSizeSeconds |
| 29 | +``` |
| 30 | + |
| 31 | +With `windowSizeSeconds = 3600`, the hourly window aligns to UTC hour boundaries (00:00-01:00, 01:00-02:00, …). |
| 32 | +The daily window (`86400` seconds) aligns to 00:00 UTC. |
| 33 | + |
| 34 | +On every write, the limiter advances the window: |
| 35 | + |
| 36 | +```text |
| 37 | +windowsElapsed = (now - windowStartTimestamp) / windowSizeSeconds |
| 38 | +mintedInCurrentWindow = subOrZero(mintedInCurrentWindow, windowsElapsed * maxPerWindow) |
| 39 | +windowStartTimestamp += windowsElapsed * windowSizeSeconds |
| 40 | +``` |
| 41 | + |
| 42 | +Two consequences worth noting: |
| 43 | + |
| 44 | +1. **Unused capacity does not roll over.** |
| 45 | + `subOrZero` clamps at zero, so an idle hour does not give twice the cap the next hour — every fresh window starts at exactly `maxPerWindow`. |
| 46 | +2. **Over-cap mints are delayed, not rejected.** |
| 47 | + `executionAllowedAt` is set to `windowStartTimestamp + windowSize * mintedInCurrentWindow / maxPerWindow`, so overflow drains hour-by-hour through the `subOrZero` step. |
| 48 | + |
| 49 | +Reading the limiter state on its own returns stale `(windowStart, minted)` values until the next write touches the contract, so this script replays the slide off-chain to show the values as they would be right now. |
| 50 | + |
| 51 | +A mint can be delayed by either the hourly/daily window or the large-minting threshold — whichever pushes [`executionAllowedAt`](/fassets/reference/IAssetManagerEvents#directmintingdelayed) further into the future wins. |
| 52 | + |
| 53 | +## Prerequisites |
| 54 | + |
| 55 | +- The [flare-viem-starter](https://github.com/flare-foundation/flare-viem-starter) cloned locally with dependencies installed. |
| 56 | +- A configured `publicClient` pointing at the [Flare network](/network/overview) you want to query (Coston2 by default in the starter). |
| 57 | + |
| 58 | +## Direct Minting Limits Script |
| 59 | + |
| 60 | +<CodeBlock language="typescript" title="src/fassets/direct-minting-limits.ts"> |
| 61 | + {FAssetsDirectMintingLimits} |
| 62 | +</CodeBlock> |
| 63 | + |
| 64 | +## Code Breakdown |
| 65 | + |
| 66 | +1. **Window sizes.** |
| 67 | + `HOURLY_WINDOW_SECONDS` and `DAILY_WINDOW_SECONDS` are the `windowSizeSeconds` values the `MintingRateLimiter.sol` library uses — `3600` aligns to UTC hour boundaries, `86400` aligns to 00:00 UTC. |
| 68 | +2. **Format helpers.** |
| 69 | + `formatUba` prints raw UBA (units of basis assets) alongside the XRP equivalent via `dropsToXrp`, and `formatTimestamp` shows ISO time with a relative offset so it is clear whether a timestamp is in the future or the past. |
| 70 | +3. **Replay the limiter slide.** |
| 71 | + `computeWindowState` mirrors the window-advancement logic in `MintingRateLimiter.sol`: it advances `windowStart` past every tumble that has elapsed and drains `mintedInCurrentWindow` by `windowsElapsed * limit`. |
| 72 | + Without this off-chain replay, you would see stale numbers between writes. |
| 73 | +4. **Print one window's live state.** |
| 74 | + `printWindow` shows the live cap, used amount, and percentage, remaining headroom, the effective window start, and the next UTC tumble. |
| 75 | +5. **Resolve `AssetManagerFXRP`.** |
| 76 | + `getContractAddressByName("AssetManagerFXRP")` looks up the asset manager through the [Flare Contract Registry](/network/guides/flare-contracts-registry). |
| 77 | +6. **Read everything in parallel.** |
| 78 | + `Promise.all` fetches the [AMG granularity](/fassets/reference/IAssetManager#assetmintinggranularityuba), the [hourly](/fassets/reference/IAssetManager#getdirectmintinghourlylimituba) and [daily](/fassets/reference/IAssetManager#getdirectmintingdailylimituba) caps, the raw limiter state for [hourly](/fassets/reference/IAssetManager#getdirectmintinghourlylimiterstate) and [daily](/fassets/reference/IAssetManager#getdirectmintingdailylimiterstate) windows, the [`unblockUntilTimestamp`](/fassets/reference/IAssetManager#getdirectmintingsunblockuntiltimestamp), and the [large-minting threshold](/fassets/reference/IAssetManager#getdirectmintinglargemintingthresholduba) and [delay](/fassets/reference/IAssetManager#getdirectmintinglargemintingdelayseconds) in one round trip. |
| 79 | +7. **Convert AMG to UBA.** |
| 80 | + The limiter stores `mintedInCurrentWindow` in AMG (`uint64`) for cheap on-chain storage. |
| 81 | + Multiplying by [`assetMintingGranularityUBA`](/fassets/reference/IAssetManager#assetmintinggranularityuba) rebases it into UBA (units of basis assets) so it can be compared against the UBA-denominated cap. |
| 82 | +8. **Honor the unblock flag.** |
| 83 | + When [`getDirectMintingsUnblockUntilTimestamp`](/fassets/reference/IAssetManager#getdirectmintingsunblockuntiltimestamp) returns a future timestamp, governance has temporarily turned off the limiter; treat full caps as available. |
| 84 | +9. **Pre-flight gate.** |
| 85 | + `bigintMin(hourlyHeadroom, dailyHeadroom)` is the largest amount that fits both windows. |
| 86 | + A request larger than this will not revert — it will mint with [`DirectMintingDelayed`](/fassets/reference/IAssetManagerEvents#directmintingdelayed) and an `executionAllowedAt` in the future. |
| 87 | + |
| 88 | +## Important Notes |
| 89 | + |
| 90 | +- **Large mintings have an independent fixed delay.** |
| 91 | + Mintings above [`directMintingLargeMintingThresholdUBA`](/fassets/reference/IAssetManager#getdirectmintinglargemintingthresholduba) are delayed by [`directMintingLargeMintingDelaySeconds`](/fassets/reference/IAssetManager#getdirectmintinglargemintingdelayseconds) even if the hourly and daily windows have headroom. |
| 92 | +- **Reads are stale between writes.** |
| 93 | + Always advance the window off-chain when displaying live limiter state. |
| 94 | +- **Plan UI flows around [`DirectMintingDelayed`](/fassets/reference/IAssetManagerEvents#directmintingdelayed)** so users are not surprised by a deferred execution. |
| 95 | + |
| 96 | +:::tip[What's next] |
| 97 | + |
| 98 | +To continue your FAssets development journey, you can: |
| 99 | + |
| 100 | +- Mint with the 32-byte memo flow in [Direct Mint FXRP](/fassets/developer-guides/fassets-direct-minting). |
| 101 | +- Mint with a reserved tag in [Direct Mint FXRP with Tag](/fassets/developer-guides/fassets-direct-minting-tag). |
| 102 | +- Read the protocol details in [Direct Minting](/fassets/direct-minting). |
| 103 | + |
| 104 | +::: |
0 commit comments