Skip to main content

ERC-20 Mint Module

@perfect-abstractions/compose/token/ERC20/Mint/ERC20MintMod.sol

Helper function for creating new ERC-20 tokens

No Authorization Check

mint creates tokens for any account you name, with no permission check of any kind. Whatever facet calls it is responsible for deciding who may mint. Compose ships no general-purpose mint facet precisely so that this decision stays yours.

Key Features
  • mint(_account, _value) increases both balanceOf[_account] and totalSupply.
  • Emits Transfer from address(0), which is the ERC-20 convention for a mint.
  • Arithmetic is checked, so an overflowing mint reverts rather than wrapping.
  • Declares a reduced ERC20Storage with no allowance field. See below.
Module Usage

Use helper functions from Compose using your own custom facets. See Facets & Modules for more information.

Storage

State Variables

PropertyTypeDescriptionSTORAGE_POSITIONbytes32ERC-20 storage position within the diamond (Value: keccak256("erc20"))

ERC20Storage

This module declares only the two fields it uses. The allowance mapping that other ERC-20 contracts declare is absent.

Definition
/** @custom:storage-location erc8042:erc20 */
struct ERC20Storage {
mapping(address owner => uint256 balance) balanceOf;
uint256 totalSupply;
}
Why the struct is shorter here

This is a layout-compatible prefix of the full struct, not a different slot. balanceOf and totalSupply occupy the same positions either way, so this module reads and writes exactly the same storage as the rest of ERC-20. It simply does not declare the field it never touches.

ERC20BurnMod and the two Bridgeable contracts use the same two-field form. Everything that reads or writes an allowance declares all three fields.

Functions

getStorage

Returns a pointer to the ERC20Storage struct.

Because this module's struct has no allowance field, the returned pointer cannot reach allowances. If your facet needs to inspect one, import a module that declares the full struct, such as ERC20TransferMod or ERC20ApproveMod.

function getStorage() pure returns (ERC20Storage storage s);

Returns:

PropertyTypeDescriptionsERC20Storage storageThe struct in storage, with balanceOf and totalSupply only.

mint

Creates _value new tokens, credits them to _account, and increases the total supply by the same amount.

No permission is checked. Gate this behind your own authorization. Minting 0 is allowed and still emits Transfer.

function mint(address _account, uint256 _value);

Parameters:

PropertyTypeDescription_accountaddressThe address receiving the new tokens. Cannot be address(0)._valueuint256The number of tokens to create.

Reverts:

PropertyTypeDescriptionERC20InvalidReceivererror_account is address(0).Panic (0x11)arithmeticThe mint would overflow totalSupply or the recipient's balance. Solidity's checked arithmetic reverts.

Events

Emitted on every successful mint, always with address(0) as the source. This is how ERC-20 represents newly created tokens, so indexers reading Transfer see the supply increase without a separate event.

Signature:
event Transfer(address indexed _from, address indexed _to, uint256 _value);
Parameters:
PropertyTypeDescription_fromaddressAlways address(0)._toaddressThe account credited with the new tokens. Always _account._valueuint256The number of tokens created.

Errors

Best Practices

Integration Notes

Import the module under a namespace and call it from your facet:

Calling mint from a guarded facet
import "src/token/ERC20/Mint/ERC20MintMod.sol" as ERC20MintMod;
import "src/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod;

contract MyFacet {
function mintTo(address _account, uint256 _value) external {
OwnerDataMod.requireOwner();
ERC20MintMod.mint(_account, _value);
}
}

ERC20Storage lives at keccak256("erc20") inside the diamond, the same slot ERC20DataFacet reads, so a mint is immediately visible through balanceOf() and totalSupply().

This module is not the only way supply grows. crosschainMint on ERC20BridgeableFacet also increases totalSupply, gated to holders of the trusted-bridge role. The two differ in one important way: this module uses checked arithmetic, so an overflowing mint reverts, while the bridge performs its additions inside an unchecked block.

Last updated:

Newsletter

Get notified about releases, feature announcements, and technical deep-dives on building smart contracts with Compose.

No spam. Unsubscribe anytime.