Vault & VaultFactory Specification
Table of Contents
Quick start
Follow the example β Work through the FlapVaultExample repository to see a complete, working vault and vault factory implementation. It is the fastest way to understand the patterns you need to follow.
Verify your implementation β Once you have written your vault, use the FlapVaultSpecChecker AI toolkit to automatically check that your implementation correctly follows this specification before deploying.
Overview
Flap's vault system allows anyone to build smart contracts for managing and distributing BNB revenue generated from tax tokens. Vaults can be customized to fit various use cases β splitting revenue among multiple recipients, routing funds based on social proof, funding a game treasury, or anything else you can imagine.
Permissionless vault creation β You can now create and deploy your own vaults and vault factories without any permission or registration. Vault factories no longer need to be registered in the VaultPortal before they can be used to launch tokens. Users can use any vault they want when launching tokens.
For a complete working example of a vault and vault factory implementation, check out the FlapVaultExample repository.
There are two generations of the vault specification:
V1
VaultBase
IVaultFactory
Core spec β description(), Guardian mandate
V2
VaultBaseV2 (extends VaultBase)
VaultFactoryBaseV2 (implements IVaultFactory)
On-chain UI schema for automatic UI generation
V2 is fully backwards-compatible with V1. Existing vaults that extend VaultBase are unaffected. New vault implementations should extend VaultBaseV2 and new factory implementations should extend VaultFactoryBaseV2 to gain UI schema support.
The Vault Specification
VaultBase (V1)
To be compatible with the VaultPortal system, your vault smart contract must inherit the VaultBase contract:
Implementation requirements:
Implement
description()β Return a dynamic string that describes the vault's current state. The description should change based on the vault's state (e.g. balance, streaming status, etc.).Implement
receive()β Accept BNB from the tax token and process the revenue according to your vault's logic.Guardian mandate β If you have any permissioned functions that should be triggered by an external address, and it is not suitable to make them public (e.g. buyback which may be sandwich attacked), you must also give the Guardian address the permissions alongside other allowed addresses as a backup. See the Flap Guardian section for details.
VaultBaseV2
VaultBaseV2 inherits from VaultBase and adds a single new abstract method: vaultUISchema(). This allows the UI to automatically discover and render the vault's user-facing methods β without needing custom code for each vault type.
What changes from V1:
All V1 obligations still apply (
description(),receive(), Guardian mandate).You must additionally override
vaultUISchema()to return aVaultUISchemadescribing every user-facing method your vault exposes. See the UI Schema Reference section for the full struct definitions.
Why this matters: Without a self-describing mechanism, every new vault type would require a custom UI to be built and deployed before users could interact with it. vaultUISchema() solves this problem by enabling automatic UI generation for any future vault type.
Existing vault types (FlapXVault, SplitVault, SnowBallVault, BlackHoleVault) already have purpose-built UIs. VaultBaseV2 is designed for future vault implementations β the UI can automatically generate a full interaction page for any vault that implements this interface.
Example β Hypothetical DonationVault:
Example β StakingVault with approve actions:
The Flap Guardian
The Flap Guardian is a privileged address that can always call permissioned functions in vault contracts that implement the Vault Specification. The Guardian serves as a backup mechanism to ensure that critical functions can be executed even if the primary authorized addresses are unable to do so.
At this moment, the Guardian is an empty but upgradeable contract managed by Flap:
Ideally, we don't need to implement any functionality in the Guardian contract. It just serves as a trusted address that can step in when necessary to protect users' funds.
If your vault has permissioned functions, you must grant the Guardian the same permissions. The Guardian's access must not be revocable by any other account β only the Guardian itself may renounce its own access.
When using OpenZeppelin's AccessControl, override revokeRole():
Adapter for legacy vaults
If you have built a vault to receive tax token revenue before the Vault Specification was introduced, you can still make your vault compatible with the VaultPortal system by creating an adapter contract that inherits from VaultBase and wraps around your existing vault. The adapter will implement the description() method and forward calls to your legacy vault as needed. This way, you can leverage VaultPortal features without modifying your original vault contract.
Please reach out to our team for assistance in creating an adapter for your legacy vault.
VaultFactory Specification
A vault factory deploys vault instances for new tax tokens. When a user launches a token through the VaultPortal, the portal calls your factory's newVault() method to create the vault.
No registration required β In V2, any contract that implements VaultFactoryBaseV2 can be passed to the VaultPortal to launch tokens. You do not need to register your factory on-chain.
IVaultFactory (V1)
The base interface that all vault factories must implement:
Key points:
Currently, only BNB (
quoteToken == address(0)) is supported as the quote token, but future support for other quote tokens may be added.The
newVaultmethod is called by the VaultPortal when a new tax token is being created. The tax token does not exist yet when this method is called β the VaultPortal predicts the token address and passes it. The actual token is created after the vault.
VaultFactoryBaseV2
VaultFactoryBaseV2 implements IVaultFactory and adds a new abstract method: vaultDataSchema(). This allows the UI to discover what vaultData encoding the factory expects, and render the launch form accordingly.
What changes from V1:
All V1 obligations still apply (
newVault(),isQuoteTokenSupported()).You must additionally override
vaultDataSchema()to return aVaultDataSchemadescribing the fields your factory expects in thevaultDataparameter.The factory now provides
_getVaultPortal()and_getGuardian()helpers.
Example β Single tuple schema:
Example β Array of tuples schema:
Example β Factory that ignores vaultData:
Recommended commission fee structure
Vault factories can charge a commission fee from the tax revenue. The fee structure must be clearly described in the vault's description() method. The recommended fee calculation is based on the tax rate (taxRateBps) and the received tax revenue (msg.value):
If
taxRateβ€ 1% (100 bps), the fee is 6% ofmsg.value.If
taxRate> 1%, the fee is(msg.value * 6) / taxRateBps.
UI Schema Reference (IVaultSchemasV1)
The shared struct definitions in IVaultSchemasV1.sol power the automatic UI generation for both vault factories (token launch forms) and vaults (vault interaction pages).
FieldDescriptor
The unified leaf type shared by both the factory schema and the vault UI schema:
Supported fieldType values:
fieldType
UI widget
Notes
"string"
Text input
"address"
Address input
With checksum validation
"uint16"
Number input
0β65535
"uint256"
Big-number input
"uint128"
Number input
"bool"
Checkbox
"bytes"
Hex input
"bytes32"
Hex input
32 bytes
"time"
Date/time picker
Alias for uint256; value is a Unix timestamp in seconds. Displayed as human-readable time or countdown in outputs
decimals behaviour:
Factory encoding (input): If
decimals > 0, the UI multiplies the user's input by $10^{\text{decimals}}$ before ABI-encoding. If0, the raw value is used.Vault display (output): If
decimals > 0, the UI divides the raw on-chain value by $10^{\text{decimals}}$ for display. If0, the raw value is displayed.For non-numeric fields (
string,address,bytes,bool),decimalsshould always be0.
VaultDataSchema
Returned by VaultFactoryBaseV2.vaultDataSchema(). Describes the shape of the vaultData bytes the factory expects:
How the UI uses VaultDataSchema:
Call
factory.vaultDataSchema()to get the schema.For each field in
fields, render the appropriate input widget based onfieldType.If
isArray == true, render an "Add Item" button for dynamic array entries.Encode the user input: if
isArrayuseabi.encode(tuple[]); otherwise useabi.encode(tuple).The encoded bytes are passed as
vaultDatainNewTaxTokenWithVaultParams.
If fields is empty and isArray is false, the factory ignores vaultData entirely.
VaultUISchema & supporting types
Returned by VaultBaseV2.vaultUISchema(). Describes the vault's entire UI surface:
How the UI uses VaultUISchema:
Display
vaultTypeas a badge/header anddescriptionas subtitle.Always call
vault.description()and display the result as a dynamic status banner (polled periodically).For each method:
View methods (
isWriteMethod == false): If no inputs, call immediately and display results. If inputs exist, render input fields with a "Query" button.Write methods (
isWriteMethod == true): Render a form with inputs. Ifapprovalsis non-empty, execute eachApproveActionbefore sending the write transaction.
Methods are displayed in the order returned.
ApproveAction workflow:
Resolve the token address from
tokenType:"taxToken"β callvault.taxToken(),"lpToken"β callvault.lpToken(), unknown β skip (forward-compatible).Read the amount from the user's input field named by
amountFieldName(already scaled bydecimals).Check current allowance:
token.allowance(user, vault). If sufficient, skip.Send
token.approve(vault, amount)and wait for confirmation.
Get your vault verified
Please reach out to our team if you want to get your vault or vault factory verified by us or our auditing partners.
Before reaching out, make sure:
You have correctly implemented the Vault Specification (the
description()method, the Guardian access to permissioned functions, andvaultUISchema()/vaultDataSchema()if using V2).Your factory contract is not upgradeable. If you want to upgrade your factory in the future, you must deploy a new factory contract and get it verified again.
The commission fee structure is clearly described in the vault's
description()method.You have passed some basic AI auditing tools β see the FAQ below.
We strongly recommend using AI auditing tools before deploying your smart contracts and tokens. This can help you resolve critical vulnerabilities before submitting for manual review.
FAQ
How to use AI to audit your smart contracts?
You can use any AI for auditing your smart contracts. For example, you can use Google's AI Studio which is free to use. The prompt is as follows:
This can help you identify common vulnerabilities and issues in your smart contracts. If your comments are clear enough, it will even help identify logical issues. However, AI tools are not perfect and may miss vulnerabilities or provide incorrect suggestions. Always review your smart contracts thoroughly before deploying them on mainnet.
Last updated