@ledgerhq/coin-tezos
Version:
333 lines (314 loc) • 10.5 kB
text/typescript
// SPDX-FileCopyrightText: © 2026 LEDGER SAS
// SPDX-License-Identifier: Apache-2.0
/**
* Fields common to tzkt account types that own a manager key (`user` and `delegate`):
* these types carry manager-key metadata — an on-chain reveal state (`revealed`), a counter,
* a balance, and (un)staked balances, plus the public key once it has been revealed.
* `publicKey` is optional: an unrevealed account (`revealed: false`) has not published one yet.
* See https://api.tzkt.io/#operation/Accounts_GetByAddress (schemas `User` / `Delegate`).
*/
type APIManagerAccountBase = {
address: string
/** Absent until the account is revealed (`revealed: false` → no public key on-chain yet). */
publicKey?: string
revealed: boolean
balance: number
stakedBalance?: number
unstakedBalance?: number
stakingUpdatesCount?: number
counter: number
/**
* The baker this account delegates to, if any. Present on plain wallets that have set a
* delegate. We do not rely on it for registered bakers: a `delegate` account is its own
* baker (self-delegated), and staking logic keys off `type === "delegate"` rather than this
* field, so it's fine whether or not tzkt populates it.
*/
delegate?: {
alias: string
address: string
active: boolean
}
}
/**
* tzkt's `/v1/accounts/{address}` returns a discriminated union on `type` with seven
* variants: `user`, `delegate`, `contract`, `ghost`, `empty`, `rollup`, `smart_rollup`.
* We model only the ones we consume: `empty` (never appeared on-chain) plus the two
* manager-key variants, `user` (plain wallet) and `delegate` (registered baker). A baker
* is reported as `type: "delegate"`, NOT `"user"` — so any manager-key logic must accept
* both (see {@link hasManagerKey}).
*/
export type APIAccount =
| {
type: 'empty'
address: string
counter: number
}
| (APIManagerAccountBase & {
type: 'user'
delegationLevel: number
delegationTime: string
numTransactions: number
firstActivityTime: string
})
| (APIManagerAccountBase & {
// A registered baker. tzkt reports these with `type: "delegate"` (not `"user"`),
// still carrying `revealed`/`publicKey`/`counter`. In practice a delegate is revealed
// (registration is a manager operation, which requires a prior reveal), but we still
// read `revealed` from the payload rather than assuming it.
type: 'delegate'
})
/** tzkt account variants that own a manager key — both `user` and `delegate` qualify. */
export type APIManagerAccount = Extract<APIAccount, { type: 'user' | 'delegate' }>
/**
* True for account *types* that own a manager key and therefore carry the `revealed`,
* `publicKey`, `counter`, and `balance` fields: plain wallets (`user`) and registered bakers
* (`delegate`). This narrows on the account type, not on whether the key is already published —
* it returns true for unrevealed `user` accounts too (check `revealed` separately for that).
* `empty` accounts (and the non-manager `contract` / `ghost` / `rollup` types we don't model)
* do not qualify. Use this instead of a bare `type === "user"` check so baker accounts aren't
* mistaken for non-manager ones.
*/
export function hasManagerKey(account: APIAccount): account is APIManagerAccount {
return account.type === 'user' || account.type === 'delegate'
}
type CommonOperationType = {
id: number
hash?: string
storageFee?: number
allocationFee?: number
bakerFee?: number
timestamp: string
level: number
block: string
gasLimit?: number
storageLimit?: number
status?: 'applied' | 'failed' | 'backtracked' | 'skipped'
}
/**
* Source: https://api.tzkt.io/#operation/Accounts_GetOperations
*/
export type APITransactionType = CommonOperationType & {
type: 'transaction'
amount: number
initiator: { address: string } | undefined | null
sender: { address: string } | undefined | null
target: { address: string } | undefined | null
counter: number
}
export function isAPITransactionType(op: APIOperation): op is APITransactionType {
return op.type === 'transaction'
}
export type APIDelegationType = CommonOperationType & {
type: 'delegation'
amount: number
sender: { address: string } | undefined | null
counter: number
prevDelegate: { address: string } | undefined | null
newDelegate: { address: string } | undefined | null
}
export function isAPIDelegationType(op: APIOperation): op is APIDelegationType {
return op.type === 'delegation'
}
export type APIRevealType = CommonOperationType & {
type: 'reveal'
sender: { address: string } | undefined | null
counter: number
}
export function isAPIRevealType(op: APIOperation): op is APIRevealType {
return op.type === 'reveal'
}
export type APIStakingType = Omit<CommonOperationType, 'block'> & {
type: 'staking'
action: 'stake' | 'unstake' | 'finalize'
/** Present on succeeded ops; failed ops omit `amount` and only carry `requestedAmount`. */
amount?: number
requestedAmount?: number
counter: number
sender: { address: string } | undefined | null
staker?: { address: string } | undefined | null
baker?: { address: string; alias?: string } | undefined | null
stakingUpdatesCount?: number
/**
* `/accounts/{addr}/operations` returns the full block object inline
* (with `.hash` and other fields); `/operations/staking` returns the
* hash as a plain string. Consumers must narrow before reading `.hash`.
*/
block?: string | APIBlock
}
export function isAPIStakingType(op: APIOperation): op is APIStakingType {
return op.type === 'staking'
}
export type APIOriginationType = CommonOperationType & {
type: 'origination'
sender: { address: string } | undefined | null
counter: number
contractBalance: number
originatedContract?: {
address: string
}
}
export function isAPIOriginationType(op: APIOperation): op is APIOriginationType {
return op.type === 'origination'
}
// https://api.tzkt.io/#operation/Accounts_GetOperations
export type AccountsGetOperationsOptions = {
lastId?: number // used as a pagination cursor to fetch more transactions
limit?: number
sort?: 'Descending' | 'Ascending'
// the minimum height of the block the operation is in
'level.ge': number
/** Exclusive upper bound on block level (pagination window). */
'level.lt'?: number
/** Exclusive lower bound on block level (pagination window). */
'level.gt'?: number
}
export type APIOperation =
| APITransactionType
| APIRevealType
| APIDelegationType
| (CommonOperationType & {
type: 'activation'
balance: number
})
| APIOriginationType
| (CommonOperationType & {
type: 'migration'
balanceChange: number
})
| APIStakingType
| (CommonOperationType & {
type: '' // this is to express fact we have others and we need to always filter out others
})
/**
* Unstake request as returned by https://api.tzkt.io/#operation/Staking_GetUnstakeRequests.
* `firstTime`: ISO timestamp the request was opened; the 4-day unlock window starts here.
*/
export type APIUnstakeRequest = {
id: number
cycle: number
baker: { address: string; alias?: string }
staker: { address: string }
firstTime: string
status: 'pending' | 'finalizable' | 'finalized'
/** Net amount actually returnable (mutez), accounting for slashing/rounding. */
actualAmount: number
requestedAmount?: number
}
export type APIBlock = {
cycle: number
level: number
hash: string
timestamp: string
proto: number
payloadRound: number
blockRound: number
validations: number
deposit: number
rewardDelegated: number
rewardStakedOwn: number
rewardStakedEdge: number
rewardStakedShared: number
bonusDelegated: number
bonusStakedOwn: number
bonusStakedEdge: number
bonusStakedShared: number
fees: number
nonceRevealed: boolean
proposer: {
address: string
}
producer: {
address: string
}
software: {
date: string
}
lbToggle: boolean
lbToggleEma: number
aiToggleEma: number
rewardLiquid: number
bonusLiquid: number
reward: number
bonus: number
priority: number
baker: {
address: string
}
lbEscapeVote: boolean
lbEscapeEma: number
/** Hash of the previous block. Not included by default; request via TzKT `select` param if needed. */
prevHash?: string
}
export type TokenTransfersGetOptions = {
limit?: number
sort?: 'Descending' | 'Ascending'
'level.ge'?: number
'level.lt'?: number
'level.gt'?: number
/** Exclusive upper bound on transfer id (TzKT `id.lt`). Used for intra-level pagination when sort is Descending. */
'id.lt'?: number
/** Exclusive lower bound on transfer id (TzKT `id.gt`). Used for intra-level pagination when sort is Ascending. */
'id.gt'?: number
}
/**
* A FA1.2 / FA2 token transfer event returned by `GET /v1/tokens/transfers`.
* https://api.tzkt.io/#operation/Tokens_GetTokenTransfers
*/
export type APITokenTransfer = {
/** Unique transfer identifier (monotonically increasing, usable as cursor). */
id: number
level: number
timestamp: string
token: {
id: number
contract: { address: string }
/** Stringified token ID (FA2 only; "0" for FA1.2). */
tokenId: string
standard: 'fa1.2' | 'fa2'
metadata?: {
name?: string
symbol?: string
decimals?: string
}
}
/** Sender address. Null/undefined for minting events. */
from: { address: string } | undefined | null
/** Receiver address. Null/undefined for burning events. */
to: { address: string } | undefined | null
/** Transfer amount as a decimal string (integer, no magnitude applied). */
amount: string
/**
* The `id` of the `APITransactionType` operation that triggered this transfer.
* Use this to join token transfers back to their parent on-chain operation hash.
* Undefined for implicit/protocol-level transfers.
*/
transactionId?: number
originationId?: number
}
/**
* A FA1.2 / FA2 token balance event returned by `GET /v1/tokens/balances`.
* https://api.tzkt.io/#operation/Tokens_GetTokenBalances
*/
export type APITokenBalance = {
id: number
account: {
address: string
}
token: {
id: number
contract: { address: string; alias?: string }
tokenId: string
standard: 'fa1.2' | 'fa2'
metadata?: {
name?: string
symbol: string
decimals: string
}
}
balance: string
transfersCount: number
firstLevel: number
firstTime: string
lastLevel: number
lastTime: string
}