Using an LP Token or Child Token as the Dividend Token
This tutorial walks you through implementing a vault factory that uses a computed dividend token — a token whose address cannot be known before the tax token is deployed, such as a Uniswap/PancakeSwap LP pair or a child token deployed deterministically from the tax token address.
This feature was introduced in factory spec v2.3.
The Problem
When launching a token through VaultPortal, the caller must supply a dividendToken address — the ERC-20 token that vault holders receive as dividends. Most of the time this is straightforward (e.g. use WBNB, or USDT).
But some vault designs require a dividend token whose address depends on the tax token address itself:
LP pair tokens — the PancakeSwap pair for
(taxToken, WBNB)has an address derived fromtaxToken.Child tokens / receipt tokens — a token deployed via CREATE2 keyed on
taxToken.
At launch time the tax token does not exist yet — VaultPortal predicts its address via CREATE2, but the actual deployment happens inside Portal. The dividendToken field is needed before that deployment, so there is no way to supply the real LP/child address upfront.
The Solution: MAGIC_DIVIDEND_COMPUTED
VaultPortal supports a special sentinel value for dividendToken:
// IPortal.sol
address constant MAGIC_DIVIDEND_COMPUTED =
address(0xC0Dec0dec0DeC0Dec0dEc0DEC0DEC0DEC0DEC0dE);When the launcher passes MAGIC_DIVIDEND_COMPUTED as dividendToken, VaultPortal will:
Compute the CREATE2-predicted tax token address.
Check that the selected vault factory implements spec v2.3 (
factorySpecVersion()returns"v2.3"or higher).Call
resolveDividendToken(predictedToken, launchVersion, launchParams)on the factory.Use the returned address as the actual
dividendTokenforwarded to Portal.
If the factory does not support v2.3, the launch reverts with FactoryDoesNotSupportComputedDividend().
Implementation Guide
Step 1 — Declare spec v2.3 in your factory
Your factory must extend VaultFactoryBaseV2 and override factorySpecVersion() to return "v2.3" (or higher):
Step 2 — Implement resolveDividendToken
IVaultFactoryDividendV23 requires a single function:
predictedToken
The CREATE2-predicted address of the tax token (not yet deployed)
launchVersion
DIVIDEND_TOKEN_LAUNCH_VERSION_V6 or DIVIDEND_TOKEN_LAUNCH_VERSION_V7 depending on the launch wrapper used
launchParams
ABI-encoded NewTokenV6WithVaultParams or NewTokenV7WithVaultParams
VaultPortal calls this as a staticcall, so the function must be view (no state writes).
Example — LP pair dividend
This example resolves the PancakeSwap V2 LP pair of (predictedToken, WBNB) as the dividend token:
Example — Child token dividend
If your vault deploys a child token deterministically from the tax token address:
Step 3 — Declare a policy so the UI pre-fills the sentinel
tokenCreationPolicies() lets the UI know that dividendToken must equal MAGIC_DIVIDEND_COMPUTED. The UI reads this policy and pre-fills (or locks) the field before the user submits the launch form.
Step 4 — Enforce the sentinel in _validateBeforeLaunch
Override _validateBeforeLaunch to reject any launch that does not carry MAGIC_DIVIDEND_COMPUTED. This is the on-chain enforcement that backs the UI policy declared above.
VaultPortal calls onBeforeLaunch(bytes) (which decodes into _validateBeforeLaunch) before it calls resolveDividendToken. This means the hook sees dividendToken == MAGIC_DIVIDEND_COMPUTED — the raw sentinel, not yet the resolved LP address. That is the correct value to check against.
Step 5 — Launch with MAGIC_DIVIDEND_COMPUTED
On the caller side, set dividendToken to the sentinel when building the launch params:
VaultPortal will call myLPVaultFactory.resolveDividendToken(...) and substitute the result before forwarding the launch to Portal.
What Happens On-Chain (Flow Summary)
Version Gating
factorySpecVersion()
MAGIC_DIVIDEND_COMPUTED supported?
"" (legacy / V1)
❌ reverts with FactoryDoesNotSupportComputedDividend
"v2.1", "v2.2"
❌ reverts
"v2.3" or higher
✅ resolveDividendToken is called
Factories that do not implement v2.3 are completely unaffected — the new sentinel only triggers for launches that explicitly pass MAGIC_DIVIDEND_COMPUTED.
Checklist
Last updated