@parity/product-sdk-individuality
npm install @parity/product-sdk-individualityExports
Classes
| Name | Summary |
|---|---|
AsPersonError | Building an origin-modifying transaction extension — AsPerson or its |
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. |
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. |
derivePersonhoodState() | Derive a person’s membership standing from one pinned snapshot. |
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 |
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, |
litePeopleRing() | The people-lite ring on the chain with genesis genesisHash. |
lookupUsername() | Read the usernames registered for an account, from Resources.Consumers. |
mintAccountAirdropVrfs() | — |
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 |
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 |
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: |
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 |
registerMessage() | "pop register using" ++ account — the 50 bytes the full member key signs. |
registerPersonhoodTx() | Build Score.register(Some((member_key, proof_of_ownership))), unsigned. |
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 |
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. |
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. |
DrawRegistration | One draw’s registration for one identity. |
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 transaction can. |
FinalizedBlockSource | The one raw-client method the pinned reads use. Structural, so PolkadotClient fits. |
FinalizedSnapshot | The finalized block every read in a result was pinned to. |
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 |
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 — |
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. |
NetworkSuffixChain | The network suffix since individuality-community #20. Root can move it between |
PapiIndividualityChain | What fromPapi returns, with the typed API preserved. |
ParticipantWatchChain | — |
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. |
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. |
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 }>. |
ReadAirdropDrawOptions | Options for readAirdropDraw. |
ReadClaimEligibilityOptions | Options for readClaimEligibility. |
ReadCommunicationIdentifierOptions | Options for readCommunicationIdentifier. |
ReadCreditCandidatesOptions | Options for readCreditCandidates. |
ReadCurrentGameOptions | Options for readCurrentGame. |
ReadGameAirdropEventIdsOptions | Options for readGameAirdropEventIds. |
ReadGameSignUpRequirementOptions | Options for readGameSignUpRequirement. |
ReadGroupMembersOptions | Options for readGroupMembers. |
ReadLiteSignUpRequirementOptions | Options for readLiteSignUpRequirement. |
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 |
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. |
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. |
SignUpWithAccountOptions | Options for signUpWithAccountTx. |
SignUpWithLiteInviteOptions | Options for signUpWithLiteInviteTx. |
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. |
AsPersonInfo | Which person origin the transaction should run under. |
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 | — |
GamePhase | The phase a game is in, named as the chain’s GameState variant. Their payloads |
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 |
PersonhoodContextName | — |
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. |
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. |
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 |
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. |
GAME_AIRDROP_EVENT_ID_BASE | Game::airdrop_event_id_base() — 27 bytes, the ten trailing spaces included as |
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 PolkadotSigner.signTx, 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 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.
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): ClaimEligibilityderivePersonhoodState()
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): PersonhoodStatedisplayUsername()
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[]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[]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>>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): stringpeopleRing()
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>>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.
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): booleanregisterMessage()
"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.
reportTx()
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?: FinalizedSnapshot): Promise<ScoreContext>signUpWithAccountTx()
Build Game.sign_up_with_account, unsigned. Pays::No on success, though a new
or archived player still pays a deposit.
No Alias argument: a recognized player needs one that cannot be produced, and
an argument that always fails on chain is worse than none.
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 or signature, 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: PolkadotSigner, info: AsPersonInfo): PolkadotSignerParameters
signer: the signer to wrap, e.g. fromAccountsProvider.getProductAccountSigner.info: which person origin to use, and where the proof comes from.
Returns
a PolkadotSigner 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: PolkadotSigner, info: LiteAliasInfo): PolkadotSignerParameters
signer: the signer to wrap, e.g. fromAccountsProvider.getProductAccountSigner.info: which lite-person origin to use, and where the proof comes from.
Returns
a PolkadotSigner 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: PolkadotSigner): PolkadotSignerParameters
signer: the signer to wrap, e.g. fromAccountsProvider.getProductAccountSigner.
Returns
a PolkadotSigner 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
FinalizedSnapshotThe 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 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
FinalizedSnapshoteventId
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
FinalizedSnapshotidentifier
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
FinalizedSnapshotcandidates
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 DrawRegistration
One draw’s registration for one identity.
Properties
at
FinalizedSnapshotentriesScanned
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 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 transaction can.
Methods
getEstimatedFees
getEstimatedFees(from: string, options: { customSignedExtensions: Record<string, { value: unknown }>; nonce: number }): Promise<bigint>interface FinalizedBlockSource
The one raw-client method the pinned reads use. Structural, so PolkadotClient fits.
Methods
getFinalizedBlock
getFinalizedBlock(): Promise<{ hash: string; number: number }>interface FinalizedSnapshot
The finalized block every read in a result was pinned to.
Properties
blockHash
stringblockNumber
numberinterface 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 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 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
FinalizedSnapshotblockers
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
FinalizedSnapshotmembers
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 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 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 PlayerIndicesResult
Properties
at
FinalizedSnapshotindices
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 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 ReadAirdropDrawOptions
Options for readAirdropDraw.
Properties
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 ReadGameSignUpRequirementOptions
Options for readGameSignUpRequirement.
Properties
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.
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 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.
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 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
FinalizedSnapshotparticipant
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 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
FinalizedSnapshotdecimals
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 SignUpWithAccountOptions
Options for signUpWithAccountTx.
Properties
airdrops
AccountVrfSignature[]Omit to enter no draw. Length must equal airdropsScheduled.
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[]Omit to enter no draw. Length must equal airdropsScheduled.
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 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 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 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 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 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 PersonhoodContextName
type PersonhoodContextName = keyof typeof PERSONHOOD_CONTEXT_INDEXtype 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 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 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: "AliasVrfsUnavailable" } | { 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 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"GAME_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: "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"