Skip to main content

ERC-20 Mint Module

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

Helper function for creating new ERC-20 tokens

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;
}

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.