إنتقل إلى المحتوى الرئيسي

Birth Hook Integration Guide

For Exchanges, DEXs, Games, and Protocols

This page explains how to add soToken object claims to your platform so users earn balance-backed objects when they trade, swap, play, or complete actions on your protocol.

The Setup

When a creator launches a soToken, they choose:

  • A source token (the asset users need to hold to support objects)
  • An interval (how much of that token supports one object)
  • A seed module (how to derive the object appearance from an action)
  • Approved birth hooks (which contracts can mint objects)

Your protocol or DEX becomes an approved birth hook. That means you can verify when a user completes an action on your platform, then call the soToken ledger to claim an object for them.

The Flow

1. User performs action on your platform (swap, route, game, etc.)
2. Your hook contract verifies the action and identifies the real recipient
3. Hook calls ledger.claimFor(owner, amount, context)
4. Ledger confirms:
- hook is approved by the creator
- user holds enough source token (interval-based)
- total object count is within max
5. Seed module derives object appearance from context
6. soToken object is born tied to user's source-token balance

The Ledger API

Authorize your hook

Ask the token creator to call:

ledger.setBirthHook(yourHookAddress, true)

This is a one-time creator action. It approves your contract to call claimFor.

Claim objects for users

Your hook calls:

(uint256[] memory objectIds) = ledger.claimFor(
owner, // The user who performed the action
amount, // Amount of source token to support (usually = interval)
context // Bytes describing the action (see below)
)

The ledger will:

  • Check that msg.sender (your hook) is approved
  • Verify the user holds enough source-token balance to support the new object
  • Call the seed module to derive a seed from context
  • Claim the object(s)
  • Return the object IDs that were born

If the user doesn't hold enough source token or the token hit its max object cap, the transaction reverts.

Context and Seeds

The context parameter should encode information about the action:

// Example: swap on Uniswap v4
abi.encode(
poolAddress,
amountIn,
amountOut,
userAddress,
blockNumber,
nonce
)

The seed module hashes this context (plus ledger state like block number and owner balance) into a deterministic seed. The renderer uses the seed to select traits from its weighted layers.

The context is NOT stored on-chain. It is only used to derive the seed at birth time. Different users performing the same action on your platform will get different objects because their balance, owner index, and block context differ.

Verifying Recipient

Do not blindly trust msg.sender in a complex protocol flow.

In routed swaps, relayers, aggregators, or other contracts may be the direct caller. Your hook must prove that the user actually performed the action.

Safe approaches:

  • The user calls your hook directly (simplest)
  • A trusted router passes the recipient and you verify the caller
  • Hook data includes the recipient and you verify it matches the action
  • You use signed intent data from the user (e.g., EIP-712)

Bad approach:

// ❌ Wrong: This could be any account
address user = tx.origin;

Source Token Support

The ledger enforces the soToken invariant:

floor(user.sourceTokenBalance / interval) >= number of active objects

If a user sells their source token later and no longer has enough balance, the ledger's sync(owner) function reconciles unsupported objects. LOAs become Dormant. BOAs apply the configured lost-support policy.

This is not a bug. It is the core soToken model: balance backs object capacity.

Example: Uniswap v4 Hook

The Mirage BpegUniswapV4SeedModule expects context to include swap information:

// In your Uniswap v4 hook
bytes memory context = abi.encode(
poolKey,
swapAmount,
userAddress
);

// Then call claimFor on the soToken ledger
ledger.claimFor(userAddress, interval, context);

The seed module hashes this context to produce a deterministic seed. Every object born from a Uniswap swap can look different based on the pool, amount, and user.

Finder's Fee & Creator Control

There is no automatic finder's fee or integration cut in the protocol. Rewards are between you and the collection creator:

  • Some creators might offer you a portion of launch fees for integration
  • Others might run their own incentive/airdrop program
  • Others might just want the integration for community value

Talk to creators directly. Mirage does not take a fee on your integration.

Error Handling

Common reverts and what they mean:

ErrorMeaning
NotApprovedForBpegYour hook is not approved by the creator (ask them to call setBirthHook)
InsufficientBalanceUser doesn't hold enough source token to support a new object
MaxObjectsReachedThe collection hit its hard cap on total objects ever born
ZeroAmountYou passed amount = 0 (should be at least interval)

Message to Creators

When you want a creator to approve your hook:

Your soToken ledger can be integrated with [your platform]. When users [action on your platform], we can claim objects for them. The ledger enforces balance support automatically, so this is not a minting backdoor. Users still need to hold your source token. We've deployed a birth hook contract at [address]. Can you call setBirthHook([address], true) to approve us?

If they use a non-default seed module, they might want to verify your context format matches what the module expects.

Next Steps

  1. Read the ledger interface: the soToken interfaces in the contracts repo
  2. Write a hook contract that verifies your action and calls claimFor
  3. Test on Base Sepolia with the test factory
  4. Find a creator with a soToken and ask them to approve your hook
  5. Launch and users can earn objects on your platform

Security checklist for your hook

Before shipping:

  • your hook cannot be called by anyone other than the intended trigger (pool, router, user)
  • the recipient is verified, not just msg.sender or tx.origin
  • you validate the ledger address is one you intended to call
  • you have replay protection if you use off-chain signatures
  • your contract is reentrancy-safe around the claimFor call
  • you have a revoke path so the creator can disable your hook if needed
  • your events emit enough data for the app to explain the birth