PARI MUTUEL POOL (PMP)
(Work in progress) PMP Contract Interface Documentation
Overview
Pari Mutuel Pool is a decentralized contract that aggregates user stakes on discrete outcomes of an event. A PMP does not charge protocol fees, but requires approval from one or more oracles before becoming active.
Each PMP is:
Deployed by a PrivateNote
Bound to a specific event and oracle list
Governed by oracle proposals (multi-oracle voting)
Contract Metadata
Contract name:
PMPRole: Pari Mutuel Pool
Deployed by:
PrivateNoteAuthorization model:
Users:
PrivateNoteOracles: oracle public keys
Lifecycle:
Deploy → Oracle Approval → Configuration → Staking → Resolution → Claims
Key Concepts
Outcomes — Discrete result intervals (minimum 2)
Staking window — Time interval for accepting stakes
Result window — Time interval for resolving outcome
Oracle approval — Required before activation
Oracle governance — Proposals and voting for configuration & resolution
Outcomes
The event has
_numOutcomespossible outcomes.Outcome names are stored in
mapping(uint32 => string) _outcomeNames.Stakes are tracked per outcome and per bet type.
Bet Types
bet_type:
0— clean bet1— debt bet2— coupon bet
Staking window
Oracles set:
_stakeStart/_stakeEnd— stake acceptance window_resultStart/_resultEnd— result/resolution window
Events
StakeAccepted
StakeAcceptedEmitted when a stake is accepted and accounted into the pool.
note(address) — PrivateNote address (wallet) that placed the stake.outcomeId(uint32) — Outcome identifier the stake is placed on.amount(uint128) — Stake amount added to the pool.bet_type(uint8) — 0 - clean bet, 1 - debt bet, 2 - coupon bet
ApprovedByOracle
ApprovedByOracleEmitted when all oracle event lists approve the PMP.
oracleEventList: the oracle event list contract address that sent the approvaloraclePubkey: the oracle public key used as an oracle identifier
Resolved
ResolvedEmitted when the event outcome is resolved.
outcomeId: the resolved outcome identifier
ClaimProcessed
ClaimProcessedEmitted when a claim is processed.
If the event is not resolved or the user did not win, payout will be 0 and win will be false.
note—PrivateNoteaddress (wallet) that claimed.payout— Calculated payout amount (0 if no payout).win— True if the claim is winning and payout > 0.
NetworkFeeBurned
NetworkFeeBurnedEmitted when network fee was burned.
The shown code does not currently emit this event; it is reserved for future accounting.
amount— Burned fee amount in native units.
TimingsSet
TimingsSetEmitted when staking and result windows are configured and the pool is marked approved.
stakeStart: staking start timestampstakeEnd: staking end timestampresultStart: result window start timestampresultEnd: result window end timestamp
NumOutcomesSet
NumOutcomesSetEmitted when number of outcomes is set.
The contract currently derives _numOutcomes from outcomeNames and may not emit this event.
numOutcomes(uint32) — Number of available outcomes
EventCancelled
EventCancelledEmitted when the event is cancelled by oracle governance.
PMPCancelled
PMPCancelledEmitted when a PMP is cancelled by oracle.
ProposalCreated
Emitted when an oracle governance proposal is created.
proposalId: deterministic proposal identifier (typically hash offunctionType+data)functionType: action type identifierdata: ABI-encoded payload (TvmCell)
ProposalExecuted
Emitted when a proposal is executed.
proposalId: executed proposal identifierfunctionType: executed action type identifierdata: ABI-encoded payload used for execution.
Oracle Approval Flow
approveEvent
approveEventThe function is called by an OracleEventList contract to confirm/approve the event initialization for this pool. It also optionally binds an internal sender address to the oracle pubkey for later governance actions.
Parameters:
oracle_pubkey: oracle public key used as an oracle identifieroutcomeNames: mappingoutcomeId -> name(used only on first approval) It represents a logical band of outcomes for a single event. Where:outcomeId(key, e.g.0, 1, 2, …) — the identifier of a specific outcomename— a description of that outcome
Example: Sports Event "Real vs Benfica" Outcome band:
0 — Real wins
1 — Benfica wins
2 — Draw
describe: event description (used only on first approval)name: pool name (used on every approval call)trustAddr: optional internal address binding tooracle_pubkeyfor internal voting flows
Access Control:
Callable only by approved
OracleEventListcontractsThe call is ignored (returns immediately) if:
this oracle event list address was already processed (implementation currently checks or
the number of approvals already reached.
Behavior:
prevents duplicate approvals (by pubkey / sender rules in implementation);
on the first oracle approval, initializes:
the event description (
describe);outcome names mapping (
outcomeNames);number of outcomes (
numOutcomes = outcomeNames.keys().length);
once all required oracle confirmations are collected, emits
ApprovedByOracle(...).
rejectEvent
rejectEventRejects the PMP and self-destructs the contract.
Staking
acceptStake
acceptStakeAccepts a stake from the user’s PrivateNote and records it in the pool.
Parameters:
outcomeId-chosen outcome identifierstakeAmount- stake amountdeposit_identifier_hash- hash used to compute the caller’sPrivateNoteaddressbet_type— 0 - clean bet, 1 - debt bet, 2 - coupon bet
Requirements:
PMP approved by all oracles
Within staking time window
Outcome ID valid
Side Effects:
Updates pools and counters
Notifies
PrivateNotevia callback
acceptFullSetStake
acceptFullSetStakeAccepts a full-set stake from a PrivateNote wallet during the dedicated full-set staking window.
A full-set stake represents proportional participation across all outcomes of the event.
acceptFullSetStake allows a user to stake across all outcomes simultaneously, preserving the proportional distribution of existing pools.
This function:
Validates that the event is approved and not cancelled.
Ensures the event is not yet resolved.
Restricts execution to the full-set time window.
Verifies proportionality against current outcome pools.
Updates internal pool accounting.
Notifies the caller’s
PrivateNoteviaonFullSetStakeAccepted.
Parameters
amount- Array of stake amounts per outcome.Must have length equal to
_numOutcomes.Must follow the required pool proportion rules (see below).
deposit_identifier_hash- Deposit identifier hash used to deterministically compute the caller’sPrivateNoteaddress.
Effects
Increases total pool liquidity.
Preserves pool balance proportions.
Does not affect coupon or debt pools.
Does not emit a specific event; confirmation occurs via callback.
Notes
Full-set staking is only available during the final portion of the staking period.
Designed to allow liquidity providers to enter proportionally without skewing odds.
Cannot be executed after resolution or cancellation.
cancelStake
cancelStakeCancels a user’s stakes after the event is cancelled and returns refund information to the caller’s PrivateNote wallet.
Parameters
stakeAmount— Array of clean stake amounts per outcome.debtAmount— Array of debt stake amounts per outcome.couponsAmount— Array of coupon stake amounts per outcome.deposit_identifier_hash— Deposit identifier hash used to deterministically compute the caller’sPrivateNoteaddress.
Access:
only the computed
PrivateNoteaddress fordeposit_identifier_hash.
Requirements
The event must be cancelled:
If
block.timestamp > _resultEndand the event is not resolved and not cancelled, the contract triggerscancelEvent()internally.After that, the function requires
_isCancelled == true.
Caller must be the expected
PrivateNotewallet address derived fromdeposit_identifier_hash.
External Calls
Calls
PrivateNote(wallet).onStakeCancelled(...)to notify the wallet about:total refunded clean+debt stake (
totalStake)total refunded coupon amount (
totalCouponRefund)
withdrawFullSet
withdrawFullSetCancels a previously placed full-set stake during the full-set window and updates pool accounting accordingly.
This function is used to withdraw (undo) a proportional full-set stake before the staking period ends
Parameters
amount- Array of withdrawal amounts per outcome.Must have length equal to
_numOutcomes.Must preserve proportionality relative to current outcome pools.
deposit_identifier_hash- Deposit identifier hash used to deterministically compute the caller’sPrivateNotewallet address.
withdrawFullSet removes a proportional full-set stake across all outcomes, provided the withdrawal keeps the same proportionality constraints used for full-set staking.
The function:
Ensures the event is approved, not cancelled, and not resolved.
Restricts execution to the full-set time window.
Validates proportionality of the provided
amount.Decreases outcome clean pools and global totals.
Notifies the caller’s
PrivateNotewallet viaonFullSetStakeCancelled.
Proportionality Rule
The withdrawal amounts must preserve the same proportional structure enforced for full-set operations:
For outcomes with non-zero pools:
amount[i]must match the proportional ratio relative to pool sizes.
For outcomes with zero pools:
amount[i]must be zero.
This is validated by _checkFullSetProportion(amount).
Notes
This function does not emit a dedicated event; confirmation is delivered via the callback to
PrivateNote.Withdrawals are only possible before
_stakeEnd, and only afterfullSetStart.The proportionality rule prevents selective withdrawal that would skew the pool distribution.
Claims
claim
claimClaims winnings (or processes a zero-payout claim) for a PrivateNote wallet after event resolution.
claim allows a user to settle their position in the PMP after the event has been resolved.
Depending on the outcome and the user’s position, the function:
Processes a winning payout, or
Processes a zero-payout claim if:
The event is not resolved yet, or
The user has no stake on the winning outcome.
After calculation, the contract notifies the caller’s PrivateNote wallet via onClaimAccepted and emits ClaimProcessed.
Effects
Finalizes user settlement.
Distributes winnings according to pari-mutuel logic.
Automatically terminates the contract when all winning claims are completed.
Notes
Arrays are expected to correspond to
_numOutcomes.Claim can be called multiple times by different participants until
_totalWinPoolis fully distributed.
Oracle Governance
createProposal
createProposalCreates a new oracle governance proposal for the PMP contract.
This function allows authorized oracle participants to propose administrative actions such as:
Setting staking and result time windows
Resolving the event
Cancelling the event
Parameters
function_type- Identifier of the proposed action. Must correspond to one of the supportedFUNCTION_TYPE_*constants:FUNCTION_TYPE_SET_STAKE_DEADLINEFUNCTION_TYPE_SET_RESOLVEFUNCTION_TYPE_CANCEL_EVENT
data- ABI-encoded payload required for the specified function type.
Behavior:
createProposal initializes a new governance proposal and automatically casts the creator’s vote.
The proposal is identified deterministically by:
If there is only one oracle, the proposal is executed immediately.
Otherwise, the proposal remains active until:
It collects enough votes (based on threshold), or
Its deadline expires (7 days from creation).
Governance Flow
Oracle creates proposal → creator vote is automatically counted.
Other oracles call
vote(proposalId).Once vote threshold is reached:
executeProposalis called.
Proposal is deleted after execution.
If deadline expires before threshold:
Proposal is discarded.
vote
voteVotes on an existing proposal.
Parameter:
proposalId: identifier of the proposal to vote on
Access:
only authorized oracles.
Behavior:
rejects if proposal does not exist;
ignores/removes proposal if it is past deadline;
prevents double voting by the same oracle pubkey;
executes proposal automatically once the threshold is reached (implementation-specific);
successful execution leads to
ProposalExecuted(...).
View Functions
getDetails
getDetailsReturns the full current state of the PMP contract.
This function provides a comprehensive snapshot of the pool configuration, lifecycle state, oracle status, and pool balances.
Returns :
General Information
name- Human-readable pool name.token_type- Static token type used for the pool.event_id- Identifier of the associated event.oracle_list_hash- Hash of the oracle list used during deployment.deployer- Address of thePrivateNotewallet that deployed the contract.privateNoteCodeHash- Hash of thePrivateNotecontract code used for address derivation.
Pool State
totalPool- Total amount currently in the pool (after fees and redistributions).approved- Indicates whether the event is approved and staking is enabled.isCancelled- Indicates whether the event has been cancelled.resolvedOutcome- Final outcome identifier, if resolved.
Outcomes
numOutcomes- Total number of outcomes.outcomeNames- Mapping of outcome identifiers to human-readable names.typedOutcomePools- Pool balances separated by:Outcome ID
Bet type (0 = clean, 1 = debt, 2 = coupon)
Time Windows
stakeStart- Stake acceptance start timestamp.stakeEnd- Stake acceptance end timestamp.resultStart- Result acceptance start timestamp.resultEnd- Result acceptance end timestamp.
Oracle Governance
numberOfOracleEvents-Total number of required oracle confirmations.approvedOracleEvents-Number of oracle confirmations received.
getVersion
getVersionReturns the implementation version and kind identifier.
Returns:
semver: version stringkind: contract kind string (expected"PMP")
Last updated