forge soldeer install
# unit tests:
forge test
# integration tests:
FOUNDRY_PROFILE=itest forge test
# fork tests:
FOUNDRY_PROFILE=ftest forge test
QUESTION_TIMEOUT=3600 \
MIN_BOND=100000000000000 \
forge script script/DeployFlatCFMRealityAdapter.s.sol …
ORACLE_ADAPTER=0x1234... \
CONDITIONAL_TOKENS=0xabcd... \
WRAPPED1155_FACTORY=0x9999... \
forge script script/DeployFlatCFMFactory.s.sol:DeployFlatCFMFactory …
Exemple decision template:
TEMPLATE_CONTENT='{"title": "Which project got funded during CFM round #23?", "type": "multiple-select", "outcomes": [%s], "category": "cfm-decision", "lang": "en"}' \
forge script script/CreateRealityTemplate.s.sol …
Example metric template:
TEMPLATE_CONTENT='{"title": "Between the first block of 2025-01-01 and the last block of 2025-06-30, what is the average TVL in million USD, calculated at each block, for %s on BrandNewChain?", "type": "uint", "category": "cfm-metric", "lang": "en"}' \
forge script script/CreateRealityTemplate.s.sol …
First deploy the Flat CFM instance:
Then deploy each Conditional Scalar Market, one per outcome:
First, define a config file (by default, use ./flatcfm.config.json
), like
{
"factoryAddress": "0x1234567890abcdef1234567890abcdef12345678",
"oracleAdapterAddress": "0x1234567890abcdef1234567890abcdef12345678",
"decisionTemplateId": 24,
"metricTemplateId": 42,
"collateralToken": "0x1234567890abcdef1234567890abcdef12345678",
"outcomeNames": [
"Project A",
"Project B",
"Project C",
"Project D"
],
"openingTimeDecision": 1737111600,
"minValue": 0,
"maxValue": 100,
"openingTimeMetric": 1737457200,
"metadataUri": "ipfs://1234"
then run
forge script script/CreateFlatCFMFromConfig.s.sol \
--rpc-url $RPC_URL \
--broadcast \
--sender $ADDRESS \
--private-key $PRIVATE_KEY
The mechanism implemented here is a simplified version of CFMs called "Flat CFM".
The main contract, FlatCFM
represents a CFM with a flat outcomes structure:
each outcome represents the condition that a project gets funded. These outcomes
are also called decision outcomes.
ConditionalScalarMarket
represents the scalar prediction market which is
conditional on the parent outcome being selected. It contains outcomes Short
(also called DOWN), Long
(also called UP) and Invalid
.
The FlatCFMFactory
contract enables the creation of a FlatCFM
and its
related ConditionalScalarMarket
. For a given CFM, it helps creating the
unique FlatCFM
instance, one ConditionalScalarMarket
instance per decision
outcome (not counting for the Invalid outcome), asks the associated oracle
questions and prepares the associated conditional tokens.
FlatCFMRealityAdapter
implements an adapter pattern to access RealityETH from our
contracts, with a normalized interface.
The system follows these general steps:
- The
FlatCFMFactory
creates a newFlatCFM
with specified parameters. This enables creation ofConditionalScalarMarket
s for each outcome. This submits the decision question to the oracle viaFlatCFMRealityAdapter
and prepares the decision condition throughConditionalTokens
. - The
FlatCFMFactory
creates newConditionalScalarMarket
s for an existingFlatCFM
. This submits the scalar question to the oracle viaFlatCFMRealityAdapter
and prepares the scalar conditions throughConditionalTokens
. This relies on a Reality template with a placeholder for the decision outcome name. - Users split their collateral into decision outcome tokens, then split again into scalar outcome tokens. These tokens are ERC20s and can be traded on AMMs.
- When the oracle provides an answer to the decision question, the
FlatCFM
can be resolved and calculates payouts. - When the oracle provides an answer to the conditional scalar questions (all
together), all
ConditionalScalarMarket
s can be resolved and calculate payouts. - Users can redeem their positions for payouts.
Gnosis' Conditional Token framework
provides the ability to create and manipulate tokens that are tied to a specific
condition happening. ConditionalTokens
is the core contract that manages among
others the creation and redemption of conditional tokens.
The codebase also rely on Wrapped1155Factory
which enables wrapping 1155
outcome tokens in ERC20s so participants can trade them on any AMM.
Both these contracts are re-deployed in their original and audited versions. We updated the build pipeling with modern tooling: see here and here.
Reality.eth is the first oracle for which an adapter has been implemented. This is a general-purpose oracle which uses Kleros as an arbitrator.
As with any external oracle, the CFM contracts economic security is limited by the economic security of the Reality + Kleros system.
Reality can return 'invalid' in case the question can't be answered.
At the decision outcome level, an invalid case means CFM contracts can't figure
whether any project has succeeded in getting funded. Hence, it is equivalent to
the fact that none of the outcomes was returned by the oracle, ie that no
project got funded.
In such a case, collateral redemption will be made available to participants in
a direct way, not accounting for any of the trading that happened in
ConditionalScalarMarket
s.
This is achieved by adding a supplementary decision outcome in FlatCFM
s, which
will get the whole payout in such cases (no project got funded or Invalid).
At the individual project level with a scalar outcome, invalid means that CFM's
scalar markets can't know how to reward traders. It thus means that the market
should return collateral deposits as-is, hence allow merging of tokens but not
redemption.
This is achieved by the same principle as above: ConditionalScalarMarket
s
create 3 outcomes: Short, Long, Invalid. No facility is provided for trading
Invalid tokens.
Reality bounties (and thus, msg.value
forwarded by these contracts) are only
useful to guarantee that the arbitrator fee requirement is fulfilled. FlatCFM &
ConditionalScalarMarket deployers (Deployers) need to be aware of the amounts
required by the arbitrator that they're using, and will need to input a
msg.value
at least matching the arbitrator fee.
On a crypto-economics level, the cfm-v1 protocol doesn't require "pure" Reality bounties (aimed at incentivizing answers, what comes atop the arbitrator fee). Indeed, Deployers are expected to make decisions with significant budget at stake based on FlatCFMs markets resolving properly. This is providing a large enough existing incentive for Reality questions to be answered to.