1. Overview
vLotto publishes public, machine‑readable status and results into the contentmultimap of the identity ledger.vlotto@. Third parties can:
- Present drawing information (phase status, drawing hash, parameters).
- Enumerate tickets deterministically from published parameters.
- Score tickets using the published drawing hash and rules.
- Verify authenticity of tickets via on‑chain signatures and hashes.
2. Prerequisites
- Access to a Verus node (local CLI) or a JSON‑RPC HTTPS endpoint.
- Network: VRSCTEST (testnet) or VRSC (mainnet). Adjust commands accordingly.
- Optional tools for examples:
curl,jq.
3. Getting the Ledger
3.0 VDXF Keys (Where to look)
vLotto uses VDXF keys to store structured data inside identities:
| Purpose | URI | VDXF ID | Where |
|---|---|---|---|
| Ledger Data | vlotto.ledger.data |
iFVPmjN213NmfaiBhAkxAJWWGtcDEoXJcU |
ledger.vlotto@ contentmultimap (latest entry) |
| Primary Ticket Finalized Data | vlotto.ticket.finalizeddata |
iMzWvy5j4ciiMSBsEEVzfy66awLQ85b4GN |
each ticket’s contentmultimap (latest entry) |
| Data Descriptor | data.type.object.datadescriptor |
i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv |
descriptor key nested inside entries to label object types |
objectdata.message.3.1 JSON‑RPC (remote)
{"jsonrpc":"1.0","id":"vlotto","method":"getidentity","params":["ledger.vlotto@"]}
Example with curl:
curl -sS -H 'content-type: text/plain' --data-binary '{"jsonrpc":"1.0","id":"vlotto","method":"getidentity","params":["ledger.vlotto@"]}' https://api.verustest.net | jq '.result.identity'
3.2 CLI (local node)
./verus -chain=VRSCTEST getidentity ledger.vlotto@
3.3 What to extract
The ledger stores a JSON message in the contentmultimap. Extract it from the latest entry:
jq -r '.contentmultimap | to_entries[] | .value[0] | to_entries[] | .value.objectdata.message'
The message contains (field names may appear in snake_case or legacy PascalCase):
| Path | Description |
|---|---|
.currentPhase | Human‑readable phase marker. |
.phaseStatus.* | Completion booleans and timestamps for phases. |
.drawingResults.drawingHash | Final 64‑hex drawing hash used for scoring. |
.drawingResults.topWinningTicket | Publisher’s top ticket info for convenience. |
.drawingParameters.* | Inputs used to derive ticket names and scoring rules (e.g., mainVerusID, drawingBlock, requiredMatches, rAddressForTickets). |
.ticketSummary.* | Planned/generated/registered counts for enumeration bounds. |
4. Enumerating Tickets
Tickets are named deterministically as: <drawingBlock>_<idx>of<planned>.<mainID-trimmed>@.
- drawingBlock: from
.drawingParameters.drawingBlock(fallback:.targetDrawingBlock). - planned: from
.ticketSummary.planned(fallback:.ticketSummary.registered). - mainID: from
.drawingParameters.mainVerusID(trim trailing@).
4.1 Fetching ticket content
Use getidentitycontent on each candidate ticket name. Query the latest content entry and extract the message object.
JSON‑RPC
{"jsonrpc":"1.0","id":"vlotto","method":"getidentitycontent","params":["<ticket_name>"]}
CLI
./verus -chain=VRSCTEST getidentitycontent <ticket_name>
From the message, read:
playing_number(orPlayingNumber): 64‑hex string.registration_txid(orRegistrationTxID).- Signatures and hashes:
ticket_validation.signed_by_ticket_signatureand..._hashproofguard_acknowledgement.signed_by_proofguard_signatureand..._hash
5. Determining Ticket “Sold” vs “Unsold”
Fetch the current identity state of the ticket:
./verus -chain=VRSCTEST getidentity <ticket_name>
A ticket is considered sold if its current primaryaddresses[0] is different from the published .drawingParameters.rAddressForTickets. Otherwise it is unsold (or graveyarded).
6. Scoring Rules
- Obtain
drawingHashfrom ledger message. - Ignore any leading zeros in the drawing hash when scoring.
- For each position after the first non‑zero nibble: if ticket nibble equals drawing nibble, increment matches and add the hex value to score.
Rank tickets by: matches desc, then score desc, then ticket index asc. Apply your winner policy (e.g., requires .drawingParameters.requiredMatches and sold=yes).
7. Verifying Authenticity
Given ticket name T, values sig1, hash1, sig2, hash2, and regtx from the ticket message:
| Check | RPC | Purpose |
|---|---|---|
| Ticket signed the registration txid | verifymessage(T, sig1, regtx) |
Confirms a ticket signature over its registration. |
| Ticket signed hash1 | verifyhash(T, sig1, hash1) |
Confirms ticket’s signature over its own content hash. |
| Proofguard signed sig1 | verifymessage(proofguard.<mainID>@, sig2, sig1) |
Confirms a second signer acknowledged the ticket signature. |
| Proofguard signed hash2 | verifyhash(proofguard.<mainID>@, sig2, hash2) |
Confirms second signer’s hash binding. |
| Optional consistency | playing_number == hash2 |
Additional integrity check used by vLotto’s public script. |
7.1 JSON‑RPC examples
{"jsonrpc":"1.0","id":"vlotto","method":"verifymessage","params":["<ticket_name>","<sig1>","<registration_txid>"]}
{"jsonrpc":"1.0","id":"vlotto","method":"verifyhash","params":["<ticket_name>","<sig1>","<hash1>"]}
{"jsonrpc":"1.0","id":"vlotto","method":"verifymessage","params":["proofguard.<mainID>@","<sig2>","<sig1>"]}
{"jsonrpc":"1.0","id":"vlotto","method":"verifyhash","params":["proofguard.<mainID>@","<sig2>","<hash2>"]}
8. Putting It All Together (Workflow)
- Fetch ledger from
ledger.vlotto@and parse message JSON. - Read parameters:
mainVerusID,drawingBlock,requiredMatches,rAddressForTickets,planned. - Enumerate tickets for
i = 1..planned→<drawingBlock>_<i>of<planned>.<main>@. - For each ticket:
- Fetch latest
getidentitycontentand parse the message. - Check current
getidentityto determine sold (primary address != rAddressForTickets). - Compute matches and score against
drawingHash(ignore hash leading zeros).
- Fetch latest
- Rank tickets by matches, score, index. Determine winner using your policy (usually: sold AND matches ≥ required).
- Verify authenticity for top candidates using the four checks in Section 7.
- Present results (phase status, parameters, top tickets, verification summary).
9. Remote vs Local Calls
All examples have a JSON‑RPC form suitable for remote APIs and a CLI form for local nodes.
| Action | JSON‑RPC | CLI (VRSCTEST) |
|---|---|---|
| Ledger | getidentity("ledger.vlotto@") | ./verus -chain=VRSCTEST getidentity ledger.vlotto@ |
| Ticket message | getidentitycontent("T") | ./verus -chain=VRSCTEST getidentitycontent T |
| Ticket state | getidentity("T") | ./verus -chain=VRSCTEST getidentity T |
| Verify 1 | verifymessage(T, sig1, regtx) | same via CLI |
| Verify 2 | verifyhash(T, sig1, hash1) | same via CLI |
| Verify 3 | verifymessage(proofguard.main@, sig2, sig1) | same via CLI |
| Verify 4 | verifyhash(proofguard.main@, sig2, hash2) | same via CLI |
10. Edge Cases & Tips
- Index lag: After updates, content or identity fields may lag a few seconds. Add short retries.
- Naming variance: If your first ticket name probe returns no content, try trimming trailing digits from the main ID base and retry.
- Field casing: Support both snake_case and PascalCase in message payloads for compatibility.
- Network: Use
./verusfor VRSC, or./verus -chain=VRSCTEST(or other networks) accordingly. - Sold detection: Compare current
primaryaddresses[0]withrAddressForTickets.
11. Minimal Scoring Pseudocode
// Inputs: ledgerMsg, api (rpc), network
main = trimAt(ledgerMsg.drawingParameters.mainVerusID)
N = ledgerMsg.ticketSummary.planned
block = ledgerMsg.drawingParameters.drawingBlock
draw = ledgerMsg.drawingResults.drawingHash
start = index of first non-zero in draw
for i in 1..N:
name = sprintf("%d_%dof%d.%s@", block, i, N, main)
msg = latestMessage(getidentitycontent(name))
if !msg: try fallback base (trim digits)
cur = getidentity(name)
sold = cur.primaryaddresses[0] != ledgerMsg.drawingParameters.rAddressForTickets
matches=0; score=0
for k from start..63:
if msg.playing_number[k] == draw[k]:
matches++
score += hex2int(draw[k])
record(matches, score, i, name, sold, msg)
rank by (matches desc, score desc, index asc)
verify top candidates via 4 checks
present results
12. Utilities & Basket
The ledger also publishes a utilities section summarizing utility IDs and basket composition. From the ledger message JSON:
.utilities.utilityIds: array of utility currency IDs to display..utilities.basketInfo: map of currency → balance (basket composition)..utilities.totalBasket: total value of the basket across currencies..utilities.basketHeight: block height at which basket values were computed.
Example (remote API):
# Fetch ledger
curl -sS -H 'content-type: text/plain' --data-binary '{"jsonrpc":"1.0","id":"vlotto","method":"getidentity","params":["ledger.vlotto@"]}' https://api.verustest.net \
| jq -r '.result.identity.contentmultimap | to_entries[] | .value[0] | to_entries[] | .value.objectdata.message' > ledger.json
jq '.utilities.utilityIds' ledger.json
jq '.utilities.basketInfo' ledger.json
jq '.utilities.totalBasket' ledger.json
jq '.utilities.basketHeight' ledger.json
To display current balances for a listed utility ID on your own node, use:
./verus -chain=VRSCTEST getcurrency <utility_id> ./verus -chain=VRSCTEST getaddressbalance <address_or_id>
.utilities.basketInfo or query per‑currency balances via the CLI.13. Graveyard Addresses (Unsold Ticket Reassignment)
After sales close and verification, vLotto does not revoke unsold tickets. Instead, it performs an updateidentity to reassign control of each unsold ticket to a designated graveyard R‑address. This preserves the ticket’s on‑chain record and its contentmultimap (chain‑of‑custody data) while removing it from the operator’s wallet.
| Network | Graveyard R‑Address |
|---|---|
| VRSCTEST (testnet) | RMzd5vMptsxxz1tWH2FeSdUgRSNgS4G52w |
| VRSC (mainnet) | RAXCjm9Z4RJWEmsNgo83B8JevTcJRt6Tj5 |
.utilities.graveyard.rAddress for display.13.1 Detecting Graveyarded Tickets
During scoring you classify a ticket as “sold” when its current primary address differs from .drawingParameters.rAddressForTickets. After cleanup, unsold tickets will have primary address = graveyard address.
# Current state of a ticket ./verus -chain=VRSCTEST getidentity <ticket_name> # Expectation after cleanup (unsold): # identity.primaryaddresses[0] == RMzd5vMptsxxz1tWH2FeSdUgRSNgS4G52w (testnet) # identity.primaryaddresses[0] == RAXCjm9Z4RJWEmsNgo83B8JevTcJRt6Tj5 (mainnet)
Third‑party UIs should reflect this by labeling such tickets as unsold/retired to graveyard. The contentmultimap remains intact and should still be parsed for chain‑of‑custody data.
13.2 Why Graveyard Instead of Revocation?
- Transparency: Preserves full history and data instead of erasing the identity state.
- Wallet hygiene: Tickets leave the operator’s spendable set.
- Determinism: Third parties can consistently identify retired tickets via a well‑known address.
14. License & Attribution
This document accompanies the vLotto project and is intended for public integration. Please retain attribution when redistributing.
15. Utility IDs – Roles and Expectations
vLotto organizes operational identities as Utility IDs. Third parties can display their presence, balances and basic status by resolving each sub‑ID under the main drawing ID (e.g., jackpot.<main>@). Below is a high‑level description of each utility and what you should expect to find on‑chain.
15.1 jackpot.<main>@
- Purpose: Holds the current jackpot balance for the current drawing and serves as the public pool tracked throughout the drawing run. The timelock functionality for this Utility ID has been postponed for a future release. Timelock is currently simulated during a drawing cycle.
- What to query:
getaddressbalance("<jackpot_address_or_id>")to show current jackpot funds by address/ID. - Reader hint: Display current jackpot balance and timelock status.
15.2 payout.<main>@
- Purpose: The payout staging identity. Funds used to purchase the winning ticket (buyback) are staged here before settlement. If a winning sold ticket is determined, the jackpot balance is moved to payout, and the buy back offer is made by payout. The intent is for payout to handle all buy back offers for winning tickets. Current default expiration of buy back offers is 10,000 blocks.
- What to query:
getidentity("payout.<main>@")for state; balances viagetaddressbalancewhen querying by address. - Reader hint: After a winner is selected, the presence of funds and payout operations will be reflected in Phase 9 in the ledger.
15.3 operations.<main>@
- Purpose: Operations identity is the allocation destination where funds to support the vlotto operation and staff are distributed to. Distribution to this identity is performed in phase 10 where a percentage of the cashier funds (from ticket) sales are are sent to the operations identity.
- What to query:
getidentity("operations.<main>@")and balances relevant to the configured currencies. - Reader hint: This address receives the operator’s share during Phase 10 distribution.
15.4 ledger.<main>@ (a.k.a. ledger.vlotto@)
- Purpose: Public bulletin of the drawing; publishes parameters, phase status, drawing results, and verification flags via
contentmultimap. The ledger is updated after each phase completes. - What to query:
getidentity("ledger.<main>@")→ extract the latestobjectdata.messagefromcontentmultimap. - Reader hint: Treat this as the source of truth for scoring inputs and phase progression.
Content Multimap Entries (message fields)
| Path | Description |
|---|---|
.currentPhase | Human‑readable marker of the most recently completed phase. |
.lastUpdated | UTC timestamp for the latest ledger write. |
.phaseStatus.phase1_initialization..phase10_distribution | Per‑phase completion booleans and timestamps. |
.drawingParameters | Immutable inputs used to derive tickets/scoring (mainVerusID, drawingBlock, ticketPrice, requiredMatches, rAddressForTickets, distribution percents, etc.). |
.ticketSummary | Planned/generated/registered counts and tallies for data updates, marketplace, sold/unsold (graveyarded), verified/fraudulent. |
.drawingResults.drawingHash | Final 64‑hex hash used for scoring (ignore leading zeros when scoring). |
.drawingResults.topWinningTicket | Display convenience for the highest scoring candidate or final winner. |
.drawingResults.verificationStatus | Status of verifying the top candidate/winner (e.g., completed). |
.drawingResults.topTicketMatches/.topTicketScore | Match count and score for the top ticket (for display). |
.drawingResults.winnerStatus | One of winner, no_winner, or pending. |
.securityMetrics | Aggregates from public validation (fraud checks, counts, rates). |
.timelockStatus | Timelock application indicators for the cycle (may be simulated depending on deployment). |
.utilities.utilityIds | Detected utility identity list (e.g., jackpot, payout, operations, ledger, proofguard, reserves, cashier). |
.utilities.basketInfo/.totalBasket/.basketHeight | Currency basket composition snapshot and the block height it was computed at (if main ID is a currency). |
.payoutSummary | Summaries of buyback offers and payout amounts after Phase 9 (if applicable). |
.distributionSummary | Phase 10 distribution totals and per‑destination amounts. |
.financialSummary | Running financial aggregates such as current/final jackpot, revenue totals, and distribution amounts. |
.operationalMetrics | Optional operational telemetry (phase processing times, retry counts) to help readers estimate performance. |
15.5 proofguard.<main>@
- Purpose: Second‑party attester for ticket authenticity. Signs the ticket’s signature and hash (see Section 7 verification). The proofguard identity remains in the possession of the vLotto system; its sole role is to provide signatures for ticket data.
- What to query: The identity itself (
getidentity("proofguard.<main>@")) and the ticket identity (getidentity("<ticket_name>")) to read the ticket’scontentmultimapand locateproofguard_acknowledgementfields. - Reader hint: Verification steps 3 and 4 use this ID to validate the second signature and hash.
15.6 reserves.<main>@
- Purpose: Optional reserve management identity for treasury/buffer accounting across runs. In order to control jackpot sizes, a jackpot ceiling parameter is defined. If the jackpot reaches that ceiling, and there are additional funds that were destined to go to the jackpot, those funds are diverted to reserves. Reserves funds are saved and used to fund the jackpot only whenever the jackpot size decreases below the jackpot ceiling.
- What to query:
getidentity("reserves.<main>@")and associated balances where applicable. - Reader hint: Display current balance. Currenct jackpot ceiling parameter is 1000 vlotto so reserves identity may have a zero balance for multiple drawing cycles until the jackpot grows beyond that amount.
15.7 cashier.<main>@
- Purpose: Revenue collection/settlement identity from ticket sales. Revenue collected from ticket sales is distrbuted in phase 10. Distribution is performed to 4 destinations. A percentage goes to the next jackpot regardless if there is a winner or not. If the jackpot ceiling is reached, the balance goes to reserves. A percentage goes to operations to fund the vlotto system and staff. There are 2 additional custom destinations that can be set by the operator with a custom percentage. Total percentage of distribution must equal 100%.
- What to query:
getidentity("cashier.<main>@")and balances viagetaddressbalanceaccording to the configured currency mix. - Reader hint: Useful for displaying current/final ticket sales before distribution in phase 10.
15.8 basket (currency)
- Purpose: The main ID is launched as a currency (the “basket”) that is 100% backed by Verus and may be used for treasury/accounting.
- What to query:
getcurrency("<main>")for currency state (supply, reserves). - Reader hint: Not a sub‑ID; treat it as a separate currency view that can be shown alongside utility IDs.
15.9 <main>@ (Main ID)
- Purpose: Root identity for the drawing system. It currently does not serve a Utility function. It anchors all Utility IDs (e.g.,
jackpot.<main>@,payout.<main>@) and is the identity used to launch the Basket currency. - What to query:
getidentity("<main>@")to view primary addresses, authorities, and general identity state. - Reader hint: Treat this as the namespace root and currency issuer; most operational data lives under the Utility IDs and the Basket currency.