Component: MToken module (mtoken::mtoken
)
Description
This module provides a fungible token on Sui with time-locked governance and fine-grained roles. It wraps coin::create_regulated_currency_v2
and enforces owner, operator, and revoker permissions with a configurable execution delay.
What it does
This module does the following.
Token issuance and redemption:
request_mint_to
followed byexecute_mint_to
mints coins for a recipient and deducts the amount from a prefunded mint budget;redeem
burns user coins and credits the budget.Role management: For owner, operator, and revoker through on-chain requests, execute and revoke cycles are guarded by a global delay.
Parameter governance: For metadata, delay, role changes, and ownership transfer, each is staged in a request object that becomes executable after the delay and then expires.
Compliance: Done through a deny list that can block or unblock accounts and emits events for every action.
Safety rails: Rails enforce versioning, minimum delay, execution-window validity, and budget limits. All privileged calls check exact roles.
How it does it
Request objects carry an effective time set to the current time plus delay. Execution checks that the current time is within the allowed window. Helper functions check roles and budget arithmetic. All critical states live in a single State<T>
object keyed by the coin phantom type.
Invariants
state.version
always equalsVERSION
.delay
is never belowMIN_DELAY
.Only the owner can create or update requests; only the operator can change the budget, mint, or redeem; and only the revoker can cancel requests.
mint_budget
cannot be negative and changes only by the exact minted or burned amount.A request executes only if the current time is at least the effective time and before it expires.
Minting fails if it would exceed
mint_budget
.TreasuryCap
andDenyCap
never leave theState
object except through controlled functions.
Test coverage
Cases covered
Deployment flow including coin creation and initial state verification.
Version migration success and failure paths.
Metadata updates with correct and incorrect roles.
Ownership-transfer request, execute, and revoke, including edge cases.
Operator and revoker changes with full life-cycle tests.
Delay changes respecting the minimum delay and timing rules.
Mint-budget adjustments including overflow and underflow guards.
Minting request, execute, and revoke with budget and timing checks.
Redemption by operator and rejection of non-operator attempts.
Denylist block and unblock actions with role checks.
Basic transfers of minted coins between users.
Cases not covered
Stress tests for rapid mint and burn sequences at budget limits.
Denylist enforcement on transfers. However, it is important to note that difficulty simulating epochs in SUI tests make such behavior harder to test for —
transfer_err_denied_src
attempts to test for this and is currently commented out.Extreme values for delay or amounts beyond the 64-bit range. In practice, this would be testing for runtime errors on overflow and underflow.
Attack surface
User-supplied addresses and amounts in mint, redeem, and governance requests are checked for overflow and budget limits.
Effective time manipulation is restricted to owner or operator actions, and execution enforces the valid window.
UpgradeCap
misuse is prevented by verifying the package address before ownership transfer.Arithmetic errors are mitigated through safe arithmetic checks.
Only the operator can modify the denylist and transfer rules.
The generic type parameter is fixed at coin creation and cannot be changed later.
External actors can only request actions. Each privileged state change is delayed, role-gated, time-bounded, and logged, limiting attack vectors to compromise of owner or operator credentials.