Hooks
Hooks are the core mechanism that allows your Mod to respond to Totem events. When a Totem action occurs (transfer, mint, burn, creation, or ownership transfer), the Totems contract calls the corresponding hook on all licensed mods that are set up to handle that event.
How Hooks Work
%%{init: {'theme': 'dark', 'mirrorActors': false, 'themeVariables': { 'primaryColor': '#1e293b', 'primaryTextColor': '#e5e7eb', 'primaryBorderColor': '#38bdf8', 'lineColor': '#38bdf8', 'actorTextColor': '#e5e7eb', 'actorBkg': '#1e293b', 'actorBorder': '#38bdf8', 'signalColor': '#38bdf8', 'signalTextColor': '#e5e7eb', 'activationBkgColor': '#1e293b', 'activationBorderColor': '#38bdf8', 'sequenceNumberColor': '#e5e7eb', 'noteBkgColor': '#000000', 'noteTextColor': '#9ca3af', 'noteBorderColor': '#4b5563' }}}%%
sequenceDiagram
participant User
participant Totems
participant Mod
User->>Totems: transfer(ticker, to, amount, memo)
Totems-->>Totems: Core logic
Totems->>Mod: onTransfer(ticker, from, to, amount, memo)
Mod-->>Mod: Custom logic
Mod->>Totems: Success/Revert
Totems->>User: Transaction complete When a user performs an action on a Totem, the Totems contract:
- Executes the core operation (transfer, mint, etc.)
- Calls the corresponding hook on each licensed mod
- If any mod reverts, the entire transaction reverts
Important
State changes happen before hooks are called. When your hook executes, balances, supply, and other state have
already been applied. For example, in onTransfer, the recipient’s balance already includes the transferred amount.
This gives your mod the power to enforce rules, track state, or trigger side effects for any Totem event.
Hook Interfaces
IModTransfer
Called after every Totem transfer.
interface IModTransfer {
function onTransfer(
string calldata ticker,
address from,
address to,
uint256 amount,
string calldata memo
) external;
} | Parameter | Description |
|---|---|
ticker | The Totem’s ticker symbol |
from | Address sending the Totems |
to | Address receiving the Totems |
amount | Number of Totems transferred |
memo | Optional message attached to the transfer |
IModMint
Called after Totems are minted.
interface IModMint {
function onMint(
string calldata ticker,
address minter,
uint256 amount,
uint256 payment,
string calldata memo
) external;
} | Parameter | Description |
|---|---|
ticker | The Totem’s ticker symbol |
minter | Address that minted the Totems |
amount | Number of Totems minted |
payment | Amount of native currency paid |
memo | Optional message attached to the mint |
IModBurn
Called after Totems are burned.
interface IModBurn {
function onBurn(
string calldata ticker,
address owner,
uint256 amount,
string calldata memo
) external;
} | Parameter | Description |
|---|---|
ticker | The Totem’s ticker symbol |
owner | Address that burned the Totems |
amount | Number of Totems burned |
memo | Optional message attached to the burn |
IModCreated
Called once when a Totem is first created.
interface IModCreated {
function onCreated(
string calldata ticker,
address creator
) external;
} | Parameter | Description |
|---|---|
ticker | The Totem’s ticker symbol |
creator | Address that created the Totem |
Warning
During Totem creation, all operations on that ticker are frozen. This means no transfers, mints, or burns can occur of that specific ticker until the creation process is fully complete. This ensures a consistent state during setup.
IModTransferOwnership
Called when a Totem’s creator transfers ownership to a new address. This is useful for mods that need to track or react to changes in Totem ownership, such as updating permissions, notifying external systems, or enforcing ownership transfer rules.
interface IModTransferOwnership {
function onTransferOwnership(
string calldata ticker,
address previousOwner,
address newOwner
) external;
} | Parameter | Description |
|---|---|
ticker | The Totem’s ticker symbol |
previousOwner | Address of the previous creator/owner |
newOwner | Address of the new creator/owner |
Note
Only the current creator can transfer ownership. This hook is called after the ownership has been updated,
so totems.getTotem(ticker).creator will already return the new owner when your hook executes.
Reverting in Hooks
If your hook reverts, the entire transaction reverts. This is powerful but should be used carefully:
function onTransfer(
string calldata ticker,
address from,
address to,
uint256 amount,
string calldata memo
) external onlyTotems onlyLicensed(ticker) {
// Block transfers to specific addresses
require(!blocklisted[to], "Recipient is blocked");
} Caution
Be careful with revert conditions. If your mod reverts unexpectedly, users won’t be able to transfer, mint, or burn their Totems. Always test thoroughly and consider edge cases. Though it’s frowned upon that mods are proxy-upgradable, it’s better to have a fixable mod than bricked Totems.
Implementing Multiple Hooks
A single mod can implement any combination of hooks:
contract MultiHookMod is TotemMod, IModTransfer, IModMint, IModBurn, IModTransferOwnership {
constructor(address _totemsContract, address payable _seller)
TotemMod(_totemsContract, _seller) {}
function isSetupFor(string calldata ticker) external view override returns (bool) {
return true;
}
function onTransfer(
string calldata ticker,
address from,
address to,
uint256 amount,
string calldata memo
) external onlyTotems onlyLicensed(ticker) {
// Transfer logic
}
function onMint(
string calldata ticker,
address minter,
uint256 amount,
uint256 payment,
string calldata memo
) external onlyTotems onlyLicensed(ticker) {
// Mint logic
}
function onBurn(
string calldata ticker,
address owner,
uint256 amount,
string calldata memo
) external onlyTotems onlyLicensed(ticker) {
// Burn logic
}
function onTransferOwnership(
string calldata ticker,
address previousOwner,
address newOwner
) external onlyTotems onlyLicensed(ticker) {
// Ownership transfer logic
}
}