Incentive Types
Leaderboard, rebate, raffle, and direct distribution types
Torque supports four incentive types, each determining how rewards are distributed to participants. Any query can use any type.
Leaderboard
Rank participants by their query metric and reward based on position. Payouts come from customFormula.
Always ask the user how they want rewards distributed before creating a leaderboard. The fallback
formula N pays each user their raw metric value (e.g., a trader with $10,000 volume would receive 10,000
tokens — essentially doubling their money). This is rarely intended. Build a customFormula from the user's
stated payout intent.
Common formula patterns:
- Fixed rank prizes:
RANK == 1 ? 10000 : RANK == 2 ? 5000 : RANK == 3 ? 2000 : 0— settotalFundAmount>= sum of all prizes. - Tiered ranges:
RANK <= 3 ? 10000 : RANK <= 10 ? 5000 : RANK <= 50 ? 1000 : 0. - Equal split:
TOTAL_REWARD_POOL / TOTAL_PARTICIPANTS. - Diminishing by rank:
TOTAL_REWARD_POOL / pow(RANK, 0.5)— top performers get more; lower ranks get reduced amounts as the pool depletes. - Capped payouts:
min(N * 0.1, 500)— 10% of metric value, capped at 500 per user.
| Parameter | Required |
|---|---|
totalFundAmount | Yes |
customFormula | Strongly recommended (ask user) |
Rebate
Return a percentage of each user's tracked value. The MCP constructs the formula from rebatePercentage.
- Formula:
VALUE * (rebatePercentage / 100)— e.g., 5% rebate becomesVALUE * 0.05. - Use case: cashback on trades, purchase rebates, fee refunds.
Custom formula examples:
- Tiered:
VALUE > 1000 ? VALUE * 0.1 : VALUE * 0.05 - Capped:
min(VALUE * 0.05, 500)
| Parameter | Required | Description |
|---|---|---|
totalFundAmount | Yes | Caps the total pool |
rebatePercentage | Yes | e.g. 5 for 5% |
Raffle
Randomly select winners from qualifying participants. Winners are drawn per raffleBuckets; tickets are assigned per raffleWeighting.
Always ask the user how tickets should be distributed before creating a raffle — WEIGHTED_BY_METRIC (activity = tickets) vs. EQUAL_CHANCES (1 ticket per qualifying user).
Weighting modes:
WEIGHTED_BY_METRIC(default) — ticket count equals the user's metric value. A user with 100 volume gets 10× more entries than a user with 10 volume. Query results must be sorted by value (highest first).EQUAL_CHANCES— every qualifying user gets exactly 1 ticket. The metric only determines whether they meet the threshold to enter.
Raffle buckets define prize tiers:
[
{ "amount": 100, "count": 1 },
{ "amount": 50, "count": 5 },
{ "amount": 10, "count": 20 }
]This creates 1 grand prize of 100, 5 prizes of 50, and 20 prizes of 10. totalFundAmount is derived from the sum. Each wallet can only win once per draw.
| Parameter | Required | Description |
|---|---|---|
raffleBuckets | Yes | Prize tiers |
raffleWeighting | No | WEIGHTED_BY_METRIC (default) or EQUAL_CHANCES |
Direct
Distribute rewards to a specific list of wallet addresses that the user provides directly — either by pasting address,amount pairs inline or by supplying a CSV. direct describes HOW allocations are supplied (the user hands them to the tool), not a payout rank or formula.
Internally, direct is persisted as type: LEADERBOARD, distributionType: FORMULA, customFormula: "N". The MCP constructs an inline SQL query from the allocations (each row has an address and an amount), and each wallet receives its allocation amount.
A customFormula CAN still be supplied to transform the allocation values — e.g., min(N, 500) to cap each payout at 500, or N * 0.5 to halve everything.
Use case: airdrops, team rewards, partner distributions, recurring fixed payouts.
| Parameter | Required |
|---|---|
allocations | Yes |
Allocations can be an array or CSV:
[
{ "address": "wallet1...", "amount": 500 },
{ "address": "wallet2...", "amount": 300 }
]MCP input vs. persisted config names
The MCP input arg names on create_recurring_incentive map to different persisted names in the epoch's distribution config:
| MCP input arg | Persisted field |
|---|---|
raffleBuckets | prizeBuckets |
raffleWeighting | selectionLogic |
If you're reading analytics or epoch configs (via get_recurring_incentive or the underlying API), expect the persisted names.
Flat-reward pattern
To pay every qualifying user the same amount, don't hard-code it in the formula — instead, flatten the metric at query time:
- In
generate_incentive_query, setvalueExpression: "1"(constant value for every qualifying user). - In
create_recurring_incentive, usecustomFormula: "TOTAL_REWARD_POOL / TOTAL_PARTICIPANTS"(equal split).
This works for any source with valueExpression (custom_event, idl_instruction, dune_query).