@parity/product-sdk-individuality
npm install @parity/product-sdk-individualityExports
Classes
| Name | Summary |
|---|---|
AsPersonError | Building an origin-modifying transaction extension — AsPerson or its |
GameRegistrationError | A step of the registration that failed: stage says which, code what the |
GameSeatBindError | A bind that did not land. permanent closes the lite route for this account. |
IndividualityDecodeError | A raw storage value did not match the shape the descriptor promised — an |
ProductIndividualityError | Base class for errors raised by @parity/product-sdk-individuality. |
Functions
| Name | Summary |
|---|---|
airdropPhase() | — |
airdropVrfDomain() | domain_for_event: label bytes then the event id. Exported as the one part |
airdropVrfTranscript() | The transcript for one draw. |
bindGameSeat() | Bind the person’s lite alias to the game account: PeopleLite.set_alias_account, |
buildLiteAliasBindTx() | Build the unsigned V5 general extrinsic that binds a lite person’s alias to |
canClaimFullUsername() | Whether this account can still claim a bare name. |
claimPrizeTx() | Build the Game.claim_airdrop call, unsigned. Pays::No on success, so only a |
confirmClaim() | Did a submitted claim take effect? Re-reads the row rather than watching, so it |
contextSuffixBytes() | Expand a ContextSuffix to the 32 bytes the context hash consumes, |
creditHash() | The credit one attestation awards, as lowercase hex: |
decodeAbsenceGracePolicy() | Decode the grace policy from its strict 0x + four-hex-digit serialization. |
decodeConsumerInfo() | undefined in means the account has no record, which is an answer, not a failure. |
deriveClaimEligibility() | Decide whether one prize can be claimed. Never throws. |
derivePeopleAirdropsSlot() | The slot an alias’s entry in one draw is filed under: |
derivePersonhoodState() | Derive a person’s membership standing from one pinned snapshot. |
deriveSeat() | The seat, from the facts alone. Pure, so every product decides the route the |
displayUsername() | The host computes this same rule over the same record at session-pairing time |
fromPapi() | — |
gameAirdropEventId() | Mirrors Game::airdrop_event_id, a plain impl method, so only its base reaches |
gameAirdropEventIds() | Every draw id of one game, in airdrop-index order. airdropsScheduled only |
gameProductId() | The game product’s DotNS id on a network, such as "dim2.paseo": the id a |
gameTimeline() | A line-for-line mirror of the runtime’s GameTimes trait, including |
groupSeats() | All maxGroupSize seats of the group the player at playerIndex sits in, |
holdsLiteKey() | Whether this person can take the free route: the chain’s score context is one |
litePeopleRing() | The people-lite ring on the chain with genesis genesisHash. |
lookupUsername() | Read the usernames registered for an account, from Resources.Consumers. |
mintAccountAirdropVrfs() | — |
mintAliasAirdropVrfs() | One People-ring proof per scheduled draw, minted through the host. |
missesInWindow() | Misses the window currently holds: the games inside it that were absences. |
numberOfGroups() | The groups a roster of playerCount splits into, 0 when there is no roster. |
offboardTx() | Build Game.offboard, unsigned. |
parsePeopleAirdropsEventId() | The draw index inside a PeopleAirdrops event id, or null if it is not one. |
peopleAirdropsEventId() | Derive a PeopleAirdrops draw’s event id, mirroring |
peopleAirdropsRegisterCalls() | PeopleAirdrops.register calls for eventIds, split so no call exceeds the |
peopleRing() | The people ring on the chain with genesis genesisHash. The host resolves |
personhoodContext() | The personhood product’s context for name on the network issuing .<tld> |
productContext() | The 32-byte proof context of { productId, suffix }, mirroring |
readAirdropDraw() | A draw that is not in storage is not a failure, it is phase: "Gone" — the |
readClaimEligibility() | Check whether one prize can be claimed, from one pinned finalized block. The six |
readCommunicationIdentifier() | The key an account is reached on during the game, at one pinned finalized block. |
readCreditCandidates() | Every credit the attestee could earn in the running game, one per co-player per |
readCurrentGame() | No game running is not a failure, it is BetweenGames — the chain’s normal |
readDrawRegistration() | Whether an identity entered a draw, which readAirdropDraw cannot say: an |
readGameAirdropEventIds() | Every event id of one game’s draws, with the base read from the chain rather |
readGameSeat() | The player’s seat for the running game: the lite sign-up requirement and the |
readGameSignUpRequirement() | What this player may do about the running game, at one pinned block. Between |
readGroupMembers() | The members of one group in one round, at one pinned finalized block. |
readLiteSignUpRequirement() | What this account may do about the free lite sign-up, at one pinned block: |
readPeopleAirdropsSigning() | Reads People.AccountToAlias and the people ring’s current root, and says |
readPeopleAirdropsStanding() | Every PeopleAirdrops draw on chain and where account stands in each, read |
readPersonhoodState() | Read a person’s personhood state from one pinned finalized block. |
readPlayerIndices() | The index a player holds in each round, at one pinned finalized block. |
readPrizeStatus() | Not an authorization oracle. The chain re-checks eligibility on claim, and a |
readRegistrationEligibility() | Read Score.Participants and Score.PersonhoodThreshold at one pinned block |
readScoreContext() | Read Score.score_context and check it is the product derivation of |
readSignUpFunds() | The deposit, the free balance and the fee of a sign-up. |
readyToRegister() | Whether Score.register with a key would pass its guards now: the |
registerForGame() | Sign the player up for the running game: seat, bind, draws, sign. Fails with a |
registerMessage() | "pop register using" ++ account — the 50 bytes the full member key signs. |
registerPersonhoodTx() | Build Score.register(Some((member_key, proof_of_ownership))), unsigned. |
registrationRetryDelay() | For a product that retries a failed registration itself: nothing in this |
reportTx() | Build Game.report, unsigned. |
ringCollectionId() | A personhood ring’s collection identifier: the human-readable name, |
runScoreContextRead() | Throws; readScoreContext owns the Result boundary. Exported so a |
seatRequired() | What the deposit route needs up front: the deposit, plus the fee times |
signUpWithAccountTx() | Build Game.sign_up_with_account, unsigned. Pays::No on success, though a new |
signUpWithLiteInviteTx() | Build Game.sign_up_with_account_lite_invite, unsigned. Pays::No, no |
statusTag() | Validate a raw Status variant name. Exported so a read that only needs the |
toAirdropEvent() | — |
toCurrentGame() | Map the raw running game, selecting the deadline that belongs to its phase. |
toGamePhaseDurations() | Map the raw phase durations, from either source. |
toGameSchedulePreview() | Map one upcoming schedule, deriving its timeline from the given durations. |
toPersonhoodParticipant() | Map a raw PAPI participant to the domain shape the derivation consumes. |
toRawRegistrationEntry() | A domain registrant as the Winners key wants it. |
usernameBase() | The letters part of a lite username, which is what a claim would offer. |
watchCurrentGame() | Game.Game, which is null between games. |
watchParticipant() | Score.Participants, which is null for a player who has never been scored. |
watchPlayer() | Game.Players, which is null for a player who never signed up or was archived. |
withAsPerson() | Wrap a signer so its transactions run under a person origin. |
withLiteAlias() | Wrap a signer so its transactions run under a lite-person origin. |
withScoreParticipant() | Wrap a signer so its transactions run as the score participant, fee-free. |
Interfaces
| Name | Summary |
|---|---|
AbsenceGracePolicy | The absence-grace policy currently in force, decoded from |
AccountVrfSignature | One AirdropVrfs::Account entry, shaped as the host’s signVrf returns it. |
AirdropAssetId | The prize asset, as an XCM location. Opaque on purpose — this package does not |
AirdropChain | Structural, so a test double satisfies it. See IndividualityChain in read.ts |
AirdropDraw | One draw at one pinned block. event is null exactly when phase is "Gone", |
AirdropEvent | The counters are null where the Status variant does not carry them — **not |
AirdropPrize | The prize a draw pays out, from AirdropPrize on chain. |
AirdropVrfSigner | An sr25519 VRF over one draw’s transcript. |
AliasAirdropVrfs | The AirdropVrfs::Alias arm: one proof per draw, all at one ring revision. |
AliasDrawProofContext | The product-scoped context one draw’s proof is minted in, as the host’s |
BindGameSeatOptions | Options for bindGameSeat. |
BlockSnapshot | A block a read was pinned to. |
BlockSource | Where a pinned read gets its block: the part of PAPI’s PolkadotClient the |
BuildLiteAliasBindTxOptions | Options for buildLiteAliasBindTx. |
CapturedGame | A game identified by the caller rather than read from the chain. |
ClaimChain | The Game.claim_airdrop call, plus the Score.Participants read the check |
ClaimEligibility | Whether a specific prize can be claimed, and what stops it if not. |
ClaimEligibilityResult | The result of checking a claim against the chain. |
ClaimInputs | Everything the predicate needs, all from one pinned block. |
ClaimTarget | Everything a claim addresses. |
ClaimWindow | When a claim stops being possible. Two deadlines apply and only one is a clock — |
CommunicationIdentifierResult | — |
ConfirmClaimOptions | Options for confirmClaim. |
ConsumersChain | The chain surface this read needs, structural rather than a pinned descriptor. |
ConsumerUsernames | The usernames registered for one account, decoded. |
CreditCandidate | One credit the attestee could earn this game: a co-player of one round, and the hash. |
CreditCandidatesResult | — |
CurrentGame | The game that is running now. |
CurrentGameWatchChain | Structural, so a test double satisfies it. |
DrawOutcome | What a sign-up carried for the game’s prize draws. |
DrawRegistration | One draw’s registration for one identity. |
DrawWaitOptions | How long a sign-up waits for draws that are not open yet. |
EncodedCallSource | The one call-encoding method the builder needs; PAPI transactions have it. |
FeeEstimable | A built transaction whose fee can be estimated, as every PAPI 3 transaction can. |
GameAccount | The game account: dim2.<tld> at GAME_ACCOUNT_INDEX. |
GameChain | Structural, so a test double satisfies it. Separate from AirdropChain because a |
GamePhaseDurations | The phase durations in force, from Game.StoredPhaseDurations when governance |
GamePlayersChain | The registration entry, needed only when ReadCurrentGameOptions.players |
GameRegistrationCapabilities | Everything a host does for a sign-up; hostGameRegistrationCapabilities builds it. |
GameRegistrationReport | What one registerForGame call did, for telemetry; failures carry it too. |
GameScheduledAirdrop | One prize draw a schedule will set up, with its timing relative to play time. |
GameSchedulePreview | A game not created yet. The chain keeps Game.GameSchedules chronological — |
GameSeat | Seat, with what decided it and whether a sign-up can go out now. |
GameSignUpRequirement | What the chain will accept from this player, at one pinned block. Index and draw |
GameTimeline | A game’s phase boundaries, Unix seconds. Mirrors the runtime’s GameTimes |
GroupMember | One occupied seat, resolved to the player the chain keys it by. |
GroupMembersResult | — |
GroupSeat | One position of a group, with whether a player was shuffled into it. |
IndividualityChain | The chain surface this read needs — deliberately structural, not a pinned |
LegacySuffixChain | The network suffix before #20. Previewnet only, and gone on its next upgrade. |
LiteAliasBindChain | What building the bind leg needs from a chain: the call codec, the current |
LiteAliasBindTx | What buildLiteAliasBindTx returns. |
LiteSignUpChain | The lite sign-up call, plus the reads that decide whether it can dispatch. |
LiteSignUpRequirement | GameSignUpRequirement with the wider blocker union: what the chain |
LookupUsernameOptions | Options for lookupUsername. |
MintAccountAirdropVrfsOptions | Options for mintAccountAirdropVrfs. |
MintAliasAirdropVrfsOptions | Options for mintAliasAirdropVrfs. |
NetworkSuffixChain | The network suffix since individuality-community #20. Root can move it between |
PapiIndividualityChain | What fromPapi returns, with the typed API preserved. |
ParticipantWatchChain | — |
PeopleAirdropEntry | One PeopleAirdrops draw, and where this account’s alias stands in it. |
PeopleAirdropsAlias | — |
PeopleAirdropsChain | The chain surface the reads need — structural, so a typed PAPI api from |
PeopleAirdropsRegisterCall | — |
PeopleAirdropsRegisterChain | The chain surface peopleAirdropsRegisterCalls needs. |
PeopleAirdropsStanding | — |
PersonhoodInputs | Everything PersonhoodState is derived from, resolved for one account at |
PersonhoodMetrics | The numbers behind a resolved state, carried alongside it. |
PersonhoodParticipant | A participant’s game record, as read from Score.Participants and decoded. |
PersonhoodProver | The personhood product’s keys, as a host exposes them; other products need its context grant. |
PersonhoodRing | A personhood key, the ring it is a member of, and the product that holds it. |
PlayerIndicesResult | — |
PlayerRecord | A player record in Game.Players, present from the first sign-up until archival. |
PlayerWatchChain | — |
RawAccountAlias | AccountToAlias, narrowed to the contextual alias the read keys on. |
RawActiveEvent | The raw Airdrop.Events value, narrowed to what the domain reads. |
RawAirdropEventInfo | The raw EventInfo. Every timestamp is a u64 of Unix seconds. |
RawAirdropPrize | The raw AirdropPrize, narrowed to the fields the domain carries. |
RawAirdropStatus | The raw Status enum. The payload is loose on purpose: enumerating eight |
RawConsumerInfo | The raw Resources.Consumers value, narrowed to the fields we read. |
RawGameAirdrop | One raw GameAirdrop from a schedule. |
RawGameInfo | The raw Game.Game value, narrowed to the fields the domain carries. |
RawGameSchedule | One raw GameSchedule from the Game.GameSchedules list. |
RawGameState | The raw GameState enum. Only the player count is read from its payload. |
RawLiteAliasBinding | PeopleLite.AccountToAlias, the alias binding the signed leg dispatches on. |
RawLiteRingMembership | One Members.Members entry, narrowed to the discriminant. Only Included |
RawParticipant | The raw Score.Participants value, narrowed to the fields the domain reads. |
RawPeopleAccountAlias | People.AccountToAlias, as stored. |
RawPhaseDurations | The raw PhaseDurationValues, from storage or from the runtime constant. |
RawRecognition | The raw recognition enum as PAPI decodes it: |
RawStreak | The raw streak enum as PAPI decodes it: Enum<{ Attended: u32; Absent: u32 }>. |
RawSubmitChain | Where the bind’s finished, unsigned bytes go out: PAPI’s submitAndWatch. |
ReadAirdropDrawOptions | Options for readAirdropDraw. |
ReadClaimEligibilityOptions | Options for readClaimEligibility. |
ReadCommunicationIdentifierOptions | Options for readCommunicationIdentifier. |
ReadCreditCandidatesOptions | Options for readCreditCandidates. |
ReadCurrentGameOptions | Options for readCurrentGame. |
ReadGameAirdropEventIdsOptions | Options for readGameAirdropEventIds. |
ReadGameSeatOptions | Options for readGameSeat. |
ReadGameSignUpRequirementOptions | Options for readGameSignUpRequirement. |
ReadGroupMembersOptions | Options for readGroupMembers. |
ReadLiteSignUpRequirementOptions | Options for readLiteSignUpRequirement. |
ReadPeopleAirdropsOptions | — |
ReadPlayerIndicesOptions | Options for readPlayerIndices. |
ReadPrizeStatusOptions | Options for readPrizeStatus. |
ReadRegistrationEligibilityOptions | Options for readRegistrationEligibility. |
ReadScoreContextOptions | Options for readScoreContext. |
ReadSignUpFundsOptions | Options for readSignUpFunds. |
RegisterChain | The Score.register call, typed structurally so the package needs no |
RegisterForGameOptions | Options for registerForGame. |
RegisterPersonhoodOptions | Options for registerPersonhoodTx. |
RegistrationEligibility | A participant’s standing against the registration guards, at one pinned |
RegistrationEligibilityChain | The two reads readRegistrationEligibility folds. Matched by hand |
ReportChain | Structural, so a test double satisfies it. Matched by hand against the paseo |
ReportOptions | Options for reportTx. |
RingLocation | Where a ring lives: a chain, and a junction path addressing the ring on it. |
RingVRFProof | A ring VRF proof and the values the chain needs to verify it. |
RosterChain | Structural, so a test double satisfies it. Matched by hand against the paseo |
ScoreContextChain | The published context every score proof must be minted in. |
Seat | A route, and whether it can be pressed now. |
SeatFacts | What the chain and the host say about the player. |
SignUpChain | The sign-up call, plus the reads that decide what it may carry. Composed with |
SignUpFunds | The parts of what a sign-up costs, in the smallest unit of the native token. |
SignUpSubmitOptions | Options the flow hands the submit capability. |
SignUpTransaction | A built sign-up call, as PAPI 3 returns it: fee-estimable and submittable. |
SignUpWithAccountOptions | Options for signUpWithAccountTx. |
SignUpWithLiteInviteOptions | Options for signUpWithLiteInviteTx. |
TimestampChain | Timestamp.Now: the chain’s clock, which registration closes by. |
TxWatch | A transaction watch, as PAPI and tx both give one. The observer’s members are |
TxWatchEvent | One event of a transaction watch, in the fields this module reads. |
VrfTranscript | — |
VrfTranscriptItem | Merlin append_message(label, value), as the host’s signVrf takes it. |
WatchAt | Options every watch takes: only the best block, so a change shows before finality. |
WatchedBlock | The block a watched value was read at, which is a best block, not a finalized one. |
WatchedValue | A PAPI watchValue observable, narrowed to the one method a watch calls. |
WatchPlayerOptions | Options for watchPlayer and watchParticipant. |
Type Aliases
| Name | Summary |
|---|---|
AirdropOutcome | Whether a registrant won. Unchecked exists so “we did not ask” cannot be |
AirdropPhase | The phase a product renders. Gone is not a chain status but the row’s absence |
AirdropRegistrant | Which identity entered a draw. Not the player’s choice on the game path: the |
AirdropStatusTag | The chain’s own Status, kept alongside AirdropPhase because the |
AirdropVrfVariant | Which variant the chain demands of this player. Read it, never choose it. |
AliasAirdropProofSigner | A People-ring proof over message in context. |
AsPersonInfo | Which person origin the transaction should run under. |
BindGameSeatOutcome | What bindGameSeat did. |
BlockAt | The block a read addresses, as PAPI’s at does: "finalized", the default, |
ClaimBlocker | Why a prize cannot be claimed. Several can hold at once, so |
ClaimOutcome | Whether a submitted claim reached the chain, re-read rather than watched. A |
ContextSuffix | The RFC-0024 context-suffix selector: a plain index, or 32 raw bytes. The same |
CreateRingVRFProof | Produce a ring VRF proof over message. |
CreditCandidatesChain | RosterChain plus the game, which readCreditCandidates reads at the same block. |
CurrentGameResult | — |
DrawSkipKind | Why a sign-up went out without its draw entries. |
FinalizedBlockSource | — |
FinalizedSnapshot | The block a read pinned itself, which is the latest finalized one unless the caller passed at. |
GamePhase | The phase a game is in, named as the chain’s GameState variant. Their payloads |
GameRegistrationChain | What registerForGame reads and submits through; fromPapi gives one. |
GameRegistrationCode | A failure’s code: one of GameRegistrationOwnCode, or the chain’s own |
GameRegistrationOwnCode | The codes this package sets itself, beside the chain’s own error names. |
GameRegistrationStage | Where registerForGame is, for a product’s progress UI: a step, or the broadcast. |
GameRegistrationStep | A step of registerForGame. |
GameSeatBindChain | What bindGameSeat reads and submits through. |
GameSeatBindRefusal | Why a bind did not put the person’s binding on the game account. |
GameSeatChain | What readGameSeat reads. |
LiteAliasInfo | Which lite-person origin the transaction should run under. |
LiteSignUpBlocker | Why the free lite sign-up (Game.sign_up_with_account_lite_invite) cannot go |
PeopleAirdropsBinding | What People.AccountToAlias says about one account, against the airdrops context. |
PeopleAirdropsSigning | Which withAsPerson origin a PeopleAirdrops call can ride for this account now. |
PersonhoodContextName | — |
PersonhoodKey | Which personhood key a proof is made with. |
PersonhoodProofContext | A ring-VRF proof context, as a host’s createRingVRFProof takes it. |
PersonhoodResult | The outcome of a personhood read. |
PersonhoodState | A person’s membership standing, derived from one pinned snapshot. |
PlayerKey | — |
PlayerRegistration | Whether the players named in ReadCurrentGameOptions.players are in the |
PrizeStatus | The outcome of a prize-status read. |
PrizeStatusChain | Both halves of the chain surface, since this read spans Game and Airdrop. |
RawRegistrationEntry | The raw RegistrationEntry enum, the key Winners is addressed by. |
RawReportVote | A vote as the pallet Report enum takes it. |
ReadPersonhoodStateOptions | What to read, and how: a username or an account, and never both. |
RegisterForGameOutcome | How registerForGame ended, when it did not fail. Every variant carries its report. |
ReportVote | The judgement of one co-player, who either attended as a person or did not. |
ScoreContext | The chain’s score context, and whether a host can mint proofs in it. |
SeatPath | What a product shows: a route, or why none is open to this account. |
SeatRoute | The ways a sign-up can actually be submitted. |
SignUpBlocker | Why a sign-up, or the draw entry inside it, cannot go ahead. A list rather than |
SignUpFundsChain | What readSignUpFunds reads. Matched by hand against the paseo descriptors |
SignUpSubmitResult | How a sign-up submission ended, as the submit capability reports it. |
SubmitSignUp | Signs and submits the built sign-up. The host adapter wraps tx’s submitAndWatch. |
UsernameCredibility | A consumer’s standing as the resources pallet records it. |
WatchErrorHandler | — |
Variables
| Name | Summary |
|---|---|
AIRDROP_VRF_TRANSCRIPT_LABEL | VRF_TRANSCRIPT_LABEL, which is also the domain item’s prefix. |
DEFAULT_FEE_HEADROOM | The fee headroom the deposit route asks for, as a multiple of the estimate. |
FALLBACK_PEOPLE_AIRDROPS_REGISTER_BATCH | Used only when the runtime does not expose MaxRegisterBatch. |
GAME_ACCOUNT_INDEX | The derivation index of the game account: 0, the host’s default product |
GAME_AIRDROP_EVENT_ID_BASE | Game::airdrop_event_id_base() — 27 bytes, the ten trailing spaces included as |
GAME_PRODUCT_NAME | Game.product_name: the product the game pallet scopes its draws to. |
GAME_REGISTRATION_RETRY_MS | How long to wait before the next try, after failures failures in a row: |
MAX_GAME_AIRDROPS | Game’s MAX_GAME_AIRDROPS: a game schedules at most this many draws. |
PEOPLE_AIRDROPS_EVENT_ID_BASE | indiv_pallet_people_airdrops::EVENT_ID_BASE — 24 bytes, four trailing spaces |
PERSONHOOD_CONTEXT_INDEX | The context suffix indices the personhood product owns, mirroring |
PERSONHOOD_PRODUCT_NAME | personhood::PRODUCT_NAME — the DotNS name (TLD excluded) the personhood |
REGISTER_MESSAGE_PREFIX | The pallet’s domain prefix for the proof of ownership in Score.register. |
Classes
class AsPersonError
Building an origin-modifying transaction extension — AsPerson or its
lite-personhood peer PeopleLiteAuth — failed.
Raised when the chain does not declare the extension, declares a pipeline version this package cannot encode, or when a value does not survive a round trip through the chain’s own codec.
Unlike IndividualityDecodeError this one is thrown, not returned: it
happens inside a PAPI 3 TxCreator, where the only channel available is
the exception PAPI already surfaces on the transaction’s error path.
Never interpolate a proof, a context or an alias into the message. Those are pseudonymous identity, and an error string is the least controlled place they can end up. An extension identifier or a version number is fine.
Extends: ProductIndividualityError
Constructors
constructor
new AsPersonError(message: string, options?: ErrorOptions): AsPersonErrorclass GameRegistrationError
A step of the registration that failed: stage says which, code what the
chain or host answered, retryable whether running it again can help.
Extends: ProductIndividualityError
Constructors
constructor
new GameRegistrationError(stage: GameRegistrationStep, code: GameRegistrationCode, options: { cause?: unknown; detail?: string; landingUnknown?: boolean; message?: string; retryable: boolean }): GameRegistrationErrorProperties
code
GameRegistrationCodelandingUnknown
booleanThe sign-up’s watch lost track: it may still land.
report
GameRegistrationReportWhat the call did up to the failure. Set by registerForGame.
retryable
booleanFalse when trying again cannot help: a refusal, a closed registration, a bad call.
stage
GameRegistrationStepclass GameSeatBindError
A bind that did not land. permanent closes the lite route for this account.
Extends: GameRegistrationError
Constructors
constructor
new GameSeatBindError(refusal: GameSeatBindRefusal, code: GameRegistrationCode, account?: string, options: { cause?: unknown; detail?: string; landingUnknown?: boolean } = {}): GameSeatBindErrorParameters
account: For"pinned-elsewhere", the account the seat is pinned to.
Properties
account
stringFor "pinned-elsewhere", the account the seat is pinned to.
permanent
booleanTrue when trying again cannot change the answer. The opposite of retryable.
refusal
GameSeatBindRefusalclass IndividualityDecodeError
A raw storage value did not match the shape the descriptor promised — an
unknown streak or recognition variant, or a malformed grace ratio.
Messages must be fixed strings. Never interpolate a decoded value into one: the values here describe a person’s chain state, and an error message is the least controlled place they can end up. The variant that failed is identifiable from the message text alone.
Extends: ProductIndividualityError
Constructors
constructor
new IndividualityDecodeError(message: string, options?: ErrorOptions): IndividualityDecodeErrorclass ProductIndividualityError
Base class for errors raised by @parity/product-sdk-individuality.
Implements the cross-package SdkError marker so isSdkError(e) also
recognizes it.
Extends: Error
Implements: SdkError
Constructors
constructor
new ProductIndividualityError(message: string, options?: ErrorOptions): ProductIndividualityErrorProperties
isSdkError
trueDiscriminant present on all SDK errors.
source
"individuality"The package that raised the error, e.g. "host", "signer", "contracts".
Functions
airdropPhase()
airdropPhase(status: AirdropStatusTag): AirdropPhaseairdropVrfDomain()
domain_for_event: label bytes then the event id. Exported as the one part
worth checking against a chain-side value.
airdropVrfDomain(eventId: string | Uint8Array<ArrayBufferLike>): Uint8ArrayairdropVrfTranscript()
The transcript for one draw.
airdropVrfTranscript(options: { eventId: string | Uint8Array<ArrayBufferLike>; publicKey: Uint8Array }): VrfTranscriptThrows
- ProductIndividualityError on a malformed event id or a wrong-width key.
bindGameSeat()
Bind the person’s lite alias to the game account: PeopleLite.set_alias_account,
unsigned, carrying a proof from the personhood product’s lite key in
Score.score_context. Resolves once a best block holds it.
Reads before it builds, so a retry never binds twice:
- A current binding resolves
already-bound, asking for nothing. A stale one is bound again (registerForGameleaves that to the sign-up). - A bind that cannot succeed is refused before any proof is asked for.
- Otherwise it proves, checks the
Game.LiteInvitespin on the alias, and submits.
A chain answer of AliasAccountAlreadySet (another bind landed first) is
already-bound. Fails with GameSeatBindError; check permanent.
bindGameSeat(chain: GameSeatBindChain, capabilities: Pick<GameRegistrationCapabilities, "account" | "personhood">, options: BindGameSeatOptions): Promise<Result<BindGameSeatOutcome, ProductIndividualityError>>buildLiteAliasBindTx()
Build the unsigned V5 general extrinsic that binds a lite person’s alias to
account: PeopleLite.set_alias_account(account, valid_at_block) under
PeopleLiteAuth::AsLiteAliasWithProof, encoded entirely client-side — no
host createTransaction, no signer.
valid_at_block is the chain’s current best block; the chain accepts the
call for its setup tolerance window (~600 blocks) after that. The proof is
requested over the implication message this builder computes, and its
context travels inside the proof — whichever call mints it decides, which
for the lite ring must be the chain’s Score.score_context (see the module
doc for the read that checks this before any of this work is done).
buildLiteAliasBindTx(chain: LiteAliasBindChain, options: BuildLiteAliasBindTxOptions): Promise<LiteAliasBindTx>Returns
the finished extrinsic bytes and the proof’s ring coordinates.
Throws
- when the chain’s metadata declares a pipeline or a
PeopleLiteAuthfield list this package cannot encode (devnet predates the revision field), when a slot has no known general-transaction value, or when the proof request fails or resolves malformed. - when
accountis not a valid address, or the chain serves no readable metadata or a malformed genesis hash.
canClaimFullUsername()
Whether this account can still claim a bare name.
This is the chain’s own precondition, not an approximation of it: the claim
extrinsic rejects a record that already carries a full username. Exact because
the decoder throws on an empty name, so null means full_username.is_none().
canClaimFullUsername(record: ConsumerUsernames): booleanclaimPrizeTx()
Build the Game.claim_airdrop call, unsigned. Pays::No on success, so only a
rejected claim costs a fee.
claimPrizeTx(chain: ClaimChain<Tx>, options: { airdropIndex: number; beneficiary: string; gameIndex: number }): TxconfirmClaim()
Did a submitted claim take effect? Re-reads the row rather than watching, so it
answers after a reload. Absence means it landed — unless the draw has left
Claiming, where the lifecycle may have swept the row instead.
confirmClaim(chain: AirdropChain & ClaimChain<unknown>, options: ConfirmClaimOptions): Promise<Result<ClaimOutcome, ProductIndividualityError>>contextSuffixBytes()
Expand a ContextSuffix to the 32 bytes the context hash consumes,
mirroring ProductContextSuffix::bytes() in individuality/support.
contextSuffixBytes(suffix: DerivationIndex): Uint8ArrayThrows
- ProductIndividualityError on an index outside
u32, orRawbytes that are not exactly 32.
creditHash()
The credit one attestation awards, as lowercase hex:
blake2b-256("polkadot-pop-game" ++ game_index ++ round ++ attester ++ attestee).
game_index is a little-endian u32, round a u8, and each player a SCALE
AccountOrPerson. An account hashes as its raw bytes, so its SS58 prefix does not
matter.
creditHash(options: { attestee: PlayerKey; attester: PlayerKey; gameIndex: number; round: number }): stringThrows
- ProductIndividualityError when a number is out of range or a player does not encode.
decodeAbsenceGracePolicy()
Decode the grace policy from its strict 0x + four-hex-digit serialization.
Any other encoding — missing prefix, wrong length, non-hex digit — throws.
The value is validated rather than trusted because a SizedHex<2> arriving
malformed means the descriptor and the chain disagree.
decodeAbsenceGracePolicy(value: string): AbsenceGracePolicydecodeConsumerInfo()
undefined in means the account has no record, which is an answer, not a failure.
decodeConsumerInfo(value: RawConsumerInfo | undefined): ConsumerUsernames | nullderiveClaimEligibility()
Decide whether one prize can be claimed. Never throws.
deriveClaimEligibility(inputs: ClaimInputs): ClaimEligibilityderivePeopleAirdropsSlot()
The slot an alias’s entry in one draw is filed under:
blake2_256("pop:people-airdrops:slot" ‖ event_id ‖ salt ‖ alias), a raw
concatenation of the 24-byte domain and three 32-byte values.
derivePeopleAirdropsSlot(eventId: string, salt: string, alias: string): stringderivePersonhoodState()
Derive a person’s membership standing from one pinned snapshot.
Never throws: an inconsistent record degrades to Suspended rather than
failing the caller’s render.
derivePersonhoodState(snapshot: PersonhoodInputs): PersonhoodStatederiveSeat()
The seat, from the facts alone. Pure, so every product decides the route the same way, and a renamed blocker is a compile error in one place.
deriveSeat(facts: SeatFacts): SeatdisplayUsername()
The host computes this same rule over the same record at session-pairing time
and exposes the answer as account.getUserId().primaryUsername. For the
signed-in user the two should agree; if they do not, the session snapshot is
older than the chain.
displayUsername(record: ConsumerUsernames): stringfromPapi()
fromPapi(client: Client, api: Api): PapiIndividualityChain<Api, Client>gameAirdropEventId()
Mirrors Game::airdrop_event_id, a plain impl method, so only its base reaches
metadata and the pinned vectors below keep this honest.
gameAirdropEventId(options: { airdropIndex: number; base: string | Uint8Array<ArrayBufferLike>; gameIndex: number }): stringThrows
- ProductIndividualityError on a malformed base, or an index wider than its
chain type (
u32game,u8airdrop).
gameAirdropEventIds()
Every draw id of one game, in airdrop-index order. airdropsScheduled only
exists while that game is current, so a past game’s count must have been
captured — probing cannot tell a cleaned-up draw from one never scheduled.
gameAirdropEventIds(options: { airdropsScheduled: number; base: string | Uint8Array<ArrayBufferLike>; gameIndex: number }): string[]gameProductId()
The game product’s DotNS id on a network, such as "dim2.paseo": the id a
host derives the game account from, and the product a draw proof’s context
names. Lower case, because the chain hashes the raw string.
gameProductId(tld: string): stringThrows
- ProductIndividualityError when
tldis empty or has a dot inside.
gameTimeline()
A line-for-line mirror of the runtime’s GameTimes trait, including
saturating_sub clamping at zero — reachable for a play time earlier than the
phases before it.
registrationStarts = play - shuffle - postShuffleMargin - registration
registrationEnds = play - shuffle - postShuffleMargin
shuffleDeadline = play - postShuffleMargin
reportingEnds = play + reporting
playerProcessEnds = play + reporting + playerProcessOnly correct for a game that does not exist yet — a created game stores its own.
gameTimeline(gamePlayTime: number, durations: GamePhaseDurations): GameTimelinegroupSeats()
All maxGroupSize seats of the group the player at playerIndex sits in,
ascending by index.
A seat whose index reaches past playerCount is unoccupied. Filtering those out
leaves the member list the pallet itself computes.
groupSeats(playerIndex: number, playerCount: number, maxGroupSize: number): GroupSeat[]holdsLiteKey()
Whether this person can take the free route: the chain’s score context is one a host mints in, and the host holds their lite key.
holdsLiteKey(chain: ScoreContextChain & Pick<LiteAliasBindChain<EncodedCallSource>, "raw">, capabilities: Pick<GameRegistrationCapabilities, "personhood">, options: { signal?: AbortSignal; tld: string }): Promise<Result<boolean, ProductIndividualityError>>litePeopleRing()
The people-lite ring on the chain with genesis genesisHash.
litePeopleRing(genesisHash: `0x${string}`): RingLocationlookupUsername()
Read the usernames registered for an account, from Resources.Consumers.
Returns a Result, per the SDK-wide error model: ok carries the answer,
err carries a ProductIndividualityError. An account with no consumer
record is not a failure. It resolves to ok(null), because the chain was
asked and answered.
The account is the input the SDK already hands callers: rootAddress from a
paired session keys this map.
Not an authorization oracle. This is a client-side read in a client-side library, and a backend that trusts “the SDK said this name is theirs” is trivially spoofed.
lookupUsername(chain: ConsumersChain, options: LookupUsernameOptions): Promise<Result<ConsumerUsernames | null, ProductIndividualityError>>mintAccountAirdropVrfs()
mintAccountAirdropVrfs(signer: AirdropVrfSigner, options: MintAccountAirdropVrfsOptions): Promise<Result<AccountVrfSignature[], ProductIndividualityError>>mintAliasAirdropVrfs()
One People-ring proof per scheduled draw, minted through the host.
Sequential, not parallel: each is a user-visible signing operation on a host that prompts, and firing sixteen at once is hidden by an allowance until a product ships without one.
Two things are checked locally because the chain’s own failure rejects the whole sign-up with the deposit taken and nothing to inspect:
- The context. The host decides it from
productIdand the suffix, and the proof carries it back. It must equal the context the chain derives for the event (product/<productId>/<event_id>, computed offline here), or the product id is misspelt, or the host hashed something else. - The ring coordinates.
AirdropVrfs::Aliascarries onering_indexand onerevisionfor every proof, so a ring revision moving between two draws’ proofs makes the set unusable. Mint again.
No retry on a rejected proof request: every refusal a host gives (no grant for the People key, a declined prompt, a key not in the ring) holds for the rest of this sign-up, so the caller should sign up without the draws rather than ask again.
mintAliasAirdropVrfs(signer: AliasAirdropProofSigner, options: MintAliasAirdropVrfsOptions): Promise<Result<AliasAirdropVrfs, ProductIndividualityError>>Throws
- nothing; every failure is on the
errchannel, with the host’s rejection as the cause.
missesInWindow()
Misses the window currently holds: the games inside it that were absences.
Mirrors the runtime’s misses_in_window(window) on the history exactly as
stored. The window is clamped to the one-byte history width, so a wider
policy counts eight games and no more.
missesInWindow(history: number, window: number): numbernumberOfGroups()
The groups a roster of playerCount splits into, 0 when there is no roster.
numberOfGroups(playerCount: number, maxGroupSize: number): numberoffboardTx()
Build Game.offboard, unsigned.
Only valid between games, or during registration for a player who has not signed
up for that game. Offboarding a Recognized player suspends their personhood for
good: playing as a person again takes a new personal id with a new key.
offboardTx(chain: ReportChain<Tx>): TxparsePeopleAirdropsEventId()
The draw index inside a PeopleAirdrops event id, or null if it is not one.
Airdrop.Events holds both schedulers, so a foreign id is data, not a caller bug.
parsePeopleAirdropsEventId(eventId: string): bigint | nullpeopleAirdropsEventId()
Derive a PeopleAirdrops draw’s event id, mirroring
PeopleAirdrops::draw_event_id. The u64 index takes a bigint or a
safe-integer number: anything above MAX_SAFE_INTEGER would round before
reaching the encoder and address a draw nobody scheduled, so it throws.
peopleAirdropsEventId(drawIndex: number | bigint): stringpeopleAirdropsRegisterCalls()
PeopleAirdrops.register calls for eventIds, split so no call exceeds the
runtime’s MaxRegisterBatch. Sign each under the origin
readPeopleAirdropsSigning reports. Duplicate ids are dropped; an empty
list yields no calls, since the pallet refuses an empty registration.
peopleAirdropsRegisterCalls(chain: PeopleAirdropsRegisterChain<Tx>, eventIds: readonly string[]): Promise<Result<PeopleAirdropsRegisterCall<Tx>[], ProductIndividualityError>>peopleRing()
The people ring on the chain with genesis genesisHash. The host resolves
the Members pallet by name, so no PalletInstance junction is needed.
peopleRing(genesisHash: `0x${string}`): RingLocationpersonhoodContext()
The personhood product’s context for name on the network issuing .<tld>
names: productContext("peopl.<tld>", Index(PERSONHOOD_CONTEXT_INDEX[name])).
The TLD belongs to the network ("paseo" on the paseo networks, "test" on
previewnet until truapi 0.13.0 renames it to "testnet"), so the same context
name on two networks is two different values, which is why it is a parameter
and never a default.
personhoodContext(tld: string, name: "score" | "resources" | "peopleLiteAuth" | "dotnsGateway" | "peopleAirdrops"): Uint8ArrayParameters
tld: a single lower-case DotNS label, without the leading dot.
Throws
- ProductIndividualityError on a tld the runtime cannot represent, or a
composite one:
"peopl" + ".te.st"and"peopl.te" + ".st"would collide.
productContext()
The 32-byte proof context of { productId, suffix }, mirroring
indiv_support::context::build_product_context.
This is the value that must equal contextualAlias.context in every
createAccountProof / getAccountAlias response for that product account,
and the value of the on-chain context constants (Score.score_context and
friends) on a runtime that derives them the product way.
productContext(productId: string, suffix: DerivationIndex): Uint8ArrayParameters
productId: the full DotNS id, TLD included ("dim2.dot","peopl.test"). Never assemble it from a hardcoded TLD: the network decides the TLD, so take it from configuration or from the chain.
Throws
- ProductIndividualityError via
contextSuffixBytes.
readAirdropDraw()
A draw that is not in storage is not a failure, it is phase: "Gone" — the
steady state for every past draw. Not evidence the draw existed either: an id
that was never scheduled answers identically.
readAirdropDraw(chain: AirdropChain, options: ReadAirdropDrawOptions): Promise<Result<AirdropDraw, ProductIndividualityError>>readClaimEligibility()
Check whether one prize can be claimed, from one pinned finalized block. The six gates span the draw, the score record and the asset list, so reading them apart is exactly the inconsistency pinning prevents.
readClaimEligibility(chain: AirdropChain & ClaimChain<unknown>, options: ReadClaimEligibilityOptions): Promise<Result<ClaimEligibilityResult, ProductIndividualityError>>readCommunicationIdentifier()
The key an account is reached on during the game, at one pinned finalized block.
readCommunicationIdentifier(chain: RosterChain, options: ReadCommunicationIdentifierOptions): Promise<Result<CommunicationIdentifierResult, ProductIndividualityError>>readCreditCandidates()
Every credit the attestee could earn in the running game, one per co-player per round, with the game and the roster read at one pinned finalized block.
Deriving is what names the attester behind each credit, and it is the only way to
see the credits that have not been awarded yet. Match the hashes against the claims
@parity/product-sdk-nfts reads to tell the two apart. The roster is drained when
the game ends, so cache the result if it has to outlive the game.
readCreditCandidates(chain: CreditCandidatesChain, options: ReadCreditCandidatesOptions): Promise<Result<CreditCandidatesResult, ProductIndividualityError>>readCurrentGame()
No game running is not a failure, it is BetweenGames — the chain’s normal
state, since one game exists at a time and each is killed when it ends.
This function has multiple overloads.
Overload 1
readCurrentGame(chain: GameChain & GamePlayersChain, options: ReadCurrentGameOptions & { players: readonly AirdropRegistrant[] }): Promise<Result<CurrentGameResult, ProductIndividualityError>>No game running is not a failure, it is BetweenGames — the chain’s normal
state, since one game exists at a time and each is killed when it ends.
Overload 2
readCurrentGame(chain: GameChain, options?: Omit<ReadCurrentGameOptions, "players">): Promise<Result<CurrentGameResult, ProductIndividualityError>>No game running is not a failure, it is BetweenGames — the chain’s normal
state, since one game exists at a time and each is killed when it ends.
readDrawRegistration()
Whether an identity entered a draw, which readAirdropDraw cannot say: an
absent Winners entry before the draw means “not drawn yet”, not “did not enter”.
A prefix scan, hence a separate call — the cost grows with the participant
count, so this is for “you are in tonight’s draw”, not for every status poll. The
personhood path could point-read it, but is gated on the PeopleAirdrops blockers.
readDrawRegistration(chain: AirdropChain, options: { eventId: string; registrant: AirdropRegistrant; signal?: AbortSignal }): Promise<Result<DrawRegistration, ProductIndividualityError>>readGameAirdropEventIds()
Every event id of one game’s draws, with the base read from the chain rather than assumed. That is the point of it: a hardcoded copy would go on deriving ids for draws that do not exist if the base ever moved.
readGameAirdropEventIds(chain: AirdropChain, options: ReadGameAirdropEventIdsOptions): Promise<Result<string[], ProductIndividualityError>>readGameSeat()
The player’s seat for the running game: the lite sign-up requirement and the
sign-up funds, read at at, folded by deriveSeat. Registration is
judged by the chain’s clock (see chainNow).
readGameSeat(chain: GameSeatChain, options: ReadGameSeatOptions): Promise<Result<GameSeat, ProductIndividualityError>>readGameSignUpRequirement()
What this player may do about the running game, at one pinned block. Between
games is not a failure, it is a NoGameRunning blocker on the success channel.
readGameSignUpRequirement(chain: GameChain & SignUpChain<unknown>, options: ReadGameSignUpRequirementOptions): Promise<Result<GameSignUpRequirement, ProductIndividualityError>>readGroupMembers()
The members of one group in one round, at one pinned finalized block.
An occupied seat with no player behind it means the counts and the indices come
from different shuffles, or the indices are already being drained, and arrives on
the err channel.
readGroupMembers(chain: RosterChain, options: ReadGroupMembersOptions): Promise<Result<GroupMembersResult, ProductIndividualityError>>readLiteSignUpRequirement()
What this account may do about the free lite sign-up, at one pinned block: the account sign-up read plus the lite gates, with the blockers merged.
canSignUp answers for sign_up_with_account_lite_invite specifically —
every lite blocker stops the sign-up itself, so it is the account read’s
answer AND’ed with “no lite blocker”. The draw-entry split (canEnterDraws,
the draw-only blockers) carries over from readGameSignUpRequirement
unchanged: the draws ride on the sign-up here exactly as they do there.
An AliasNotBound answer is not a dead end — it says the bind leg
(PeopleLite.set_alias_account under withLiteAlias(AliasWithProof)) has
not run yet. AnotherAccountInvited and AccountIsALitePerson are dead ends
for this account; AliasBoundElsewhere is recoverable, but only through
a call this package cannot make. signup-types.ts has the detail per arm.
Game.LiteInvites is consulted only when a binding in the score context
exists: the invite pin is keyed by the alias, and without the binding the
alias is unknown here.
This function has multiple overloads.
Overload 1
readLiteSignUpRequirement(chain: GameChain & SignUpChain<unknown> & ScoreContextChain & NetworkSuffixChain & LiteSignUpChain<unknown>, options: ReadLiteSignUpRequirementOptions): Promise<Result<LiteSignUpRequirement, ProductIndividualityError>>What this account may do about the free lite sign-up, at one pinned block: the account sign-up read plus the lite gates, with the blockers merged.
canSignUp answers for sign_up_with_account_lite_invite specifically —
every lite blocker stops the sign-up itself, so it is the account read’s
answer AND’ed with “no lite blocker”. The draw-entry split (canEnterDraws,
the draw-only blockers) carries over from readGameSignUpRequirement
unchanged: the draws ride on the sign-up here exactly as they do there.
An AliasNotBound answer is not a dead end — it says the bind leg
(PeopleLite.set_alias_account under withLiteAlias(AliasWithProof)) has
not run yet. AnotherAccountInvited and AccountIsALitePerson are dead ends
for this account; AliasBoundElsewhere is recoverable, but only through
a call this package cannot make. signup-types.ts has the detail per arm.
Game.LiteInvites is consulted only when a binding in the score context
exists: the invite pin is keyed by the alias, and without the binding the
alias is unknown here.
Overload 2
readLiteSignUpRequirement(chain: GameChain & SignUpChain<unknown> & ScoreContextChain & LegacySuffixChain & LiteSignUpChain<unknown>, options: ReadLiteSignUpRequirementOptions): Promise<Result<LiteSignUpRequirement, ProductIndividualityError>>What this account may do about the free lite sign-up, at one pinned block: the account sign-up read plus the lite gates, with the blockers merged.
canSignUp answers for sign_up_with_account_lite_invite specifically —
every lite blocker stops the sign-up itself, so it is the account read’s
answer AND’ed with “no lite blocker”. The draw-entry split (canEnterDraws,
the draw-only blockers) carries over from readGameSignUpRequirement
unchanged: the draws ride on the sign-up here exactly as they do there.
An AliasNotBound answer is not a dead end — it says the bind leg
(PeopleLite.set_alias_account under withLiteAlias(AliasWithProof)) has
not run yet. AnotherAccountInvited and AccountIsALitePerson are dead ends
for this account; AliasBoundElsewhere is recoverable, but only through
a call this package cannot make. signup-types.ts has the detail per arm.
Game.LiteInvites is consulted only when a binding in the score context
exists: the invite pin is keyed by the alias, and without the binding the
alias is unknown here.
Overload 3
readLiteSignUpRequirement(chain: GameChain & SignUpChain<unknown> & ScoreContextChain & LiteSignUpChain<unknown>, options: ReadLiteSignUpRequirementOptions & { tld: string }): Promise<Result<LiteSignUpRequirement, ProductIndividualityError>>What this account may do about the free lite sign-up, at one pinned block: the account sign-up read plus the lite gates, with the blockers merged.
canSignUp answers for sign_up_with_account_lite_invite specifically —
every lite blocker stops the sign-up itself, so it is the account read’s
answer AND’ed with “no lite blocker”. The draw-entry split (canEnterDraws,
the draw-only blockers) carries over from readGameSignUpRequirement
unchanged: the draws ride on the sign-up here exactly as they do there.
An AliasNotBound answer is not a dead end — it says the bind leg
(PeopleLite.set_alias_account under withLiteAlias(AliasWithProof)) has
not run yet. AnotherAccountInvited and AccountIsALitePerson are dead ends
for this account; AliasBoundElsewhere is recoverable, but only through
a call this package cannot make. signup-types.ts has the detail per arm.
Game.LiteInvites is consulted only when a binding in the score context
exists: the invite pin is keyed by the alias, and without the binding the
alias is unknown here.
readPeopleAirdropsSigning()
Reads People.AccountToAlias and the people ring’s current root, and says
which origin a registration needs. Pure reads: this never signs or proves.
readPeopleAirdropsSigning(chain: PeopleAirdropsChain, options: ReadPeopleAirdropsOptions): Promise<Result<PeopleAirdropsSigning, ProductIndividualityError>>readPeopleAirdropsStanding()
Every PeopleAirdrops draw on chain and where account stands in each, read
at one block. Airdrop.Events also holds other schedulers’ draws (the weekly
game’s); those are skipped by event id.
readPeopleAirdropsStanding(chain: PeopleAirdropsChain, options: ReadPeopleAirdropsOptions): Promise<Result<PeopleAirdropsStanding, ProductIndividualityError>>readPersonhoodState()
Read a person’s personhood state from one pinned finalized block.
Takes a DotNS username or an account address. Every resolved answer carries
both the derived state and the PersonhoodMetrics it came from, so a
caller rendering progress does not have to switch on the state to find a
score.
Returns a Result, per the SDK-wide error model: ok carries the answer,
err carries a ProductIndividualityError. Everything that can go
wrong arrives on the err channel, not only decode failures. That includes an
unreachable node, an aborted signal, and the pinned block leaving the
follower’s window mid-read, each normalized into the package’s error type with
the original cause attached.
A username nobody owns is not a failure. It resolves to
ok({ tag: "UsernameUnowned", ... }), because the chain was asked and
answered. An account input never lands there: nothing was looked up, so
an account with no records resolves to NotEnrolled instead.
Not an authorization oracle. This is a client-side read in a client-side
library, and a backend that trusts “the SDK said Member” is trivially
spoofed.
readPersonhoodState(chain: IndividualityChain, options: ReadPersonhoodStateOptions): Promise<Result<PersonhoodResult, ProductIndividualityError>>readPlayerIndices()
The index a player holds in each round, at one pinned finalized block.
readPlayerIndices(chain: RosterChain, options: ReadPlayerIndicesOptions): Promise<Result<PlayerIndicesResult, ProductIndividualityError>>readPrizeStatus()
Not an authorization oracle. The chain re-checks eligibility on claim, and a
backend trusting a Won here is trivially spoofed.
Game.airdrop_event_id_base escapes the pinned block — PAPI serves constants from
the client’s runtime — so it can only disagree across an upgrade mid-read.
readPrizeStatus(chain: PrizeStatusChain, options: ReadPrizeStatusOptions = {}): Promise<Result<PrizeStatus, ProductIndividualityError>>readRegistrationEligibility()
Read Score.Participants and Score.PersonhoodThreshold at one pinned block
and fold them into RegistrationEligibility.
Not an authorization oracle. The chain re-checks every guard at dispatch, and the threshold can move between this read and the transaction landing.
readRegistrationEligibility(chain: RegistrationEligibilityChain, options: ReadRegistrationEligibilityOptions): Promise<Result<RegistrationEligibility, ProductIndividualityError>>readScoreContext()
Read Score.score_context and check it is the product derivation of
peopl.<tld>/Index(0) — the only kind of context a stock host can mint.
A chain’s suffix source is fixed by its type, so one with none is a compile error rather than a runtime disappointment.
const score = await readScoreContext(chain, { tld: "paseo" });
if (score.ok && score.value.tag === "ProductDerived") {
// mint proofs in { productId: score.value.productId, suffix: Index(0) }
}This function has multiple overloads.
Overload 1
readScoreContext(chain: ScoreContextChain & NetworkSuffixChain, options?: ReadScoreContextOptions): Promise<Result<ScoreContext, ProductIndividualityError>>Read Score.score_context and check it is the product derivation of
peopl.<tld>/Index(0) — the only kind of context a stock host can mint.
A chain’s suffix source is fixed by its type, so one with none is a compile error rather than a runtime disappointment.
const score = await readScoreContext(chain, { tld: "paseo" });
if (score.ok && score.value.tag === "ProductDerived") {
// mint proofs in { productId: score.value.productId, suffix: Index(0) }
}Overload 2
readScoreContext(chain: ScoreContextChain & LegacySuffixChain, options?: ReadScoreContextOptions): Promise<Result<ScoreContext, ProductIndividualityError>>Read Score.score_context and check it is the product derivation of
peopl.<tld>/Index(0) — the only kind of context a stock host can mint.
A chain’s suffix source is fixed by its type, so one with none is a compile error rather than a runtime disappointment.
const score = await readScoreContext(chain, { tld: "paseo" });
if (score.ok && score.value.tag === "ProductDerived") {
// mint proofs in { productId: score.value.productId, suffix: Index(0) }
}Overload 3
readScoreContext(chain: ScoreContextChain, options: ReadScoreContextOptions & { tld: string }): Promise<Result<ScoreContext, ProductIndividualityError>>Read Score.score_context and check it is the product derivation of
peopl.<tld>/Index(0) — the only kind of context a stock host can mint.
A chain’s suffix source is fixed by its type, so one with none is a compile error rather than a runtime disappointment.
const score = await readScoreContext(chain, { tld: "paseo" });
if (score.ok && score.value.tag === "ProductDerived") {
// mint proofs in { productId: score.value.productId, suffix: Index(0) }
}readSignUpFunds()
The deposit, the free balance and the fee of a sign-up.
The deposit and the balance come from one pinned finalized block, the fee from
wherever PAPI estimates it, see SignUpFunds.estimatedFee.
readSignUpFunds(chain: SignUpFundsChain, options: ReadSignUpFundsOptions): Promise<Result<SignUpFunds, ProductIndividualityError>>readyToRegister()
Whether Score.register with a key would pass its guards now: the
participant exists, is NotRecognized, and has the score or the sticky
reached_personhood flag.
Suspended participants are not ready in this sense — they resume with
register(None), a different call shape this package does not build — and
neither are already-recognized ones.
Exported separately from the read, so it can run against a participant the caller already holds.
readyToRegister(participant: PersonhoodParticipant | null, personhoodThreshold: number): booleanregisterForGame()
Sign the player up for the running game: seat, bind, draws, sign. Fails with a
GameRegistrationError naming the step, the code and whether a retry
can help; losing a race to another product is already-registered.
registerForGame(chain: GameRegistrationChain, capabilities: GameRegistrationCapabilities, options: RegisterForGameOptions): Promise<Result<RegisterForGameOutcome, ProductIndividualityError>>registerMessage()
"pop register using" ++ account — the 50 bytes the full member key signs.
The pallet builds the same bytes with
account.using_encoded(|b| [PREFIX, b].concat()), and AccountId32 encodes
as its bare 32 bytes, so this is a raw concatenation with no SCALE framing.
registerMessage(account: Uint8Array<ArrayBufferLike> | SS58String): Uint8ArrayParameters
account: the registering account (the transaction signer), as an SS58 address or its raw 32-byte public key.
Throws
- ProductIndividualityError when the account does not decode or is not 32 bytes.
registerPersonhoodTx()
Build Score.register(Some((member_key, proof_of_ownership))), unsigned.
Pays::No on success. Submission stays with @parity/product-sdk-tx, and
the fee-free origin with import("./as-score-participant-signer.js").withScoreParticipant.
Preconditions on chain, or the dispatch fails: Score.Participants has the
signer with reached_personhood || score >= PersonhoodThreshold and
recognition == NotRecognized — check with readRegistrationEligibility.
InvalidProofOfOwnership means the message or key is wrong; KeyAlreadyInUse
that this member key already is a person.
registerPersonhoodTx(chain: RegisterChain<Tx>, options: RegisterPersonhoodOptions): TxThrows
- ProductIndividualityError on a wrong-width key or signature. Checked here because the chain’s own failure rejects the call with nothing to inspect, after the fee-free allowance was already spent on it.
registrationRetryDelay()
For a product that retries a failed registration itself: nothing in this
package calls it, since registerForGame never retries.
registrationRetryDelay(failures: number): numberreportTx()
Build Game.report, unsigned.
Only valid while the game is in Reporting. Each Person vote awards the attestee
a claim credit on the spot, and the call fails with Game.CreditCapacityExhausted
before recording anything when there is no room for them. Pays::No on success.
reportTx(chain: ReportChain<Tx>, options: ReportOptions): TxThrows
- ProductIndividualityError on a vote that is neither
PersonnorNotPerson.
ringCollectionId()
A personhood ring’s collection identifier: the human-readable name,
space-padded to the 32-byte CollectionId the Members pallet keys on.
Lite and full personhood differ only in this junction.
ringCollectionId(name: "people" | "people-lite"): Uint8ArrayrunScoreContextRead()
Throws; readScoreContext owns the Result boundary. Exported so a
composing read can run it against a block it already pinned, like
prize-status.ts runs runDrawRead, rather than pinning a second.
runScoreContextRead(chain: AnyScoreContextChain, options: ReadScoreContextOptions = {}, pinned?: BlockSnapshot): Promise<ScoreContext>seatRequired()
What the deposit route needs up front: the deposit, plus the fee times
feeHeadroom. An estimate the runtime could not make counts as no fee.
seatRequired(funds: Pick<SignUpFunds, "deposit" | "estimatedFee">, feeHeadroom: number = DEFAULT_FEE_HEADROOM): bigintsignUpWithAccountTx()
Build Game.sign_up_with_account, unsigned. Pays::No on success, though a new
or archived player still pays a deposit.
airdrops takes either arm; the chain decides which one it accepts from this
player’s recognition, so build the one GameSignUpRequirement.variant names.
A returning player owes no deposit and can sign under withScoreParticipant to
skip the fee as well, which is how a zero-balance account signs up again. A new
or archived player owes the deposit, so sign plainly.
signUpWithAccountTx(chain: SignUpChain<Tx>, options: SignUpWithAccountOptions): TxThrows
- ProductIndividualityError on a wrong-width key, signature or proof, or
an airdrop count that disagrees with
airdropsScheduled. Checked because the chain’s own failure rejects the sign-up with nothing to inspect.
signUpWithLiteInviteTx()
Build Game.sign_up_with_account_lite_invite, unsigned. Pays::No, no
deposit, valid on a zero balance — but only submittable under
withLiteAlias({ tag: "AliasWithAccount" }) by the bound account, with
RestrictOrigins true (which that signer sets).
The same width and count guards as signUpWithAccountTx: they protect the
same call arguments, and the chain’s own rejection names nothing local.
signUpWithLiteInviteTx(chain: LiteSignUpChain<Tx>, options: SignUpWithLiteInviteOptions): TxThrows
- ProductIndividualityError on a wrong-width key or signature, or an
airdrop count that disagrees with
airdropsScheduled.
statusTag()
Validate a raw Status variant name. Exported so a read that only needs the
variant, not the whole event, still fails loudly on an unknown one.
The domain tags match the chain’s variant names exactly, so this narrows rather than translates.
statusTag(type: string): AirdropStatusTagtoAirdropEvent()
toAirdropEvent(eventId: string, raw: RawActiveEvent): AirdropEventParameters
eventId: the key the row was read under, rather thanraw.id; the two agreeing is asserted below, not assumed.
Throws
- IndividualityDecodeError on an unknown status variant, an out-of-range
timestamp, or an
idthat disagrees with the key.
toCurrentGame()
Map the raw running game, selecting the deadline that belongs to its phase.
toCurrentGame(raw: RawGameInfo): CurrentGameThrows
- IndividualityDecodeError on a
GameStatevariant this package does not know.
toGamePhaseDurations()
Map the raw phase durations, from either source.
toGamePhaseDurations(raw: RawPhaseDurations): GamePhaseDurationstoGameSchedulePreview()
Map one upcoming schedule, deriving its timeline from the given durations.
The durations must come from the same block as the schedule, or the projection describes a game under rules that were never in force together.
toGameSchedulePreview(raw: RawGameSchedule, durations: GamePhaseDurations): GameSchedulePreviewtoPersonhoodParticipant()
Map a raw PAPI participant to the domain shape the derivation consumes.
The recognition payload (a revision id) is discarded, the game-economy fields
are dropped, and a missing last_attended_game becomes null rather than
undefined so the domain type has one absent value, not two.
toPersonhoodParticipant(raw: RawParticipant): PersonhoodParticipanttoRawRegistrationEntry()
A domain registrant as the Winners key wants it.
toRawRegistrationEntry(registrant: AirdropRegistrant): RawRegistrationEntryusernameBase()
The letters part of a lite username, which is what a claim would offer.
A lite username is letters, one dot, then digits, so the dot is always there and there is only one. A full username has no dot and is returned unchanged.
A suggestion, not an entitlement. An account may hold a reservation for a different name, and the reservation is what the chain honours.
usernameBase(username: string): stringwatchCurrentGame()
Game.Game, which is null between games.
watchCurrentGame(chain: CurrentGameWatchChain, onValue: (game: CurrentGame | null, block: WatchedBlock) => void, onError: WatchErrorHandler): () => voidwatchParticipant()
Score.Participants, which is null for a player who has never been scored.
watchParticipant(chain: ParticipantWatchChain, options: WatchPlayerOptions, onValue: (participant: PersonhoodParticipant | null, block: WatchedBlock) => void, onError: WatchErrorHandler): () => voidwatchPlayer()
Game.Players, which is null for a player who never signed up or was archived.
watchPlayer(chain: PlayerWatchChain, options: WatchPlayerOptions, onValue: (record: PlayerRecord | null, block: WatchedBlock) => void, onError: WatchErrorHandler): () => voidwithAsPerson()
Wrap a signer so its transactions run under a person origin.
signBytes and publicKey pass through untouched. PAPI stamps publicKey
into the extrinsic and uses it to fetch the nonce, so it has to stay the inner
signer’s.
withAsPerson(signer: CommonSignerTxCreator, info: AsPersonInfo): CommonSignerTxCreatorParameters
signer: the signer to wrap, e.g. fromAccountsProvider.getProductAccountSigner.info: which person origin to use, and where the proof comes from.
Returns
a transaction creator usable anywhere the original was.
withLiteAlias()
Wrap a signer so its transactions run under a lite-person origin.
signBytes and publicKey pass through untouched. PAPI stamps publicKey
into the extrinsic and uses it to fetch the nonce, so it has to stay the
inner signer’s.
withLiteAlias(signer: CommonSignerTxCreator, info: LiteAliasInfo): CommonSignerTxCreatorParameters
signer: the signer to wrap, e.g. fromAccountsProvider.getProductAccountSigner.info: which lite-person origin to use, and where the proof comes from.
Returns
a transaction creator usable anywhere the original was.
withScoreParticipant()
Wrap a signer so its transactions run as the score participant, fee-free.
signBytes and publicKey pass through untouched. PAPI stamps publicKey
into the extrinsic and uses it to fetch the nonce, so it has to stay the
inner signer’s — which is also what keeps the participant the chain resolves
(Participants[Account(signer)]) the account this signer signs as.
withScoreParticipant(signer: CommonSignerTxCreator): CommonSignerTxCreatorParameters
signer: the signer to wrap, e.g. fromAccountsProvider.getProductAccountSigner.
Returns
a transaction creator usable anywhere the original was.
Interfaces
interface AbsenceGracePolicy
The absence-grace policy currently in force, decoded from
Score.AbsenceGraceRatio.
window is a count of recent games; allowedMisses is how many of them may
be absences before the next one suspends. A window of 0 means no grace at
all.
Properties
allowedMisses
numberwindow
numberinterface AccountVrfSignature
One AirdropVrfs::Account entry, shaped as the host’s signVrf returns it.
Properties
preOutput
Uint8Array32 bytes.
proof
Uint8Array64 bytes, the DLEQ proof.
interface AirdropAssetId
The prize asset, as an XCM location. Opaque on purpose — this package does not
model XCM; it is the key an Assets.Metadata read takes.
Properties
interior
unknownparents
numberinterface AirdropChain
Structural, so a test double satisfies it. See IndividualityChain in read.ts
for the conventions and where the fidelity guard lives.
Matched by hand against the paseo descriptors on 2026-08-20:
Game.airdrop_event_id_base: PlainDescriptor<SizedHex<27>>
Airdrop.Events: StorageDescriptor<[Key: SizedHex<32>], ActiveEvent, true, never>
Airdrop.Winners: StorageDescriptor<[SizedHex<32>, RegistrationEntry], SizedHex<32>, true, never>
Airdrop.EventEntropy: StorageDescriptor<[Key: SizedHex<32>], SizedHex<32>, true, never>Extends: PinnedChain
Properties
individuality
{ constants: { Game: { airdrop_event_id_base: unknown } }; query: { Airdrop: { EventEntropy: { getValue: unknown }; Events: { getValue: unknown }; Registrations: { getEntries: unknown }; SupportedAssets: { getValue: unknown }; Winners: { getValue: unknown } } } }interface AirdropDraw
One draw at one pinned block. event is null exactly when phase is "Gone",
but the outcome survives that: Winners is cleared in its own lifecycle state,
so a win can outlive the event row or be swept before it.
Properties
at
BlockSnapshotThe finalized block every read in this row was pinned to.
entropy
string | nullThe draw’s entropy seed, present from DrawWinners onwards and null
before it. Only useful for verifying a draw independently; a product
rendering a result does not need it.
event
AirdropEvent | nulleventId
stringoutcome
AirdropOutcomephase
AirdropPhaseinterface AirdropEvent
The counters are null where the Status variant does not carry them — not
zero: a Finalizing draw did have participants, the chain stopped reporting it.
| Field | Absent in |
|---|---|
totalParticipants | Scheduled, Finalizing |
effectiveWinners | Scheduled, Registering |
claimed | Scheduled, Registering, AwaitingEntropy, DrawWinners |
Properties
claimed
number | nulldrawTime
numberUnix seconds: registration closes and the draw is performed.
effectiveWinners
number | nullendTime
numberUnix seconds: claiming closes and clean-up starts.
eventId
stringThe 32-byte event id, 0x-prefixed, as the draw is addressed by.
phase
AirdropPhaseprize
AirdropPrizeregistrationStarts
numberUnix timestamp in seconds, when registration opens.
All three timestamps are u64 seconds on chain, not block numbers and
not milliseconds. Multiply by 1000 before handing one to Date.
source
string | nullThe account funding this event, for source-funded draws. null for
pre-funded ones, whose released funds stay in the pallet’s pot.
status
AirdropStatusTagtotalParticipants
number | nullinterface AirdropPrize
The prize a draw pays out, from AirdropPrize on chain.
Properties
assetAmount
bigintTotal amount paid across all winners, in the prize asset’s smallest unit.
assetId
AirdropAssetIdNot the chain’s native token. Prizes are paid in a foreign asset, so
formatting assetAmount with the chain’s tokenDecimals is wrong. Read
Assets.Metadata for this id and use its decimals.
maxWinners
numberHard cap on winners, whatever the participant count.
winnerCapPermill
numberThe share of participants that may win, as a Permill — parts per
million, not a count and not a percentage. 10_000 is one percent.
Named for the unit because rendering it as a count is the mistake the
plain chain name (winner_cap) invites.
interface AirdropVrfSigner
An sr25519 VRF over one draw’s transcript.
Wire this to AccountsProvider.signVrf(account, label, items). Neither host
call satisfies it directly, since both take the account first, so the adapter
closes over it and unwraps the Result. The module doc has one.
Structural, so the package keeps no dependency on @parity/product-sdk-host.
Methods
signVrf
signVrf(transcriptLabel: Uint8Array, items: VrfTranscriptItem[]): Promise<AccountVrfSignature>interface AliasAirdropVrfs
The AirdropVrfs::Alias arm: one proof per draw, all at one ring revision.
Properties
proofs
Uint8Array<ArrayBufferLike>[]In airdrop-index order, raw bandersnatch ring-VRF proof bytes.
revision
numberThat ring’s revision at generation time. One for all of them.
ringIndex
numberThe ring the proofs were generated against. One for all of them.
interface AliasDrawProofContext
The product-scoped context one draw’s proof is minted in, as the host’s
createRingVRFProof takes it: the product’s dotNS id and the event id as a
raw 32-byte suffix. Structural, so the package keeps no dependency on
@parity/product-sdk-host; the Raw arm of truapi’s ProductProofContext.
Properties
productId
string"<product_name>.<tld>", lower case: the chain hashes the raw string.
suffix
{ tag: "Raw"; value: string }The draw’s event id, 0x hex, 32 bytes.
interface BindGameSeatOptions
Options for bindGameSeat.
Properties
signal
AbortSignaltimeoutMs
numberHow long to wait for a block to hold the bind. Default 120 000 ms, then Timeout.
tld
stringinterface BlockSnapshot
A block a read was pinned to.
Properties
blockHash
stringblockNumber
numberinterface BlockSource
Where a pinned read gets its block: the part of PAPI’s PolkadotClient the
reads use, so a PolkadotClient fits as it is.
Methods
getBestBlocks
getBestBlocks(): Promise<{ hash: string; number: number }[]>getFinalizedBlock
getFinalizedBlock(): Promise<{ hash: string; number: number }>interface BuildLiteAliasBindTxOptions
Options for buildLiteAliasBindTx.
Properties
account
stringThe account to bind, as an SS58 address. A plain call parameter: the
chain ties it to nothing but the proof’s alias, which is what lets the
personhood product bind another product’s account. LiteInvites later
pins it as the one account this lite person may ever invite, so show a
person which account they are binding before building this.
createProof
CreateRingVRFProofMints the lite ring-VRF proof over the message this builder computes.
Wire it to createRingVRFProof with the lite key handle, the
RingLocation from litePeopleRing, and the ProductProofContext that
readScoreContext reported — never choose the message yourself.
signal
AbortSignalinterface CapturedGame
A game identified by the caller rather than read from the chain.
Properties
airdropsScheduled
numberairdrops_scheduled as it was while the game ran. Capture it then: it is
unreadable afterwards, and it is the count that actually got scheduled
rather than what the schedule asked for.
index
numberinterface ClaimChain
The Game.claim_airdrop call, plus the Score.Participants read the check
needs. Composed with AirdropChain, which supplies the draw.
Extends: PinnedChain
Properties
individuality
{ constants: { Game: { airdrop_event_id_base: unknown } }; query: { Score: { Participants: { getValue: unknown } } }; tx: { Game: { claim_airdrop: unknown } } }interface ClaimEligibility
Whether a specific prize can be claimed, and what stops it if not.
Properties
blockers
ClaimBlocker[]Empty exactly when claimable is true.
claimable
booleanticket
string | nullThe winning ticket, when there is one. Worth keeping: it is the only local
evidence that distinguishes “claimed” from “never won” once the chain has
removed the Winners row.
window
ClaimWindow | nullThe draw’s deadlines whenever the draw exists, independent of whether this
caller can claim, so a product can show the window to someone who did not
win. null only when the event row is gone. Read claimable for whether
there is anything to do before it.
interface ClaimEligibilityResult
The result of checking a claim against the chain.
Extends: ClaimEligibility
Properties
airdropIndex
numberat
BlockSnapshoteventId
stringgameIndex
numberinterface ClaimInputs
Everything the predicate needs, all from one pinned block.
Properties
draw
AirdropDrawThe draw, as readAirdropDraw or readPrizeStatus returned it.
gameIndex
numberThe game the prize belongs to, which the chain compares attendance against.
now
numberUnix seconds, against the draw’s end_time. An input rather than the
clock so a caller can pass the block’s own time: a device clock minutes fast
will call a live window closed.
participant
PersonhoodParticipant | nullnull when Score.Participants holds no record for the claimant.
prizeAssetEnabled
boolean | nullWhether the prize asset is still enabled for airdrops, from
Airdrop.SupportedAssets. false blocks the claim on chain, so leaving it
out would let a claimable: true cost the player a fee.
null means nothing to check: the draw’s event row is gone and carries no
asset id. Not the same as disabled, and reporting it as such would name a
cause that is not true on top of the DrawNotClaiming that already fires.
interface ClaimTarget
Everything a claim addresses.
Properties
airdropIndex
numbergameIndex
numberregistrant
AirdropRegistrantWho is claiming. Decides both the Score.Participants key and the
Winners key, and must match the identity that entered the draw — a
player who signed up with an alias cannot claim as an account.
interface ClaimWindow
When a claim stops being possible. Two deadlines apply and only one is a clock — the other has no timestamp at all.
Properties
closesOnNextAttendance
booleanAlways true on the game path, and the reason a countdown alone misleads:
attending the next game moves last_attended_game and closes the claim,
usually well before endTime. The runtime contemplates relaxing == to
>=, which would make this false.
endTime
numberUnix seconds. The draw’s end_time.
interface CommunicationIdentifierResult
Properties
at
BlockSnapshotidentifier
Uint8Array<ArrayBufferLike> | nullThe 65 bytes the account registered at sign-up, or null when it has none.
The chain never interprets them, and deriving them stays with the product.
interface ConfirmClaimOptions
Options for confirmClaim.
Extends: ClaimTarget
Properties
signal
AbortSignalinterface ConsumersChain
The chain surface this read needs, structural rather than a pinned descriptor.
Anything exposing this one entry satisfies it: a real ChainClient from
getChainAPI, a future People Lite deployment, or a hand-rolled test double.
Deliberately narrower than IndividualityChain in read.ts, so a double for
either read does not have to implement the other’s entries.
Written with method shorthand on purpose: the parameter bivariance that gives is what lets the real PAPI signature satisfy the loosened key type below.
Fidelity is checked at compile time from the umbrella package, in
packages/sdk/src/individuality/contract.test.ts, for the reason recorded
there: inside this package the same assertion is vacuous.
Properties
individuality
{ query: { Resources: { Consumers: { getValue: unknown } } } }interface ConsumerUsernames
The usernames registered for one account, decoded.
Properties
credibility
UsernameCredibilityfullUsername
string | nullliteUsername
stringAlways present, for example example.07.
interface CreditCandidate
One credit the attestee could earn this game: a co-player of one round, and the hash.
Properties
attester
PlayerKeyExactly as the chain keys the co-player, which is the form the hash is built from.
attesterIndex
numberhash
stringThe credit, as creditHash derives it.
round
numberinterface CreditCandidatesResult
Properties
at
BlockSnapshotcandidates
CreditCandidate[]Ascending by round, then by attester index. Empty when the attestee holds no seat.
gameIndex
number | nullThe game the candidates belong to, or null when no game has a roster at this block.
interface CurrentGame
The game that is running now.
Properties
airdropsScheduled
numberDraws actually scheduled, carrying airdrop indices 0..airdropsScheduled.
Derive event ids from this, not the schedule’s count. Scheduling stops at the first failure, so a game can end up with fewer draws than it asked for.
gamePlayTime
numberindex
numberThe game index, which is also the game_index a prize claim takes.
Games are numbered from 1: the counter is incremented when a game is created, so index 0 never names one.
maxGroupSize
numbernextDeadline
number | nullThe boundary this phase runs to, null for PlayerProcess and Cancelling,
which end on work rather than time. Taken from the boundary matching
phase, never inferred from the clock: transitions run in an offchain
worker’s own time, so a boundary can be past while its phase is current.
pendingAttendance
numberRegistered players whose attendance is not settled yet. Reaches zero when every player has been resolved, which can end the reporting phase early.
phase
GamePhaseplayerCount
number | nullPlayers in the roster, which the group arithmetic of the roster reads needs.
Known from the end of the shuffle until PlayerProcess clears the indices,
and null outside that window, which is also when the roster reads are valid.
registrationEnds
numberUnix seconds. Stored on the game, not re-derived.
reportingEnds
numberrounds
numbershuffleDeadline
numberinterface CurrentGameWatchChain
Structural, so a test double satisfies it.
Properties
individuality
{ query: { Game: { Game: { watchValue: unknown } } } }interface DrawOutcome
What a sign-up carried for the game’s prize draws.
Properties
entered
numberHow many draws the sign-up enters.
kind
DrawSkipKindretries
numberscheduled
numberGame.airdrops_scheduled.
skipped
stringWhy none, when entered is 0 and draws were scheduled.
waitedMs
numberHow long the sign-up waited for a draw to open.
interface DrawRegistration
One draw’s registration for one identity.
Properties
at
BlockSnapshotentriesScanned
numberEntries the scan walked. Reported because it is the cost of the call, and nothing bounds it below the draw’s participant count.
eventId
stringslot
string | nullThe entropy slot the registration is stored under, or null when this
identity has none. The slot is also the draw ticket.
interface DrawWaitOptions
How long a sign-up waits for draws that are not open yet.
Properties
closingSeconds
numberStop waiting this many seconds before registration closes. Default 15.
maxMs
numberThe longest wait. Default 20 000 ms.
retryMs
numberHow often to ask again. Default 2 000 ms, about a block.
interface EncodedCallSource
The one call-encoding method the builder needs; PAPI transactions have it.
Methods
getEncodedData
getEncodedData(): Promise<Uint8Array<ArrayBufferLike>>interface FeeEstimable
A built transaction whose fee can be estimated, as every PAPI 3 transaction can.
Methods
getEstimatedFees
getEstimatedFees(creator: CommonSignerTxCreator, options: { nonce: number }): Promise<bigint>interface GameAccount
The game account: dim2.<tld> at GAME_ACCOUNT_INDEX.
Properties
address
stringSS58.
publicKey
Uint8ArrayThe 32-byte sr25519 public key.
interface GameChain
Structural, so a test double satisfies it. Separate from AirdropChain because a
caller reading the game needs neither it nor the personhood entries;
PrizeStatusChain is the intersection.
Matched by hand against the paseo descriptors on 2026-08-20:
Game.GameIndex: StorageDescriptor<[], number, false, never>
Game.Game: StorageDescriptor<[], GameInfo, true, never>
Game.GameSchedules: StorageDescriptor<[], Array<GameSchedule>, false, never>
Game.StoredPhaseDurations: StorageDescriptor<[], PhaseDurationValues, true, never>
Game.DefaultPhaseDurations: PlainDescriptor<PhaseDurationValues>Extends: PinnedChain
Properties
individuality
{ constants: { Game: { DefaultPhaseDurations: unknown } }; query: { Game: { Game: { getValue: unknown }; GameIndex: { getValue: unknown }; GameSchedules: { getValue: unknown }; StoredPhaseDurations: { getValue: unknown } } } }interface GamePhaseDurations
The phase durations in force, from Game.StoredPhaseDurations when governance
has set one and Game.DefaultPhaseDurations otherwise. All in seconds.
Properties
playerProcess
numberpostShuffleMargin
numberSlack between the shuffle deadline and the play time.
registration
numberreporting
numbershuffle
numberinterface GamePlayersChain
The registration entry, needed only when ReadCurrentGameOptions.players
is given. Kept out of GameChain so a caller that never asks about a
player, and every existing test double, keeps satisfying the narrower type.
Game.Players: StorageDescriptor<[Key: AccountOrPerson], { registered: boolean }, true, never>Properties
individuality
{ query: { Game: { Players: { getValue: (key: PlayerKey, options: ReadAt) => Promise<{ registered: boolean } | undefined> } } } }interface GameRegistrationCapabilities
Everything a host does for a sign-up; hostGameRegistrationCapabilities builds it.
Properties
account
GameAccountpersonhood
PersonhoodProverThe personhood keys. Without it, no free route and no member draw entries.
signer
CommonSignerTxCreatorThe game account’s signer: getProductAccountSigner.
signVrf
(transcriptLabel: Uint8Array, items: VrfTranscriptItem[]) => Promise<AccountVrfSignature>An sr25519 VRF by the game account, for account-arm draw tickets. Without it, no tickets.
submit
SubmitSignUpSubmits the built sign-up.
verifyVrf
(publicKey: Uint8Array, transcript: VrfTranscript, signature: AccountVrfSignature) => booleanChecks a ticket before it rides the sign-up, where one bad ticket fails it all.
interface GameRegistrationReport
What one registerForGame call did, for telemetry; failures carry it too.
Properties
bind
{ outcome: BindGameSeatOutcome } | { code: GameRegistrationCode; outcome: "refused"; permanent: boolean; refusal: GameSeatBindRefusal }broadcastAt
numberWhen the sign-up went on the wire.
draws
DrawOutcomeliteKeyLookupFailed
stringWhy the host’s lite key could not be looked up; the free route was closed.
route
SeatRouteseat
{ open: boolean; path: SeatPath; ready: boolean; registered: boolean }signUp
{ code?: GameRegistrationCode; landingUnknown?: boolean; message?: string; outcome: "registered" | "already-registered" | "failed" }steps
Partial<Record<GameRegistrationStep, { endedAt?: number; startedAt: number }>>When each step started and ended, in wall-clock milliseconds.
interface GameScheduledAirdrop
One prize draw a schedule will set up, with its timing relative to play time.
Properties
claimWindow
numberSeconds the claim window stays open after the draw.
drawOffset
numberSeconds after the play time at which winners are drawn.
prize
AirdropPrizeinterface GameSchedulePreview
A game not created yet. The chain keeps Game.GameSchedules chronological —
schedule_games rejects anything overlapping or preceding the last one, and
remove_scheduled_game binary-searches it — so the first entry is the next game.
Properties
airdrops
GameScheduledAirdrop[]The draws this schedule asks for — an upper bound, since scheduling can fail per draw. For showing a prize before the game exists, never for deriving event ids.
gamePlayTime
numberUnix seconds. The only time the chain stores for a scheduled game.
maxGroupSize
numberrounds
numbertimeline
GameTimelineBoundaries derived from the durations at the same block — a projection.
Governance can move them before this game is created, shifting everything
here except gamePlayTime. Once it exists, read its stored boundaries.
interface GameSeat
Seat, with what decided it and whether a sign-up can go out now.
Extends: Seat
Properties
funds
SignUpFundsopen
booleanRegistration is open: none of NoGameRunning, NotInRegistration,
RegistrationEnded, judged by the chain’s clock at the best block, never
the device’s.
registered
booleanAlreadyRegistered: this account is signed up for the running game.
required
bigintWhat the deposit route needs up front; see seatRequired.
requirement
LiteSignUpRequirementinterface GameSignUpRequirement
What the chain will accept from this player, at one pinned block. Index and draw count must come from the same block: an id built from one game’s index and another’s count addresses a draw that does not exist.
Properties
airdropsScheduled
numberGame.airdrops_scheduled. The airdrops list must have exactly this many entries.
at
BlockSnapshotblockers
SignUpBlocker[]Empty exactly when both canSignUp and canEnterDraws hold.
canEnterDraws
booleanNever true when canSignUp is false: the draws ride on the sign-up.
canSignUp
booleanWhether the chain would accept a sign-up, with or without draw entry.
Not whether this package can build one: an Alias registrant needs
sign_up_with_alias, which cannot be assembled, and still reads true.
eventIds
string[]Ids for airdrop indices 0 to airdropsScheduled - 1, in supply order.
gameIndex
number | nullnull between games. Not the lastGameIndex a late claim uses.
phase
GamePhase | nullregistrationEnds
number | nullUnix seconds. null between games.
variant
AirdropVrfVariant | nullnull between games, where recognition is known but there is nothing to enter.
interface GameTimeline
A game’s phase boundaries, Unix seconds. Mirrors the runtime’s GameTimes
trait (pallets/game/src/types.rs:525), and is only ever a projection, for a
game that does not exist yet.
Properties
gamePlayTime
numberplayerProcessEnds
numberEnd of the whole game. The chain schedules nothing else before it.
registrationEnds
numberregistrationStarts
numberEarliest the game may open for sign-ups.
reportingEnds
numbershuffleDeadline
numberMiss this and the game is cancelled rather than played.
interface GroupMember
One occupied seat, resolved to the player the chain keys it by.
Properties
index
numberplayer
PlayerKeyinterface GroupMembersResult
Properties
at
BlockSnapshotmembers
GroupMember[]Every occupied seat, the player at ownIndex included, ascending by index.
interface GroupSeat
One position of a group, with whether a player was shuffled into it.
Properties
index
numberoccupied
booleaninterface IndividualityChain
The chain surface this read needs — deliberately structural, not a pinned descriptor.
Anything exposing these six entries satisfies it: a real
ChainClient<{ individuality: … }> from getChainAPI, a future People Lite
deployment, or a hand-rolled test double. The same approach as
PeopleUsernameQueryApi in @parity/product-sdk’s identity/dotns.ts, and
for the same reason — the SDK should not pin a genesis hash to read a
username.
Written with method shorthand on purpose: the parameter bivariance that gives is what lets the real PAPI signatures satisfy the loosened key types below.
Fidelity is checked at compile time, from the umbrella package.
packages/sdk/src/individuality/contract.test.ts asserts that a real
getChainAPI client still satisfies this type, so a descriptor regeneration
that changes an entry fails pnpm typecheck.
The guard has to live there rather than here, which is worth recording because
it is not obvious. Inside this package the same assertion is vacuous: it
passes even against a contract demanding a pallet the chain does not have,
because the descriptor types do not fully resolve through this package’s
dependency graph. From packages/sdk, which depends on both chain-client and
this package, the identical assertion correctly rejects a bogus contract. Both
halves were verified before choosing the placement.
The entries were also matched by hand on 2026-08-17 against
descriptors/chains/paseo-individuality/generated/dist/paseo_individuality.d.ts:
UsernameOwnerOf: StorageDescriptor<[Key: Uint8Array], SS58String, true, never>
Participants: key AnonymousEnum<{ Account: SS58String; Person: SizedHex<32> }>
PersonhoodThreshold: StorageDescriptor<[], number, false, never>
AbsenceGraceRatio: StorageDescriptor<[], SizedHex<2>, false, never>
AccountToAlias: value { revision, ring, ca: { alias, context } }
LitePeople: value { ring_vrf_key, method } (presence is the signal)A descriptor regeneration that changes any of them now fails pnpm typecheck
rather than passing silently.
Properties
individuality
{ query: { People: { AccountToAlias: { getValue: unknown } }; PeopleLite: { AccountToAlias: { getValue: unknown }; LitePeople: { getValue: unknown } }; Resources: { UsernameOwnerOf: { getValue: unknown } }; Score: { AbsenceGraceRatio: { getValue: unknown }; Participants: { getValue: unknown }; PersonhoodThreshold: { getValue: unknown } } } }raw
{ individuality: { getFinalizedBlock: unknown } }interface LegacySuffixChain
The network suffix before #20. Previewnet only, and gone on its next upgrade.
Score.Suffix: PlainDescriptor<Uint8Array>Properties
individuality
{ constants: { Score: { Suffix: unknown } } }interface LiteAliasBindChain
What building the bind leg needs from a chain: the call codec, the current
best block for valid_at_block, and the three values the proof implicitly
signs — metadata (the extension pipeline), the runtime version and the
genesis hash. Matched by hand against the previewnet descriptors on
2026-08-31.
Properties
individuality
{ apis: { Metadata: { metadata_at_version: unknown } }; constants: { System: { Version: unknown } }; query: { System: { Number: { getValue: unknown } } }; tx: { PeopleLite: { set_alias_account: unknown } } }raw
{ individuality: { getChainSpecData: unknown } }interface LiteAliasBindTx
What buildLiteAliasBindTx returns.
Properties
ringIndex
numberWhich ring the proof was minted against, for logging.
ringRevision
numberThat ring’s revision at minting time, for logging.
transaction
Uint8ArrayThe finished extrinsic. Submit it raw — client.submit, or anything
that broadcasts bytes; there is nothing left to sign.
validAtBlock
numberThe valid_at_block the call carries: the best block at build time.
interface LiteSignUpChain
The lite sign-up call, plus the reads that decide whether it can dispatch.
Composed with GameChain and SignUpChain, which supply the
game and the account-path reads. Matched by hand against the paseo and
previewnet descriptors on 2026-09-02 (devnet predates the surface):
PeopleLite.AccountToAlias: StorageDescriptor<[Key: SS58String], { revision, ring, ca }, true, never>
PeopleLite.LitePeople: StorageDescriptor<[Key: SS58String], LitePersonInfo, true, never>
Game.LiteInvites: StorageDescriptor<[Key: SizedHex<32>], SS58String, true, never>
Members.Members: StorageDescriptor<[SizedHex<32>, SizedHex<32>], MemberStatus, true, never>
Members.Root: StorageDescriptor<[SizedHex<32>, number], { root, revision, intermediate }, true, never>
Game.StmtAccountToAlias: StorageDescriptor<[Key: SS58String], SizedHex<32>, true, never>Properties
individuality
{ query: { Game: { LiteInvites: { getValue: unknown }; StmtAccountToAlias: { getValue: unknown } }; Members: { Members: { getValue: unknown }; Root: { getValue: unknown } }; PeopleLite: { AccountToAlias: { getValue: unknown }; LitePeople: { getValue: unknown } } }; tx: { Game: { sign_up_with_account_lite_invite: unknown } } }interface LiteSignUpRequirement
GameSignUpRequirement with the wider blocker union: what the chain
will accept from this account as a lite sign-up, at one pinned block.
canSignUp and canEnterDraws answer for
Game.sign_up_with_account_lite_invite — the account read’s answers AND’ed
with “no lite blocker”, since every lite arm stops the whole extrinsic.
Extends: Omit<GameSignUpRequirement, "blockers">
Properties
blockers
LiteSignUpBlocker[]Empty exactly when both canSignUp and canEnterDraws hold.
interface LookupUsernameOptions
Options for lookupUsername.
Extends: ConsumersReadAt
Properties
account
stringThe account to read, SS58 encoded. This is the storage key.
interface MintAccountAirdropVrfsOptions
Options for mintAccountAirdropVrfs.
Properties
eventIds
string[]In airdrop-index order: entry i is checked against airdrop index i.
publicKey
Uint8ArrayThe signing account’s sr25519 key, 32 bytes.
signal
AbortSignalChecked between draws only. AirdropVrfSigner takes no signal, so a
signature already being prompted for cannot be cancelled, unlike the reads.
interface MintAliasAirdropVrfsOptions
Options for mintAliasAirdropVrfs.
Properties
eventIds
string[]In airdrop-index order: entry i is checked against airdrop index i.
productId
stringThe game’s product under the network tld, e.g. "dim2.paseo":
Game.product_name on chain, which every event the game schedules
stores, joined to the dotNS tld the host runs on. Lower case; the chain
hashes the raw string, so DIM2.paseo is a different context.
registrant
AirdropRegistrantThe identity signing up, which the chain verifies each proof against.
signal
AbortSignalChecked between draws only; a proof already being prompted for cannot be cancelled.
interface NetworkSuffixChain
The network suffix since individuality-community #20. Root can move it between
blocks, so it is read at a pinned one. The pallet is testnet-only upstream, so
production has neither this nor LegacySuffixChain and the caller says.
NetworkSuffix.NetworkSuffix: StorageDescriptor<[], Uint8Array, false, never>Extends: PinnedChain
Properties
individuality
{ query: { NetworkSuffix: { NetworkSuffix: { getValue: unknown } } } }interface PapiIndividualityChain
What fromPapi returns, with the typed API preserved.
Properties
individuality
Apiraw
{ individuality: Client }interface ParticipantWatchChain
Properties
individuality
{ query: { Score: { Participants: { watchValue: (key: PlayerKey, options: WatchAt) => WatchedValue<RawParticipant | undefined> } } } }interface PeopleAirdropEntry
One PeopleAirdrops draw, and where this account’s alias stands in it.
Properties
drawIndex
bigintevent
AirdropEventregistered
boolean | nullWhether Airdrop.Registrations holds the slot; null when there is no slot to look up.
slot
string | nullThe alias’s slot in the draw; null without an alias or before the draw has a salt.
won
boolean | nullWhether Airdrop.Winners holds the alias; null without an alias.
interface PeopleAirdropsAlias
Properties
airdropsContext
stringPeopleAirdrops.people_airdrops_context, the context an entering alias must carry.
binding
PeopleAirdropsBindinginterface PeopleAirdropsChain
The chain surface the reads need — structural, so a typed PAPI api from
fromPapi, any network’s descriptors, or a test double all satisfy it.
Extends: PinnedChain
Properties
individuality
{ constants: { PeopleAirdrops: { people_airdrops_context: unknown } }; query: { Airdrop: { Events: { getEntries: unknown }; Registrations: { getValues: unknown }; Winners: { getValues: unknown } }; Members: { Root: { getValue: unknown } }; People: { AccountToAlias: { getValue: unknown } }; PeopleAirdrops: { DrawSalts: { getValues: unknown } } } }interface PeopleAirdropsRegisterCall
Properties
eventIds
string[]tx
Txinterface PeopleAirdropsRegisterChain
The chain surface peopleAirdropsRegisterCalls needs.
Properties
individuality
{ constants: { PeopleAirdrops: { MaxRegisterBatch: unknown } }; tx: { PeopleAirdrops: { register: unknown } } }interface PeopleAirdropsStanding
Properties
account
stringalias
PeopleAirdropsAliasat
BlockSnapshotdraws
PeopleAirdropEntry[]Every PeopleAirdrops draw still on chain, oldest draw index first.
interface PersonhoodInputs
Everything PersonhoodState is derived from, resolved for one account at
one block.
Named inputs rather than a snapshot on purpose: FinalizedSnapshot is
the block this was read at, and two exported types called Snapshot meaning
different things is a trap.
Properties
isLitePerson
booleanparticipant
PersonhoodParticipant | nullpersonhoodThreshold
numberScore.PersonhoodThreshold. This is a u8 on chain, but PAPI types
both u8 and u32 as number, so a width mistake here typechecks and
passes tests. Verified against the metadata blob on 2026-08-16.
policy
AbsenceGracePolicyinterface PersonhoodMetrics
The numbers behind a resolved state, carried alongside it.
The state union answers “what is this person’s standing”; these answer “by how much”, which a progress bar needs in every state rather than only in the two whose variants happen to carry payload. All five come from the same pinned snapshot as the state, so no extra read pays for them.
misses here is not Caution.misses. This is what the window holds
now. Caution.misses is a projection — what it would hold after one more
absence — because that is what the grace policy is evaluated against. A UI
showing “you have missed 2 of the last 8” wants this one.
score and misses are null when the account has no participant record:
there is no score to report and no attendance history to count. The threshold
and the policy are unkeyed storage values, so they are always present.
Properties
allowedMisses
numberScore.AbsenceGraceRatio: how many of window may be absences.
misses
number | nullAbsences inside the current window, or null with no record.
personhoodThreshold
numberScore.PersonhoodThreshold, the score at which personhood is reached.
score
number | nullwindow
numberScore.AbsenceGraceRatio: how many recent games the policy looks at.
interface PersonhoodParticipant
A participant’s game record, as read from Score.Participants and decoded.
attendanceHistory is a rolling byte: bit 0 is the most recent game, 1
means attended and 0 means absent.
Properties
attendanceHistory
numberhasEverReachedPersonhood
booleanStays true once personhood was reached, after the score falls back below the threshold.
lastAttendedGame
number | nullreachedPersonhood
booleanrecognition
"Suspended" | "ExternallyRecognized" | "NotRecognized" | "Recognized"score
numberstreak
{ count: number; tag: "Attended" | "Absent" }interface PersonhoodProver
The personhood product’s keys, as a host exposes them; other products need its context grant.
Methods
holds
Whether the host holds this person’s key in that ring.
holds(ring: PersonhoodRing): Promise<boolean>prove
A proof over message in context with that key. Rejects when the host refuses.
prove(ring: PersonhoodRing, context: PersonhoodProofContext, message: Uint8Array): Promise<RingVRFProof>interface PersonhoodRing
A personhood key, the ring it is a member of, and the product that holds it.
Properties
key
PersonhoodKeyowner
stringThe personhood product, peopl.<tld>: the owner a host lists the key under.
ring
RingLocationinterface PlayerIndicesResult
Properties
at
BlockSnapshotindices
number[] | nullOne index per round, or null when the player holds no seat in the roster.
interface PlayerRecord
A player record in Game.Players, present from the first sign-up until archival.
Properties
registered
booleanSigned up for the current game.
interface PlayerWatchChain
Properties
individuality
{ query: { Game: { Players: { watchValue: (key: PlayerKey, options: WatchAt) => WatchedValue<{ registered: boolean } | undefined> } } } }interface RawAccountAlias
AccountToAlias, narrowed to the contextual alias the read keys on.
Properties
ca
{ alias: string }interface RawActiveEvent
The raw Airdrop.Events value, narrowed to what the domain reads.
Extra fields on the actual value are accepted — this is a structural type, not an exhaustive record of the storage entry.
Properties
id
stringinfo
RawAirdropEventInfosource
stringstatus
RawAirdropStatusinterface RawAirdropEventInfo
The raw EventInfo. Every timestamp is a u64 of Unix seconds.
Properties
draw_time
bigintend_time
bigintprize
RawAirdropPrizeregistration_starts
bigintinterface RawAirdropPrize
The raw AirdropPrize, narrowed to the fields the domain carries.
Properties
asset_amount
bigintasset_id
AirdropAssetIdmax_winners
numberwinner_cap
numberinterface RawAirdropStatus
The raw Status enum. The payload is loose on purpose: enumerating eight
variants’ field sets would duplicate the descriptor and catch nothing the
availability rules above miss.
Properties
type
stringvalue
{ claimed?: number; effective_winners?: number; total_participants?: number }interface RawConsumerInfo
The raw Resources.Consumers value, narrowed to the fields we read.
The chain also sends identifier_key, an opaque communication key with no
bearing on names. Extra fields on the actual value are accepted; this is a
structural type, not an exhaustive record of the storage entry.
Properties
credibility
{ type: string; value?: { alias: string; demoted: boolean; last_update: bigint } }PAPI’s encoding of the pallet’s Credibility enum: variant name in type,
payload in value. Either Lite, which has no payload, or Person.
full_username
Uint8Array<ArrayBufferLike>lite_username
Uint8Arrayinterface RawGameAirdrop
One raw GameAirdrop from a schedule.
Properties
claim_window
numberdraw_offset
numberprize
RawAirdropPrizeinterface RawGameInfo
The raw Game.Game value, narrowed to the fields the domain carries.
Properties
airdrops_scheduled
numbergame_date
numberindex
numbermax_group_size
numberpending_attendance
numberregistration_ends
numberreport_ends
numberrounds
numbershuffle_deadline
numberstate
RawGameStateinterface RawGameSchedule
One raw GameSchedule from the Game.GameSchedules list.
Properties
airdrops
RawGameAirdrop[]game_play_time
numbermax_group_size
numberrounds
numberinterface RawGameState
The raw GameState enum. Only the player count is read from its payload.
Properties
type
stringvalue
unknowninterface RawLiteAliasBinding
PeopleLite.AccountToAlias, the alias binding the signed leg dispatches on.
ca.context is read as well as ca.alias: a binding in any context other
than the chain’s score context does not satisfy the game’s origin check.
Properties
ca
{ alias: string; context: string }The contextual alias itself, both halves as 0x hex.
revision
numberRing revision the binding was proven at.
ring
numberRing the alias belongs to.
interface RawLiteRingMembership
One Members.Members entry, narrowed to the discriminant. Only Included
means the key sits in a built ring and a proof against it will verify.
Properties
type
stringinterface RawParticipant
The raw Score.Participants value, narrowed to the fields the domain reads.
The chain also sends credit and cashed_out. Both are deliberately absent:
they are game-economy fields with no bearing on membership. Extra
fields on the actual value are accepted — this is a structural type, not an
exhaustive record of the storage entry.
Properties
attendance_history
numberhas_ever_reached_personhood
booleanlast_attended_game
numberreached_personhood
booleanrecognition
RawRecognitionscore
numberstreak
RawStreakinterface RawPeopleAccountAlias
People.AccountToAlias, as stored.
Properties
ca
{ alias: string; context: string }revision
numberring
numberinterface RawPhaseDurations
The raw PhaseDurationValues, from storage or from the runtime constant.
Properties
player_process
numberpost_shuffle_margin
numberregistration
numberreporting
numbershuffle
numberinterface RawRecognition
The raw recognition enum as PAPI decodes it:
Enum<{ ExternallyRecognized; NotRecognized; Suspended: bigint; Recognized: bigint }>.
The payload is a revision id on two of the four variants and absent on the other two. The domain does not carry it.
Properties
type
stringvalue
bigintinterface RawStreak
The raw streak enum as PAPI decodes it: Enum<{ Attended: u32; Absent: u32 }>.
Properties
type
stringvalue
numberinterface RawSubmitChain
Where the bind’s finished, unsigned bytes go out: PAPI’s submitAndWatch.
Properties
raw
{ individuality: { submitAndWatch: unknown } }interface ReadAirdropDrawOptions
Options for readAirdropDraw.
Properties
at
BlockAtThe block to read at, as PAPI’s at: "finalized", the default, "best"
to follow a best-block watch without waiting for finality, or a snapshot
another read already pinned.
eventId
stringThe 32-byte event id, 0x-prefixed. Derive it with gameAirdropEventId
or peopleAirdropsEventId — no storage entry lists it.
registrant
AirdropRegistrantWhose outcome to look up. Omit it to read the draw itself without asking
about anyone, which returns outcome: { tag: "Unchecked" } rather than a
false that would read as “did not win”.
signal
AbortSignalForwarded into every underlying pull, so an aborted caller stops the whole batch. No deadline is applied here — that belongs to the caller.
interface ReadClaimEligibilityOptions
Options for readClaimEligibility.
Extends: ClaimTarget
Properties
now
numberUnix seconds; defaults to the device clock. See ClaimInputs.now.
signal
AbortSignalinterface ReadCommunicationIdentifierOptions
Options for readCommunicationIdentifier.
Properties
account
stringSS58. Only accounts register one, an alias never does.
signal
AbortSignalinterface ReadCreditCandidatesOptions
Options for readCreditCandidates.
Properties
attestee
PlayerKeysignal
AbortSignalinterface ReadCurrentGameOptions
Options for readCurrentGame.
Properties
players
readonly AirdropRegistrant[]Whose registration to read, at the same block as the game. One person is
keyed twice on chain — by account and, once recognized, by alias — so pass
every key the caller holds; any hit answers Registered. Requires a chain
that also satisfies GamePlayersChain.
signal
AbortSignalForwarded into every underlying pull, so an aborted caller stops the whole batch. No deadline is applied here — that belongs to the caller.
interface ReadGameAirdropEventIdsOptions
Options for readGameAirdropEventIds.
Properties
airdropsScheduled
numberGame.Game.airdrops_scheduled, readable only while the game is current —
capture it then, because a past game’s count is unrecoverable. Probing ids
upward cannot tell a cleaned-up draw from one never scheduled.
gameIndex
numberThe game the draws belong to.
interface ReadGameSeatOptions
Options for readGameSeat.
Properties
account
stringSS58. The game account, dim2.<tld> at GAME_ACCOUNT_INDEX.
at
BlockAtDefaults to "best", the block a sign-up is validated against.
bound
booleanSee SeatFacts.bound.
feeHeadroom
numberDefaults to DEFAULT_FEE_HEADROOM.
litePerson
booleanSee SeatFacts.litePerson.
signal
AbortSignaltld
stringThe network’s DotNS TLD, such as "paseo".
interface ReadGameSignUpRequirementOptions
Options for readGameSignUpRequirement.
Properties
at
BlockAtThe block to read at, as PAPI’s at: "finalized", the default, "best"
to follow a best-block watch without waiting for finality, or a snapshot
another read already pinned.
keyType
"sr25519" | "ed25519" | "ecdsa"Only "sr25519" can mint Account VRFs, and no chain read reveals the
scheme. Pass it for a NotSr25519 blocker, omit it and the check is yours.
now
numberUnix seconds; defaults to the device clock.
registrant
AirdropRegistrantKeys both reads, and must be the identity that will sign.
signal
AbortSignalinterface ReadGroupMembersOptions
Options for readGroupMembers.
Properties
maxGroupSize
numberownIndex
numberThe index of the player whose group to read, in that round.
playerCount
numberFrom CurrentGame.playerCount.
round
numbersignal
AbortSignalinterface ReadLiteSignUpRequirementOptions
Options for readLiteSignUpRequirement.
Properties
account
stringThe account the sign-up will be signed by and dispatched for — usually the caller’s playing product account. Keys the alias-binding read here and the registration reads of the account path.
at
BlockAtThe block to read at, as PAPI’s at: "finalized", the default, "best"
to follow a best-block watch without waiting for finality, or a snapshot
another read already pinned.
keyType
"sr25519" | "ed25519" | "ecdsa"Forwarded to the account read’s draw-entry check.
liteMemberKey
Uint8Array<ArrayBufferLike>The 32-byte lite member key (RFC-0022 index 1, from the host’s
registerRingVrfKey against the lite people ring). Pass it for a
NotLiteMember blocker when the key is not an Included ring member;
omit it and the membership check is yours.
now
numberUnix seconds; defaults to the device clock.
signal
AbortSignaltld
stringRequired when the chain publishes no suffix, and wins when it does.
interface ReadPeopleAirdropsOptions
Properties
account
stringThe account People.AccountToAlias is keyed by — the one that signs registrations.
at
BlockAtDefaults to "best": a registration cares about the draws accepting entries now.
signal
AbortSignalinterface ReadPlayerIndicesOptions
Options for readPlayerIndices.
Properties
player
PlayerKeysignal
AbortSignalinterface ReadPrizeStatusOptions
Options for readPrizeStatus.
Properties
game
CapturedGameA game the caller already knows, for claiming after it ended. Supplying it
skips the game read — four fewer reads, so game on the result is null
even if this index is the running one.
registrant
AirdropRegistrantWhose outcome to report. Omit to read the draws without asking about
anyone, which leaves every outcome Unchecked.
signal
AbortSignalinterface ReadRegistrationEligibilityOptions
Options for readRegistrationEligibility.
Properties
registrant
{ accountAddress: string; tag: "Account" }The account that would sign register; the pallet reads no other key.
signal
AbortSignalinterface ReadScoreContextOptions
Options for readScoreContext.
Properties
signal
AbortSignaltld
stringRequired when the chain publishes no suffix, and wins when it does.
interface ReadSignUpFundsOptions
Options for readSignUpFunds.
Properties
account
stringSS58. The account that will sign and hold the deposit.
at
BlockAtThe block to read at, as PAPI’s at: "finalized", the default, "best"
to follow a best-block watch without waiting for finality, or a snapshot
another read already pinned.
signal
AbortSignaltx
FeeEstimableThe sign-up transaction as built, for example by signUpWithAccountTx.
Omit it and estimatedFee is null. Placeholder VRFs of the right width cost
the same as real ones, so the funds can be checked before any is minted.
interface RegisterChain
The Score.register call, typed structurally so the package needs no
descriptor dependency. Matched by hand against the previewnet descriptors on
2026-08-31:
Score.register: TxDescriptor<{ key?: [SizedHex<32>, SizedHex<64>] }>Properties
individuality
{ tx: { Score: { register: unknown } } }interface RegisterForGameOptions
Options for registerForGame.
Properties
drawWait
DrawWaitOptionsfeeHeadroom
numberPassed to readGameSeat.
identifierKey
Uint8ArrayCommunicationIdentifier: the 65-byte P-256 key co-players reach this player with.
seat
GameSeatA seat read moments ago, to skip reading it again. Never pass a cached one on a retry.
signal
AbortSignalStops the flow up to the broadcast; after it, the sign-up may still land.
tld
stringThe network’s DotNS TLD, such as "paseo".
waitFor
"finalized" | "best-block"When the sign-up counts as done. Default "best-block"; "finalized" waits for finality.
Methods
onDraws
onDraws(draws: DrawOutcome): voidonSeat
onSeat(seat: GameSeat): voidonStage
onStage(stage: GameRegistrationStage): voidinterface RegisterPersonhoodOptions
Options for registerPersonhoodTx.
Properties
memberKey
Uint8ArrayThe full member key, 32 bytes: registerRingVrfKey(Index(0), peopleRing)
from the personhood product’s host session. Opaque here — this package
never mints it.
proofOfOwnership
Uint8ArrayA plain Bandersnatch signature by that key over
registerMessage(account), 64 bytes: ringVrfSign from the same
session. account must be the account that will sign the transaction,
or the chain answers InvalidProofOfOwnership.
interface RegistrationEligibility
A participant’s standing against the registration guards, at one pinned block.
Properties
at
BlockSnapshotparticipant
PersonhoodParticipant | nullnull for an account Score has never seen.
personhoodThreshold
numberScore.PersonhoodThreshold at the same block. A u8, but u32 on devnet.
readyToRegister
booleanreadyToRegister over the two fields above.
interface RegistrationEligibilityChain
The two reads readRegistrationEligibility folds. Matched by hand
against the previewnet descriptors on 2026-08-31:
Score.Participants: StorageDescriptor<[Key: AccountOrPerson], Participant, true, never>
Score.PersonhoodThreshold: StorageDescriptor<[], number, false, never>PersonhoodThreshold is a storage item, not a constant: the runtime
recalculates it from a population-tiered schedule at the start of each report
session, so it can move under a participant mid-season — which is why both
reads are pinned to one block.
Extends: PinnedChain
Properties
individuality
{ query: { Score: { Participants: { getValue: (key: PlayerKey, options: ReadAt) => Promise<RawParticipant | undefined> }; PersonhoodThreshold: { getValue: unknown } } } }interface ReportChain
Structural, so a test double satisfies it. Matched by hand against the paseo descriptors on 2026-09-25:
Game.report: TxDescriptor<{ full_report: Array<Array<Enum<{ Person, NotPerson }>>> }>
Game.offboard: TxDescriptor<undefined>Properties
individuality
{ tx: { Game: { offboard: unknown; report: unknown } } }interface ReportOptions
Options for reportTx.
Properties
fullReport
readonly readonly ReportVote[][]One entry per round of the game, exactly rounds of them. Each holds a vote per
co-player in the group of the reporter that round, in group order, which is
ascending player index, with the reporter left out. A round that does not match
the real group fails with Game.InvalidReport.
interface RingLocation
Where a ring lives: a chain, and a junction path addressing the ring on it.
Structurally compatible with the host’s RingLocation, and declared here
rather than imported so this package needs no dependency on
@parity/product-sdk-host. Same approach as RingVRFProof.
Properties
chainId
`0x${string}`Genesis hash of the chain hosting the ring.
junctions
{ tag: "PalletInstance"; value: number } | { tag: "CollectionId"; value: `0x${string}` }[]Path addressing the ring within the chain.
interface RingVRFProof
A ring VRF proof and the values the chain needs to verify it.
Structurally compatible with the host’s RingVRFProof, and declared here
rather than imported so this package needs no dependency on
@parity/product-sdk-host. Same approach as IndividualityChain, and the
umbrella package asserts the two stay compatible at compile time.
Properties
contextualAlias
{ alias: Uint8Array; context: Uint8Array }The alias the proof commits to, and the 32-byte context it is bound to.
proof
Uint8ArrayRaw ring VRF proof bytes.
ringIndex
numberIndex of the ring the proof was generated against.
ringRevision
numberRevision of that ring at generation time.
interface RosterChain
Structural, so a test double satisfies it. Matched by hand against the paseo descriptors on 2026-09-25:
Game.PlayerToIndex: StorageDescriptor<[Key: AccountOrPerson], Array<number>, true, never>
Game.IndexToPlayer: StorageDescriptor<[Key: [number, number]], AccountOrPerson, true, never>
Game.CommunicationIdentifiers: StorageDescriptor<[Key: SS58String], SizedHex<65>, true, never>Extends: PinnedChain
Properties
individuality
{ query: { Game: { CommunicationIdentifiers: { getValue: unknown }; IndexToPlayer: { getValues: (keys: [[number, number]][], options: ReadAt) => Promise<PlayerKey | undefined[]> }; PlayerToIndex: { getValue: (key: PlayerKey, options: ReadAt) => Promise<number[] | undefined> } } } }interface ScoreContextChain
The published context every score proof must be minted in.
Separate from the suffix contracts because merging them needs optional members, which constrain nothing structurally and blind the umbrella guard.
Matched by hand against the previewnet descriptors on 2026-08-31:
Score.score_context: PlainDescriptor<SizedHex<32>>Properties
individuality
{ constants: { Score: { score_context: unknown } } }interface Seat
A route, and whether it can be pressed now.
Properties
path
SeatPathready
booleanFalse only while the free route’s bind has not landed.
interface SeatFacts
What the chain and the host say about the player.
Properties
blockers
readonly LiteSignUpBlocker[]The blockers of readLiteSignUpRequirement for the game account.
bound
booleanThis product’s own bind of the account sits in a best block. A read at
the finalized block trails it by a few blocks and still says
AliasNotBound about a seat that is bound.
free
bigintThe account’s free balance.
litePerson
booleanThe host holds a lite-personhood key for this person, and nothing has closed the lite route for the session (a bind refused for good does).
required
bigintWhat the deposit route needs up front. See seatRequired.
interface SignUpChain
The sign-up call, plus the reads that decide what it may carry. Composed with
GameChain, which supplies the game. Matched by hand against the paseo
descriptors on 2026-08-21.
Extends: PinnedChain
Properties
individuality
{ constants: { Game: { airdrop_event_id_base: unknown } }; query: { Game: { Players: { getValue: (key: PlayerKey, options: ReadAt) => Promise<{ registered: boolean } | undefined> } }; Score: { Participants: { getValue: (key: PlayerKey, options: ReadAt) => Promise<RawParticipant | undefined> } } }; tx: { Game: { sign_up_with_account: unknown } } }interface SignUpFunds
The parts of what a sign-up costs, in the smallest unit of the native token.
How much headroom to demand on top is product policy, so no total is given.
Properties
at
BlockSnapshotdecimals
number | nullnull when the chain spec does not publish it.
deposit
bigintHeld from a new or archived player at sign-up. A returning player owes none, and an existing deposit keeps the amount it was created with.
estimatedFee
bigint | nullCharged up front and refunded on success, so the account needs it to start
with. Nothing under withScoreParticipant. PAPI estimates it at the latest
finalized block, which can be newer than at.
free
bigintThe raw free balance, which is more than a sign-up can spend.
The fee cannot come out of frozen funds, and neither the fee nor the deposit
may take the account below the existential deposit. So a check that free
covers deposit + estimatedFee can pass while the sign-up fails.
symbol
string | nullinterface SignUpSubmitOptions
Options the flow hands the submit capability.
Properties
onBroadcast
() => voidCalled once the transaction is on the wire, for an optimistic UI.
signal
AbortSignalThe caller’s abort. The flow already drops a late signature; a submit that can stop sooner should.
waitFor
"finalized" | "best-block"interface SignUpTransaction
A built sign-up call, as PAPI 3 returns it: fee-estimable and submittable.
Extends: FeeEstimable
Methods
createSubmitAndWatch
createSubmitAndWatch(signer: CommonSignerTxCreator): TxWatchinterface SignUpWithAccountOptions
Options for signUpWithAccountTx.
Properties
airdrops
AccountVrfSignature[] | AliasAirdropVrfsOmit to enter no draw. Count must equal airdropsScheduled: a list
of account VRFs from mintAccountAirdropVrfs, or the alias arm from
mintAliasAirdropVrfs. Which one is the chain’s choice, read from
GameSignUpRequirement.variant; the other is rejected on chain.
airdropsScheduled
numberFrom GameSignUpRequirement, checked against airdrops when both are
given. A mismatch fails the whole sign-up on chain with the deposit taken,
and is reachable by re-reading the requirement between minting and building.
identifierKey
Uint8ArrayCommunicationIdentifier, exactly 65 bytes. Stored against the account and
never interpreted by the chain; it is how co-players reach each other.
interface SignUpWithLiteInviteOptions
Options for signUpWithLiteInviteTx.
Properties
account
stringThe account to sign up — a call argument here, unlike the account
sign-up where the signer implies it. It must also be the account that
signs the transaction: the extension resolves the alias from the signer,
and LiteInvites is checked against this argument.
airdrops
AccountVrfSignature[] | AliasAirdropVrfsOmit to enter no draw. Count must equal airdropsScheduled: account
VRFs, or the alias arm for a recognized player, as signUpWithAccountTx.
airdropsScheduled
numberFrom LiteSignUpRequirement, checked against airdrops when both
are given — the same guard as the account sign-up, for the same reason.
identifierKey
Uint8ArrayCommunicationIdentifier, exactly 65 bytes. Rewritten on every sign-up,
so pass the key whose private half the playing product holds now.
interface TimestampChain
Timestamp.Now: the chain’s clock, which registration closes by.
Properties
individuality
{ query: { Timestamp: { Now: { getValue: unknown } } } }interface TxWatch
A transaction watch, as PAPI and tx both give one. The observer’s members are
methods so they compare bivariantly, as tx’s type needs.
Methods
subscribe
subscribe(observer: { complete?: unknown; error: unknown; next: unknown }): { unsubscribe: unknown }interface TxWatchEvent
One event of a transaction watch, in the fields this module reads.
Properties
dispatchError
unknownok
booleantype
stringinterface VrfTranscript
Properties
items
VrfTranscriptItem[]domain then signer. The order is part of the message.
label
Uint8Arrayinterface VrfTranscriptItem
Merlin append_message(label, value), as the host’s signVrf takes it.
Properties
label
Uint8Arrayvalue
Uint8Arrayinterface WatchAt
Options every watch takes: only the best block, so a change shows before finality.
Properties
at
"best"interface WatchedBlock
The block a watched value was read at, which is a best block, not a finalized one.
Properties
blockHash
stringblockNumber
numberinterface WatchedValue
A PAPI watchValue observable, narrowed to the one method a watch calls.
Methods
subscribe
subscribe(observer: { error: (error: unknown) => void; next: (emission: { block: { hash: string; number: number }; value: Value }) => void }): { unsubscribe: unknown }interface WatchPlayerOptions
Options for watchPlayer and watchParticipant.
Properties
player
PlayerKeyType Aliases
type AirdropOutcome
Whether a registrant won. Unchecked exists so “we did not ask” cannot be
mistaken for “did not win” — a false there would be a claim the read never
made.
type AirdropOutcome = { tag: "Unchecked" } | { tag: "NotWon" } | { tag: "Won"; ticket: string }type AirdropPhase
The phase a product renders. Gone is not a chain status but the row’s absence
— the steady state for every past draw. It is not proof a draw happened: an id
that was never scheduled answers identically, and the chain cannot tell them
apart.
type AirdropPhase = "Upcoming" | "Registering" | "Drawing" | "Claiming" | "Settling" | "Gone"type AirdropRegistrant
Which identity entered a draw. Not the player’s choice on the game path: the
chain picks Alias for a recognized person and Account for everyone else.
type AirdropRegistrant = { accountAddress: string; tag: "Account" } | { alias: string; tag: "Alias" }type AirdropStatusTag
The chain’s own Status, kept alongside AirdropPhase because the
collapse is lossy: a product renders one spinner for AwaitingEntropy and
DrawWinners, but someone debugging a stalled draw needs to know which.
type AirdropStatusTag = "Scheduled" | "Registering" | "AwaitingEntropy" | "DrawWinners" | "Claiming" | "ClearingRegistrations" | "ClearingWinners" | "Finalizing"type AirdropVrfVariant
Which variant the chain demands of this player. Read it, never choose it.
type AirdropVrfVariant = "Account" | "Alias"type AliasAirdropProofSigner
A People-ring proof over message in context.
Wire this to AccountsProvider.createRingVRFProof(keyHandle, context, ring, message) with the People member key ((peopl.<tld>, Index 0); list it with
listRingVrfKeys first, keys register lazily) and peopleRing(genesis).
The host grants or refuses the key per product; a refusal rejects here.
Neither argument is the caller’s to choose. The context is the draw’s and the message is the registration entry the chain verifies the proof against.
type AliasAirdropProofSigner = (context: AliasDrawProofContext, message: Uint8Array) => Promise<RingVRFProof>type AsPersonInfo
Which person origin the transaction should run under.
Only the alias variants are here. AsPersonalIdentityWithProof needs a raw
sr25519 signature over the implication hash, which no host call currently
produces, and AsPersonalIdentityWithAccount has no known consumer.
type AsPersonInfo = { tag: "AliasWithAccount" } | { createProof: CreateRingVRFProof; tag: "AliasWithProof" } | { createProof: CreateRingVRFProof; tag: "AliasWithAccountRevised" }type BindGameSeatOutcome
What bindGameSeat did.
type BindGameSeatOutcome = "bound" | "already-bound"type BlockAt
The block a read addresses, as PAPI’s at does: "finalized", the default,
"best", or a snapshot another read already pinned, so several reads share
one block.
type BlockAt = "finalized" | "best" | BlockSnapshottype ClaimBlocker
Why a prize cannot be claimed. Several can hold at once, so
ClaimEligibility carries a list rather than the first one found — a UI
that says “not recognized” while the window has also closed sends the player
to fix the wrong thing.
type ClaimBlocker = { tag: "NotAParticipant" } | { tag: "NotRecognized" } | { tag: "Suspended" } | { lastAttendedGame: number | null; tag: "DidNotAttendThisGame" } | { phase: AirdropPhase; tag: "DrawNotClaiming" } | { endTime: number; tag: "ClaimWindowClosed" } | { tag: "PrizeAssetDisabled" } | { tag: "NoPrize" } | { tag: "OutcomeUnchecked" }type ClaimOutcome
Whether a submitted claim reached the chain, re-read rather than watched. A
successful claim removes the Winners row, so the absence of a ticket that was
there before is the confirmation — recoverable after a reload, which a
subscription is not.
type ClaimOutcome = { at: FinalizedSnapshot; tag: "Claimed" } | { at: FinalizedSnapshot; tag: "Pending"; ticket: string } | { at: FinalizedSnapshot; phase: AirdropPhase; tag: "Unknown" }type ContextSuffix
The RFC-0024 context-suffix selector: a plain index, or 32 raw bytes. The same selector RFC-0022 uses for a product account, under a name that reads right at a proof-context call site.
type ContextSuffix = DerivationIndextype CreateRingVRFProof
Produce a ring VRF proof over message.
Wire this to SignerManager.createRingVRFProof(keyHandle, context, location, message), or to any other call that returns a proof for the context the chain
expects.
The message is computed by the wrapping signer and must not be chosen by the caller. It is blake2-256 of the call implication, which depends on the nonce, the era, the tip and every other extension after the one being filled. A proof over anything else fails on chain as a bad proof.
The context is taken from the returned proof, not from the request, so whichever call mints the proof decides it.
type CreateRingVRFProof = (message: Uint8Array) => Promise<RingVRFProof>type CreditCandidatesChain
RosterChain plus the game, which readCreditCandidates reads at the same block.
type CreditCandidatesChain = RosterChain & { individuality: { query: { Game: { Game: { getValue: unknown } } } } }type CurrentGameResult
type CurrentGameResult = { at: FinalizedSnapshot; durations: GamePhaseDurations; game: CurrentGame; registration: PlayerRegistration; tag: "Running"; upcoming: GameSchedulePreview[] } | { at: FinalizedSnapshot; durations: GamePhaseDurations; lastGameIndex: number | null; tag: "BetweenGames"; upcoming: GameSchedulePreview[] }type DrawSkipKind
Why a sign-up went out without its draw entries.
type DrawSkipKind = "not-open" | "closed" | "closing" | "read-failed" | "signature" | "verified-person" | "refused"type FinalizedBlockSource
Deprecated. Renamed
BlockSource, which a read givenat: "best"also needs.
type FinalizedBlockSource = BlockSourcetype FinalizedSnapshot
The block a read pinned itself, which is the latest finalized one unless the caller passed at.
type FinalizedSnapshot = BlockSnapshottype GamePhase
The phase a game is in, named as the chain’s GameState variant. Their payloads
are not decoded — offchain-worker cursors and sub-step markers, not anything a
product renders; pendingAttendance is the progress signal that is. The one
exception is the player count, see CurrentGame.playerCount.
type GamePhase = "Registration" | "Shuffle" | "Reporting" | "PlayerProcess" | "Cancelling"type GameRegistrationChain
What registerForGame reads and submits through; fromPapi gives one.
type GameRegistrationChain = SeatBindParts<SignUpTransaction> & SignUpFundsChain & AirdropChain & TimestampChaintype GameRegistrationCode
A failure’s code: one of GameRegistrationOwnCode, or the chain’s own
error name (NoRegistration, AccountInUse, Custom(172), a blocker such as
AliasBoundElsewhere). Never free text, so it can be grouped and compared;
what the error said rides along as the error’s message and cause.
type GameRegistrationCode = GameRegistrationOwnCode | string & objecttype GameRegistrationOwnCode
The codes this package sets itself, beside the chain’s own error names.
Timeout: no answer in time, from the watch or the host.Aborted: the caller’s signal.SigningRejected: the player declined to sign.HostRefused: the host turned a call down (a grant, a proof, a key).Network: the connection or the block subscription dropped.Dropped: the transaction left the pool without a block holding it.InvalidSignUp: the sign-up call could not be built.StaleAliasNeedsLiteKey,NoPersonhoodProver: nothing here can make a proof the step needs.Unknown: anything else; the error’smessageandcausesay what.
type GameRegistrationOwnCode = "Timeout" | "Aborted" | "SigningRejected" | "HostRefused" | "Network" | "Dropped" | "InvalidSignUp" | "StaleAliasNeedsLiteKey" | "NoPersonhoodProver" | "Unknown"type GameRegistrationStage
Where registerForGame is, for a product’s progress UI: a step, or the broadcast.
type GameRegistrationStage = GameRegistrationStep | "broadcast"type GameRegistrationStep
A step of registerForGame.
type GameRegistrationStep = "seat" | "bind" | "draws" | "sign"type GameSeatBindChain
What bindGameSeat reads and submits through.
type GameSeatBindChain = SeatBindParts<unknown>type GameSeatBindRefusal
Why a bind did not put the person’s binding on the game account.
type GameSeatBindRefusal = "pinned-elsewhere" | "dead-end" | "no-proof-context" | "no-lite-key" | "rejected"type GameSeatChain
What readGameSeat reads.
type GameSeatChain = GameChain & SignUpChain<FeeEstimable> & ScoreContextChain & LiteSignUpChain & SignUpFundsChain & TimestampChaintype LiteAliasInfo
Which lite-person origin the transaction should run under.
AsLitePerson, the fourth variant on chain, is deliberately absent: it
authenticates the canonical lite account itself, which stays in host
custody, so no product-side signer can ever be that origin.
type LiteAliasInfo = { tag: "AliasWithAccount" } | { createProof: CreateRingVRFProof; tag: "AliasWithProof" } | { createProof: CreateRingVRFProof; tag: "AliasWithAccountRevised" }type LiteSignUpBlocker
Why the free lite sign-up (Game.sign_up_with_account_lite_invite) cannot go
ahead: every account-path blocker, plus the lite-only gates.
A parallel union rather than new arms on SignUpBlocker, on purpose:
widening that union would break every existing exhaustive consumer of the
account read the moment this package is upgraded, for a path they never
call. readGameSignUpRequirement keeps returning the narrow union;
readLiteSignUpRequirement returns this one, and a consumer of both narrows
once.
Unlike the account read’s draw-only arms, every lite arm blocks the sign-up
itself. AnotherAccountInvited and AccountIsALitePerson are permanent for
the account they name; ContextNotProductDerived is about the environment,
not the account.
type LiteSignUpBlocker = SignUpBlocker | { tag: "AliasNotBound" } | { tag: "AliasBoundElsewhere" } | { invited: string; tag: "AnotherAccountInvited" } | { tag: "AccountIsALitePerson" } | { tag: "NotLiteMember" } | { tag: "ContextNotProductDerived" } | { tag: "AlreadyPlaying" } | { tag: "AccountIsAStatementAccount" } | { tag: "StaleAlias" }type PeopleAirdropsBinding
What People.AccountToAlias says about one account, against the airdrops context.
type PeopleAirdropsBinding = { tag: "Unbound" } | { context: string; tag: "OtherContext" } | { alias: string; revision: number; ring: number; tag: "Bound" }type PeopleAirdropsSigning
Which withAsPerson origin a PeopleAirdrops call can ride for this account now.
type PeopleAirdropsSigning = { alias: string; tag: "Bound" } | { alias: string; aliasContext: string; ring: number; tag: "Revised" } | { airdropsContext: string; tag: "Unbound" } | { context: string; tag: "OtherContext" } | { ring: number; tag: "RingUnavailable" }type PersonhoodContextName
type PersonhoodContextName = keyof typeof PERSONHOOD_CONTEXT_INDEXtype PersonhoodKey
Which personhood key a proof is made with.
type PersonhoodKey = "lite" | "full"type PersonhoodProofContext
A ring-VRF proof context, as a host’s createRingVRFProof takes it.
type PersonhoodProofContext = { productId: string; suffix: { tag: "Index"; value: number } } | AliasDrawProofContexttype PersonhoodResult
The outcome of a personhood read.
UsernameUnowned is a first-class success value: the chain was queried and
answered that nobody owns that username. It is not an error channel.
type PersonhoodResult = { at: FinalizedSnapshot; tag: "UsernameUnowned" } | { accountAddress: string; alias: string | null; at: FinalizedSnapshot; metrics: PersonhoodMetrics; participant: PersonhoodParticipant | null; state: PersonhoodState; tag: "Resolved" }type PersonhoodState
A person’s membership standing, derived from one pinned snapshot.
Ordered here roughly by progression, not by precedence. The derivation rules are the authority on precedence — in particular a participant record always beats Lite personhood, and external recognition is permanent.
type PersonhoodState = { tag: "NotEnrolled" } | { tag: "Lite" } | { gamesRemaining: number; personhoodThreshold: number; score: number; tag: "Candidate" } | { tag: "MembershipReady" } | { activeWeeks: number; lastAttendedGame: number | null; tag: "Member" } | { allowedMisses: number; lastAttendedGame: number | null; misses: number; tag: "Caution"; window: number } | { tag: "Suspended" }type PlayerKey
type PlayerKey = { type: "Account"; value: string } | { type: "Person"; value: string }type PlayerRegistration
Whether the players named in ReadCurrentGameOptions.players are in the
running game. One identity is keyed twice on chain (account and alias), so the
question is asked per key and answered once: any hit is Registered.
Unknown exists so a failed key read cannot be mistaken for “not registered”
— a stale account miss must not hide a person-side registration. Unchecked
exists so “we did not ask” cannot be mistaken for either.
type PlayerRegistration = { tag: "Registered" } | { tag: "NotRegistered" } | { tag: "Unknown" } | { tag: "Unchecked" }type PrizeStatus
The outcome of a prize-status read.
type PrizeStatus = { at: FinalizedSnapshot; lastGameIndex: number | null; tag: "NoGame"; upcoming: GameSchedulePreview[] } | { at: FinalizedSnapshot; drawCountFrom: "chain" | "caller"; draws: AirdropDraw[]; game: CurrentGame | null; gameIndex: number; tag: "Draws" }type PrizeStatusChain
Both halves of the chain surface, since this read spans Game and Airdrop.
type PrizeStatusChain = AirdropChain & GameChaintype RawRegistrationEntry
The raw RegistrationEntry enum, the key Winners is addressed by.
type RawRegistrationEntry = { type: "Alias"; value: { alias: string } } | { type: "Account"; value: { account_id: string } }type RawReportVote
A vote as the pallet Report enum takes it.
type RawReportVote = { type: "Person"; value: undefined } | { type: "NotPerson"; value: undefined }type ReadPersonhoodStateOptions
What to read, and how: a username or an account, and never both.
Two inputs rather than one because a profile or results screen usually holds an account, not a name, and making it look the name up first would be a read this function then throws away.
The rule is enforced at runtime, not by this type. The union below rejects
an object literal that names both fields as strings, and rejects an empty one.
It does not reject { username: maybeName, account: maybeAccount } with both
typed string | undefined, which is the shape a caller writes when the values
come from state: TypeScript checks such a literal property by property against
the union and lets it through. selectInput is what actually holds the
rule, and an ambiguous call is an err result rather than a silent choice.
type ReadPersonhoodStateOptions = { signal?: AbortSignal } & { account?: never; username: string } | { account: string; username?: never }type RegisterForGameOutcome
How registerForGame ended, when it did not fail. Every variant carries its report.
type RegisterForGameOutcome = { draws: DrawOutcome; kind: "registered"; report: GameRegistrationReport; route: SeatRoute } | { kind: "already-registered"; report: GameRegistrationReport } | { kind: "not-open"; report: GameRegistrationReport; seat: GameSeat } | { kind: "unfunded"; missing: bigint; report: GameRegistrationReport; seat: GameSeat }type ReportVote
The judgement of one co-player, who either attended as a person or did not.
type ReportVote = "Person" | "NotPerson"type ScoreContext
The chain’s score context, and whether a host can mint proofs in it.
NotProductDerived is an answer, not a failure — it is the state nextv2 is
in — so it travels on the ok channel, like UsernameUnowned does. Every
proof-building flow must treat it as a hard stop.
A chain that will not say what its suffix is has no variant here; it is rejected at compile time.
type ScoreContext = unknowntype SeatPath
What a product shows: a route, or why none is open to this account.
type SeatPath = SeatRoute | "unfunded"type SeatRoute
The ways a sign-up can actually be submitted.
type SeatRoute = "returning" | "free" | "deposit"type SignUpBlocker
Why a sign-up, or the draw entry inside it, cannot go ahead. A list rather than the first hit: a player told “registration has closed” who is also already registered fixes the wrong thing.
Several of these stop only the draws. GameSignUpRequirement is what
separates the two, not this type.
A tag must name a condition that is true on its own, or it sends the player to fix the wrong thing.
type SignUpBlocker = { tag: "NoGameRunning" } | { phase: GamePhase; tag: "NotInRegistration" } | { registrationEnds: number; tag: "RegistrationEnded" } | { tag: "AlreadyRegistered" } | { tag: "AccountVrfsNeedAnAccount" } | { tag: "NoDrawsScheduled" } | { keyType: string; tag: "NotSr25519" }type SignUpFundsChain
What readSignUpFunds reads. Matched by hand against the paseo descriptors
on 2026-09-25:
Game.PlayDepositAmount: StorageDescriptor<[], bigint, false, never>
System.Account: StorageDescriptor<[Key: SS58String], AccountInfo, false, never>type SignUpFundsChain = PinnedChain & { individuality: { query: { Game: { PlayDepositAmount: { getValue: unknown } }; System: { Account: { getValue: unknown } } } }; raw: { individuality: { getChainSpecData: unknown } } }type SignUpSubmitResult
How a sign-up submission ended, as the submit capability reports it.
type SignUpSubmitResult = { ok: true } | { cause?: unknown; code: GameRegistrationCode; landingUnknown?: boolean; message?: string; ok: false; refused?: boolean }type SubmitSignUp
Signs and submits the built sign-up. The host adapter wraps tx’s submitAndWatch.
type SubmitSignUp = (tx: SignUpTransaction, signer: CommonSignerTxCreator, options: SignUpSubmitOptions) => Promise<SignUpSubmitResult>type UsernameCredibility
A consumer’s standing as the resources pallet records it.
alias is the person alias the pallet stores against the credibility, which
is not the same value as a contextual alias from People.AccountToAlias.
type UsernameCredibility = { tag: "Lite" } | { alias: string; demoted: boolean; lastUpdate: number; tag: "Person" }type WatchErrorHandler
type WatchErrorHandler = (error: ProductIndividualityError) => voidVariables
AIRDROP_VRF_TRANSCRIPT_LABEL
VRF_TRANSCRIPT_LABEL, which is also the domain item’s prefix.
let AIRDROP_VRF_TRANSCRIPT_LABEL: "pop:airdrop" = "pop:airdrop"DEFAULT_FEE_HEADROOM
The fee headroom the deposit route asks for, as a multiple of the estimate.
let DEFAULT_FEE_HEADROOM: 2 = 2FALLBACK_PEOPLE_AIRDROPS_REGISTER_BATCH
Used only when the runtime does not expose MaxRegisterBatch.
let FALLBACK_PEOPLE_AIRDROPS_REGISTER_BATCH: 16 = 16GAME_ACCOUNT_INDEX
The derivation index of the game account: 0, the host’s default product
account (RFC-0022 //product//dim2/0). Every product must use the same one,
because a lite person’s free seat is pinned to a single account for good
(Game.LiteInvites).
let GAME_ACCOUNT_INDEX: 0 = 0GAME_AIRDROP_EVENT_ID_BASE
Game::airdrop_event_id_base() — 27 bytes, the ten trailing spaces included as
part of the value. The pinned expectation; production reads the chain’s copy.
let GAME_AIRDROP_EVENT_ID_BASE: "pop:game:airdrop: " = "pop:game:airdrop: "GAME_PRODUCT_NAME
Game.product_name: the product the game pallet scopes its draws to.
let GAME_PRODUCT_NAME: "dim2" = "dim2"GAME_REGISTRATION_RETRY_MS
How long to wait before the next try, after failures failures in a row:
5 s, 15 s, 45 s, 2 min, then 5 min. Check retryable first.
let GAME_REGISTRATION_RETRY_MS: readonly number[] = ...MAX_GAME_AIRDROPS
Game’s MAX_GAME_AIRDROPS: a game schedules at most this many draws.
let MAX_GAME_AIRDROPS: 16 = 16PEOPLE_AIRDROPS_EVENT_ID_BASE
indiv_pallet_people_airdrops::EVENT_ID_BASE — 24 bytes, four trailing spaces
included. Hardcoded because it never reaches metadata, unlike Game’s; if it
ever gains an extra_constants entry, read that and delete this.
let PEOPLE_AIRDROPS_EVENT_ID_BASE: "pop:people-airdrops: " = "pop:people-airdrops: "PERSONHOOD_CONTEXT_INDEX
The context suffix indices the personhood product owns, mirroring
personhood in individuality/support/src/context.rs.
Only score, peopleLiteAuth and peopleAirdrops are published as runtime
constants; resources and dotnsGateway exist solely as this derivation, so
pinning the published three pins the derivation that produces the other two.
let PERSONHOOD_CONTEXT_INDEX: { readonly dotnsGateway: 3; readonly peopleAirdrops: 4; readonly peopleLiteAuth: 2; readonly resources: 1; readonly score: 0 } = ...PERSONHOOD_PRODUCT_NAME
personhood::PRODUCT_NAME — the DotNS name (TLD excluded) the personhood
product’s contexts derive from, shared by every network.
let PERSONHOOD_PRODUCT_NAME: "peopl" = "peopl"REGISTER_MESSAGE_PREFIX
The pallet’s domain prefix for the proof of ownership in Score.register.
18 bytes of UTF-8, concatenated raw — no separator, no length prefix.
let REGISTER_MESSAGE_PREFIX: "pop register using" = "pop register using"