PARI MUTUEL POOL (PMP)

(Work in progress) PMP Contract Interface Documentation

file-download
7KB

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: PMP

  • Role: Pari Mutuel Pool

  • Deployed by: PrivateNote

  • Authorization model:

    • Users: PrivateNote

    • Oracles: 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 _numOutcomes possible 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 bet

  • 1 — debt bet

  • 2 — coupon bet

Staking window

Oracles set:

  • _stakeStart / _stakeEnd — stake acceptance window

  • _resultStart / _resultEnd — result/resolution window

Events

StakeAccepted

Emitted 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

Emitted when all oracle event lists approve the PMP.

  • oracleEventList: the oracle event list contract address that sent the approval

  • oraclePubkey: the oracle public key used as an oracle identifier


Resolved

Emitted when the event outcome is resolved.

  • outcomeId: the resolved outcome identifier


ClaimProcessed

Emitted 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.

  • notePrivateNote address (wallet) that claimed.

  • payout — Calculated payout amount (0 if no payout).

  • win — True if the claim is winning and payout > 0.


NetworkFeeBurned

Emitted 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

Emitted when staking and result windows are configured and the pool is marked approved.

  • stakeStart: staking start timestamp

  • stakeEnd: staking end timestamp

  • resultStart: result window start timestamp

  • resultEnd: result window end timestamp


NumOutcomesSet

Emitted 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

Emitted when the event is cancelled by oracle governance.


PMPCancelled

Emitted when a PMP is cancelled by oracle.


ProposalCreated

Emitted when an oracle governance proposal is created.

  • proposalId: deterministic proposal identifier (typically hash of functionType + data)

  • functionType: action type identifier

  • data: ABI-encoded payload (TvmCell)


ProposalExecuted

Emitted when a proposal is executed.

  • proposalId: executed proposal identifier

  • functionType: executed action type identifier

  • data: ABI-encoded payload used for execution.


Oracle Approval Flow

approveEvent

The 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 identifier

  • outcomeNames: mapping outcomeId -> 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 outcome

    • name — 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 to oracle_pubkey for internal voting flows

Access Control:

  • Callable only by approved OracleEventList contracts

  • The 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

Rejects the PMP and self-destructs the contract.


Staking

acceptStake

Accepts a stake from the user’s PrivateNote and records it in the pool.

Parameters:

  • outcomeId-chosen outcome identifier

  • stakeAmount- stake amount

  • deposit_identifier_hash- hash used to compute the caller’s PrivateNote address

  • bet_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 PrivateNote via callback


acceptFullSetStake

Accepts 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 PrivateNote via onFullSetStakeAccepted.

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’s PrivateNote address.

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

Cancels 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’s PrivateNote address.

Access:

  • only the computed PrivateNote address for deposit_identifier_hash.

Requirements

  • The event must be cancelled:

    • If block.timestamp > _resultEnd and the event is not resolved and not cancelled, the contract triggers cancelEvent() internally.

    • After that, the function requires _isCancelled == true.

  • Caller must be the expected PrivateNote wallet address derived from deposit_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

Cancels 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’s PrivateNote wallet 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 PrivateNote wallet via onFullSetStakeCancelled.

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 after fullSetStart.

  • The proportionality rule prevents selective withdrawal that would skew the pool distribution.


Claims

claim

Claims 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 _totalWinPool is fully distributed.


Oracle Governance

createProposal

Creates 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 supported FUNCTION_TYPE_* constants:

    • FUNCTION_TYPE_SET_STAKE_DEADLINE

    • FUNCTION_TYPE_SET_RESOLVE

    • FUNCTION_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

  1. Oracle creates proposal → creator vote is automatically counted.

  2. Other oracles call vote(proposalId).

  3. Once vote threshold is reached:

    • executeProposal is called.

  4. Proposal is deleted after execution.

  5. If deadline expires before threshold:

    • Proposal is discarded.


vote

Votes 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

Returns 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 the PrivateNote wallet that deployed the contract.

  • privateNoteCodeHash - Hash of the PrivateNote contract 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

Returns the implementation version and kind identifier.

Returns:

  • semver: version string

  • kind: contract kind string (expected "PMP")

Last updated