Outcome templates and keywords
Every deployer-created HIP-4 market fills a validator-voted template that fixes its wording, side names and typed keywords, one value per keyword.
A template takes the wording out of your hands. Validators vote it in, fixing the text, side names and typed keywords; you only fill the keywords. Its semanticRestriction states what its markets may mean, and a market that contradicts it is malformed and slashable.
Say you fill binaryPrice with perp BTC, priceDescription “the BTC mark”, seconds 60, threshold 100000 and time 20261101-1200. On chain the name is template:binaryPrice and the description perp:BTC|priceDescription:the BTC mark|seconds:60|threshold:100000|time:20261101-1200. It resolves Yes if the 60-second TWAP is above 100000 at 12:00 UTC on 1 November 2026.
Every template has one of 3 roles
Section titled “Every template has one of 3 roles”| Role | Deploys | Fixes |
|---|---|---|
| Standalone outcome | a single two-sided market | the side names, for example Over and Under |
| Question | a question, the container | the question’s text; sides are Yes and No |
| Question outcome | one outcome inside a question | declares a parent question template and only instantiates under it |
Names and descriptions contain typed {keyword} placeholders, for example "{underlying} above {target} at {expiry}"; an instance supplies exactly one value per keyword.
Where templates come from
Section titled “Where templates come from”Validators vote templates in with registerTemplate; {"type": "outcomeTemplates"} lists a network’s templates. Mainnet listed none until permissionless deployment launched, then 18 on 2026-09-14 (testnet 60, and 66 by 2026-09-20).
Versions are new ids with a numeric suffix (binaryPrice up to binaryPrice6); deployer tooling treats the highest as current. The same id can differ by network (5 keywords on one, 11 on the other) or exist on only one: mainnet has scalarPrice, testnet instead scalePrice (misspelt), scalePrice2 and scalarPrice3, same keywords.
Read outcomeTemplates on the target network every time, comparing keywords and semanticRestriction, not just the id: a new version can change what a market may mean.
The mainnet set
Section titled “The mainnet set”| Role | Templates |
|---|---|
| Standalone | aiModelHeadToHead, binaryPrice, companyIpoConfirmed, priceTouch, scalarPrice, sportsContestWinner, sportsOverUnderMarket, sportsScalarMarket |
| Question | policyRateDecision, sportsContestResult, sportsTournamentWinner, each with its question outcome templates |
The three price templates take a perp keyword of type hlPerp:
| Template | Keywords | Semantics |
|---|---|---|
binaryPrice |
perp, priceDescription, seconds, threshold, time |
Yes if the seconds-second TWAP is above threshold at time; a delisted perp uses its delisting price |
priceTouch |
level named target |
can settle as soon as the price touches target, before time |
scalarPrice |
high, low, perp, priceDescription, seconds, time |
sides Long and Short; Long pays (price - low) / (high - low) clamped to 0 and 1, Short the rest, on the seconds-second TWAP ending at time; semanticRestriction requires the price of a Hyperliquid perp |
Settlement fractions are part of each template’s semantics:
| Fraction | Templates |
|---|---|
| draw or void may settle at 0.5 | aiModelHeadToHead, sportsContestWinner, sportsOverUnderMarket, sportsScalarMarket |
| exact fractions expected | scalarPrice, scalePrice, sportsScalarMarket |
Keyword types and value rules
Section titled “Keyword types and value rules”| Hint | Value |
|---|---|
dateTime |
UTC YYYYMMDD-HHMM, for example "20260712-1830"; in the future, within the next year |
date |
UTC YYYYMMDD, meaning end of day; in the future, within the next year |
string |
free text |
shortString |
free text of at most 10 characters |
hlPerp |
the name of an existing perp, "ABC" or a HIP-3 "dex:ABC" |
uInt |
non-negative integer that fits in a u64, no sign or leading zeros |
uDecimal |
non-negative decimal, no sign, exponent, or leading or trailing zeros |
Every value is at most 100 characters, with no {, } or pipe; : is allowed so HIP-3 coin names fit. Deployer tooling reads “within the next year” as at most 366 days.
What lands on chain
Section titled “What lands on chain”| Field | Derived as |
|---|---|
| Name | template:<template id>, for example template:binaryPrice; the prefix is reserved for template deployments; at most 100 characters |
| Description | the keyword pairs sorted by keyword, joined as key:value with pipes; at most 2000 characters |
| Side names | standalone: template: plus the template’s side names, for example template:Long; question outcomes: Yes and No |
| Question fallback | named template fallback, description other, sides Yes and No |
Outcomes inside a question carry only their own keywords; the event time and any resolution deadline live on the parent. Protocol recurring markets use underlying, targetPrice and expiry where binaryPrice uses perp, threshold and time.
The numbers
Section titled “The numbers”| Limit | Value |
|---|---|
| Keyword value length | 100 characters |
shortString |
10 characters |
| Dated keywords | future, at most 366 days ahead |
| Display name after substitution | 70 characters (standalone, question); 25 (question outcome) |
| Standalone side name | 10 characters |
| On-chain name | 100 characters |
| On-chain description | 2000 characters |
| Question outcomes per question | 100 |
| Deployer fee scale | 0 to 10, decimal string |
| Templates, 2026-09-14 | 18 mainnet, 60 testnet |
Sending an instance
Section titled “Sending an instance”The example above, as sent:
{ "type": "outcomeDeploy", "venue": "ab", "operation": { "registerStandaloneOutcomeFromTemplate": { "id": "binaryPrice", "keywordToValue": [ ["perp", "BTC"], ["priceDescription", "the BTC mark"], ["seconds", "60"], ["threshold", "100000"], ["time", "20261101-1200"] ], "deployerFeeScale": "1" } }}A question with its outcomes, in display order (the protocol adds the fallback):
{ "type": "outcomeDeploy", "venue": "ab", "operation": { "registerQuestionFromTemplate": { "questionTemplateInstance": { "id": "abc", "keywordToValue": [["expiry", "20261101-1830"]], "deployerFeeScale": "1" }, "namedOutcomeTemplateInstances": [ { "id": "abc-outcome", "keywordToValue": [["choice", "A"]] }, { "id": "abc-outcome", "keywordToValue": [["choice", "B"]] } ] } }}Rules that fail silently or late:
keywordToValueis pairs sorted by keyword. Signed as a JSON object, it encodes differently and recovers a stranger’s address.deployerFeeScalesits on the standalone or question instance; question outcomes inherit it, including those added byregisterAndAssociateNamedOutcomeFromTemplate.- Grammar is checked on submission. A
uDecimal"95.000"signs fine and is rejected (it must be"95"), still using a daily slot. Validate locally. - A new outcome in a live question credits each holder of the fallback’s Yes with equal new Yes, so “other” keeps its meaning.
Reading a template correctly
Section titled “Reading a template correctly”- TWAP templates are not settled by one print: a single mark at
timeis the wrong input forbinaryPriceandscalarPrice. scheduledStartis kickoff, not a deadline. Sports templates also carryresolutionDeadline; price templates onlytime. Misreading it makes every sports market look overdue at kickoff.- Docs examples are not live keywords. They use
underlying,targetandexpiry; livebinaryPriceusesperp,thresholdandtime,priceTouchusestarget. Read names fromoutcomeTemplates, and never hard-code an id across networks.
Once listed, you owe a settlement (settling outcomes). For how templates look to traders, see market shapes.