@vultisig/core-chain 2.19.0 → 2.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/chains/solana/staking/config.d.ts +75 -0
  3. package/dist/chains/solana/staking/config.d.ts.map +1 -0
  4. package/dist/chains/solana/staking/config.js +75 -0
  5. package/dist/chains/solana/staking/config.js.map +1 -0
  6. package/dist/chains/solana/staking/cooldownGate.d.ts +34 -0
  7. package/dist/chains/solana/staking/cooldownGate.d.ts.map +1 -0
  8. package/dist/chains/solana/staking/cooldownGate.js +32 -0
  9. package/dist/chains/solana/staking/cooldownGate.js.map +1 -0
  10. package/dist/chains/solana/staking/metadata/ValidatorMetadataProvider.d.ts +25 -0
  11. package/dist/chains/solana/staking/metadata/ValidatorMetadataProvider.d.ts.map +1 -0
  12. package/dist/chains/solana/staking/metadata/ValidatorMetadataProvider.js +2 -0
  13. package/dist/chains/solana/staking/metadata/ValidatorMetadataProvider.js.map +1 -0
  14. package/dist/chains/solana/staking/metadata/enrichValidators.d.ts +13 -0
  15. package/dist/chains/solana/staking/metadata/enrichValidators.d.ts.map +1 -0
  16. package/dist/chains/solana/staking/metadata/enrichValidators.js +18 -0
  17. package/dist/chains/solana/staking/metadata/enrichValidators.js.map +1 -0
  18. package/dist/chains/solana/staking/metadata/stakewizProvider.d.ts +3 -0
  19. package/dist/chains/solana/staking/metadata/stakewizProvider.d.ts.map +1 -0
  20. package/dist/chains/solana/staking/metadata/stakewizProvider.js +73 -0
  21. package/dist/chains/solana/staking/metadata/stakewizProvider.js.map +1 -0
  22. package/dist/chains/solana/staking/models/stakeAccount.d.ts +102 -0
  23. package/dist/chains/solana/staking/models/stakeAccount.d.ts.map +1 -0
  24. package/dist/chains/solana/staking/models/stakeAccount.js +85 -0
  25. package/dist/chains/solana/staking/models/stakeAccount.js.map +1 -0
  26. package/dist/chains/solana/staking/models/validator.d.ts +62 -0
  27. package/dist/chains/solana/staking/models/validator.d.ts.map +1 -0
  28. package/dist/chains/solana/staking/models/validator.js +34 -0
  29. package/dist/chains/solana/staking/models/validator.js.map +1 -0
  30. package/dist/chains/solana/staking/rpc.d.ts +49 -0
  31. package/dist/chains/solana/staking/rpc.d.ts.map +1 -0
  32. package/dist/chains/solana/staking/rpc.js +112 -0
  33. package/dist/chains/solana/staking/rpc.js.map +1 -0
  34. package/package.json +43 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @vultisig/core-chain
2
2
 
3
+ ## 2.21.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#912](https://github.com/vultisig/vultisig-sdk/pull/912) [`403d5d5`](https://github.com/vultisig/vultisig-sdk/commit/403d5d5f7c7dba3e45cb818899db00f765541ecf) Thanks [@Ehsan-saradar](https://github.com/Ehsan-saradar)! - feat(solana): validator-metadata seam (Stakewiz, swappable)
8
+
9
+ Phase 2 of Solana native staking. Adds a swappable off-chain enrichment seam for
10
+ validator display metadata (name / logo / APY estimate / score) on top of the
11
+ Phase 1 on-chain `getVoteAccounts` rows, under
12
+ `@vultisig/core-chain/chains/solana/staking/metadata`:
13
+
14
+ - `ValidatorMetadataProvider` — provider interface; contract: never throws.
15
+ - `stakewizProvider` — concrete impl over api.stakewiz.com (`apy_estimate`
16
+ percent→fraction, `image`→logo, `wiz_score`→score). Degrades to an empty map
17
+ on any outage / non-OK / parse error so callers fall back to on-chain-only.
18
+ - `enrichValidators` — merges the metadata map onto the validator rows; the
19
+ provider is injectable for tests.
20
+
21
+ ## 2.20.0
22
+
23
+ ### Minor Changes
24
+
25
+ - [#900](https://github.com/vultisig/vultisig-sdk/pull/900) [`9e72781`](https://github.com/vultisig/vultisig-sdk/commit/9e7278125bd8bc722a26ab3a1f91ba1be03054d1) Thanks [@Ehsan-saradar](https://github.com/Ehsan-saradar)! - feat(solana): staking foundation — models + RPC read layer
26
+
27
+ Phase 1 of Solana native staking. Adds the chain-layer read foundation under
28
+ `@vultisig/core-chain/chains/solana/staking`: config, stake-account/validator
29
+ models (jsonParsed parsing + activation-state derivation), the RPC read layer
30
+ (getVoteAccounts / stake-account scan / epoch / rent / inflation / supply), and
31
+ the withdraw cooldown gate. No UI, no signing, no validator-metadata source.
32
+
3
33
  ## 2.19.0
4
34
 
5
35
  ### Minor Changes
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Constants for Solana native staking (Stake program) reads.
3
+ *
4
+ * The Stake-program account layout and the staker-authority memcmp offset are
5
+ * protocol facts, not per-chain config, so this is a single flat constant set.
6
+ *
7
+ * The min-delegation RPC (`getStakeMinimumDelegation`) is blocked by the
8
+ * Vultisig proxy. The 1 SOL program minimum delegation is active on mainnet and
9
+ * is enforced by the Stake program — a delegation below it reverts with
10
+ * `StakeError.InsufficientDelegation`. Since the RPC is blocked, the delegation
11
+ * floor uses the documented `minDelegationFloorLamports` constant below plus the
12
+ * live rent-exempt reserve (active stake = funding − rent, so the funding floor
13
+ * is 1 SOL + rent).
14
+ *
15
+ * Port of iOS `SolanaStakingConfig`.
16
+ */
17
+ export declare const solanaStakingConfig: {
18
+ /**
19
+ * The on-chain Stake program. Every stake account is owned by this program;
20
+ * it is also the `programId` argument to the stake-filtered
21
+ * `getProgramAccounts` scan.
22
+ */
23
+ readonly stakeProgramId: "Stake11111111111111111111111111111111111111";
24
+ /**
25
+ * Byte size of a fully-initialized stake account (`StakeStateV2`). The
26
+ * `getProgramAccounts` scan filters on `dataSize: 200` to exclude
27
+ * uninitialized / rewards-pool accounts before the memcmp narrows to the
28
+ * owner's accounts.
29
+ */
30
+ readonly stakeStateSize: 200;
31
+ /**
32
+ * Offset of the staker authority pubkey inside the stake-account data, used
33
+ * as the `memcmp` offset to fetch only a given owner's stake accounts.
34
+ * Layout: 4-byte state enum discriminant + 8-byte `rentExemptReserve` = 12
35
+ * bytes precede `Meta.authorized.staker`.
36
+ */
37
+ readonly stakerMemcmpOffset: 12;
38
+ /**
39
+ * Offset of the delegation `voter` (vote account) pubkey inside the
40
+ * stake-account data. Available for vote-account-scoped scans; the
41
+ * owner-scoped read uses `stakerMemcmpOffset`.
42
+ */
43
+ readonly voterMemcmpOffset: 124;
44
+ /**
45
+ * Documented substitute for the blocked min-delegation RPC. 1 SOL in
46
+ * lamports — the historical program minimum. Used together with the live
47
+ * rent-exempt reserve as the delegation floor.
48
+ */
49
+ readonly minDelegationFloorLamports: 1000000000n;
50
+ /** Lamports per SOL (9 decimals). Shared by the staking read/format layer. */
51
+ readonly lamportsPerSol: 1000000000n;
52
+ /**
53
+ * Rent-exempt reserve for a 200-byte stake account (`StakeStateV2`), in
54
+ * lamports. Deterministic from the rent rate + account size, so it serves as
55
+ * the pre-load default before the live `getMinimumBalanceForRentExemption`
56
+ * read returns.
57
+ */
58
+ readonly rentExemptReserveLamports: 2282880n;
59
+ /**
60
+ * Mainnet schedule: 432,000 slots per epoch (~2 days). Informational — the
61
+ * live value is read from `getEpochInfo.slotsInEpoch`; this is the documented
62
+ * fallback for activation/cooldown copy.
63
+ */
64
+ readonly slotsPerEpoch: 432000n;
65
+ /**
66
+ * `u64::MAX` sentinel the Stake program writes into `deactivationEpoch` while
67
+ * a delegation is active (not deactivating). Parsed stake accounts carry this
68
+ * verbatim; the activation-state derivation treats it as "no deactivation
69
+ * scheduled".
70
+ */
71
+ readonly epochSentinel: 18446744073709551615n;
72
+ };
73
+ /** SOL decimals — used by the staking format layer. */
74
+ export declare const solDecimals = 9;
75
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/staking/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB;IAC9B;;;;OAIG;;IAGH;;;;;OAKG;;IAGH;;;;;OAKG;;IAGH;;;;OAIG;;IAGH;;;;OAIG;;IAGH,8EAA8E;;IAG9E;;;;;OAKG;;IAGH;;;;OAIG;;IAGH;;;;;OAKG;;CAEK,CAAA;AAEV,uDAAuD;AACvD,eAAO,MAAM,WAAW,IAAI,CAAA"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Constants for Solana native staking (Stake program) reads.
3
+ *
4
+ * The Stake-program account layout and the staker-authority memcmp offset are
5
+ * protocol facts, not per-chain config, so this is a single flat constant set.
6
+ *
7
+ * The min-delegation RPC (`getStakeMinimumDelegation`) is blocked by the
8
+ * Vultisig proxy. The 1 SOL program minimum delegation is active on mainnet and
9
+ * is enforced by the Stake program — a delegation below it reverts with
10
+ * `StakeError.InsufficientDelegation`. Since the RPC is blocked, the delegation
11
+ * floor uses the documented `minDelegationFloorLamports` constant below plus the
12
+ * live rent-exempt reserve (active stake = funding − rent, so the funding floor
13
+ * is 1 SOL + rent).
14
+ *
15
+ * Port of iOS `SolanaStakingConfig`.
16
+ */
17
+ export const solanaStakingConfig = {
18
+ /**
19
+ * The on-chain Stake program. Every stake account is owned by this program;
20
+ * it is also the `programId` argument to the stake-filtered
21
+ * `getProgramAccounts` scan.
22
+ */
23
+ stakeProgramId: 'Stake11111111111111111111111111111111111111',
24
+ /**
25
+ * Byte size of a fully-initialized stake account (`StakeStateV2`). The
26
+ * `getProgramAccounts` scan filters on `dataSize: 200` to exclude
27
+ * uninitialized / rewards-pool accounts before the memcmp narrows to the
28
+ * owner's accounts.
29
+ */
30
+ stakeStateSize: 200,
31
+ /**
32
+ * Offset of the staker authority pubkey inside the stake-account data, used
33
+ * as the `memcmp` offset to fetch only a given owner's stake accounts.
34
+ * Layout: 4-byte state enum discriminant + 8-byte `rentExemptReserve` = 12
35
+ * bytes precede `Meta.authorized.staker`.
36
+ */
37
+ stakerMemcmpOffset: 12,
38
+ /**
39
+ * Offset of the delegation `voter` (vote account) pubkey inside the
40
+ * stake-account data. Available for vote-account-scoped scans; the
41
+ * owner-scoped read uses `stakerMemcmpOffset`.
42
+ */
43
+ voterMemcmpOffset: 124,
44
+ /**
45
+ * Documented substitute for the blocked min-delegation RPC. 1 SOL in
46
+ * lamports — the historical program minimum. Used together with the live
47
+ * rent-exempt reserve as the delegation floor.
48
+ */
49
+ minDelegationFloorLamports: 1000000000n,
50
+ /** Lamports per SOL (9 decimals). Shared by the staking read/format layer. */
51
+ lamportsPerSol: 1000000000n,
52
+ /**
53
+ * Rent-exempt reserve for a 200-byte stake account (`StakeStateV2`), in
54
+ * lamports. Deterministic from the rent rate + account size, so it serves as
55
+ * the pre-load default before the live `getMinimumBalanceForRentExemption`
56
+ * read returns.
57
+ */
58
+ rentExemptReserveLamports: 2282880n,
59
+ /**
60
+ * Mainnet schedule: 432,000 slots per epoch (~2 days). Informational — the
61
+ * live value is read from `getEpochInfo.slotsInEpoch`; this is the documented
62
+ * fallback for activation/cooldown copy.
63
+ */
64
+ slotsPerEpoch: 432000n,
65
+ /**
66
+ * `u64::MAX` sentinel the Stake program writes into `deactivationEpoch` while
67
+ * a delegation is active (not deactivating). Parsed stake accounts carry this
68
+ * verbatim; the activation-state derivation treats it as "no deactivation
69
+ * scheduled".
70
+ */
71
+ epochSentinel: 18446744073709551615n,
72
+ };
73
+ /** SOL decimals — used by the staking format layer. */
74
+ export const solDecimals = 9;
75
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/staking/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC;;;;OAIG;IACH,cAAc,EAAE,6CAA6C;IAE7D;;;;;OAKG;IACH,cAAc,EAAE,GAAG;IAEnB;;;;;OAKG;IACH,kBAAkB,EAAE,EAAE;IAEtB;;;;OAIG;IACH,iBAAiB,EAAE,GAAG;IAEtB;;;;OAIG;IACH,0BAA0B,EAAE,WAAc;IAE1C,8EAA8E;IAC9E,cAAc,EAAE,WAAc;IAE9B;;;;;OAKG;IACH,yBAAyB,EAAE,QAAU;IAErC;;;;OAIG;IACH,aAAa,EAAE,OAAQ;IAEvB;;;;;OAKG;IACH,aAAa,EAAE,qBAA2B;CAClC,CAAA;AAEV,uDAAuD;AACvD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { SolanaStakeAccount } from './models/stakeAccount.js';
2
+ /**
3
+ * Gates a stake-account withdraw on the deactivation cooldown. After a
4
+ * deactivate, the stake cools down for ~1 epoch: the lamports become
5
+ * withdrawable only once the network epoch has advanced PAST the account's
6
+ * `deactivationEpoch`. Evaluating this before a withdraw keysign avoids
7
+ * surprising the user with a transaction the Stake program would reject.
8
+ *
9
+ * Port of iOS `SolanaEpochCooldownGate`.
10
+ */
11
+ export type SolanaEpochCooldownState = {
12
+ status: 'available';
13
+ } | {
14
+ status: 'blocked';
15
+ unlocksAtEpoch: bigint;
16
+ };
17
+ /**
18
+ * Evaluates whether `account`'s deactivated stake can be withdrawn at
19
+ * `currentEpoch`. Pure function over the parsed delegation + the live epoch.
20
+ *
21
+ * - A non-deactivating account (sentinel `deactivationEpoch`) is `available` —
22
+ * there is nothing cooling down.
23
+ * - A deactivating account unlocks once the network advances past its
24
+ * deactivation epoch, i.e. at `deactivationEpoch + 1`.
25
+ */
26
+ export declare const evaluateCooldown: (account: SolanaStakeAccount, currentEpoch: bigint) => SolanaEpochCooldownState;
27
+ /**
28
+ * Approximate mainnet epoch length in days. Informational copy only — the
29
+ * authoritative withdraw gate is `evaluateCooldown`, which uses the live epoch.
30
+ */
31
+ export declare const approximateDaysPerEpoch = 2;
32
+ /** Approximate calendar days for `epochs` epochs of cooldown. */
33
+ export declare const approximateCooldownDays: (epochs: number) => number;
34
+ //# sourceMappingURL=cooldownGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cooldownGate.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/staking/cooldownGate.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAElF;;;;;;;;GAQG;AACH,MAAM,MAAM,wBAAwB,GAAG;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAA;AAE9G;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,kBAAkB,EAAE,cAAc,MAAM,KAAG,wBAapF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC,iEAAiE;AACjE,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,KAAG,MAAuD,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { isDeactivationSentinel } from './models/stakeAccount.js';
2
+ /**
3
+ * Evaluates whether `account`'s deactivated stake can be withdrawn at
4
+ * `currentEpoch`. Pure function over the parsed delegation + the live epoch.
5
+ *
6
+ * - A non-deactivating account (sentinel `deactivationEpoch`) is `available` —
7
+ * there is nothing cooling down.
8
+ * - A deactivating account unlocks once the network advances past its
9
+ * deactivation epoch, i.e. at `deactivationEpoch + 1`.
10
+ */
11
+ export const evaluateCooldown = (account, currentEpoch) => {
12
+ const { delegation } = account;
13
+ if (!delegation) {
14
+ return { status: 'available' };
15
+ }
16
+ if (isDeactivationSentinel(delegation)) {
17
+ return { status: 'available' };
18
+ }
19
+ if (currentEpoch > delegation.deactivationEpoch) {
20
+ return { status: 'available' };
21
+ }
22
+ // `deactivationEpoch` is < sentinel here, so +1 is safe.
23
+ return { status: 'blocked', unlocksAtEpoch: delegation.deactivationEpoch + 1n };
24
+ };
25
+ /**
26
+ * Approximate mainnet epoch length in days. Informational copy only — the
27
+ * authoritative withdraw gate is `evaluateCooldown`, which uses the live epoch.
28
+ */
29
+ export const approximateDaysPerEpoch = 2;
30
+ /** Approximate calendar days for `epochs` epochs of cooldown. */
31
+ export const approximateCooldownDays = (epochs) => Math.max(0, epochs) * approximateDaysPerEpoch;
32
+ //# sourceMappingURL=cooldownGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cooldownGate.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/staking/cooldownGate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAsB,MAAM,uBAAuB,CAAA;AAalF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA2B,EAAE,YAAoB,EAA4B,EAAE;IAC9G,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAA;IAC9B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;IAChC,CAAC;IACD,IAAI,sBAAsB,CAAC,UAAU,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;IAChC,CAAC;IACD,IAAI,YAAY,GAAG,UAAU,CAAC,iBAAiB,EAAE,CAAC;QAChD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;IAChC,CAAC;IACD,yDAAyD;IACzD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,CAAC,iBAAiB,GAAG,EAAE,EAAE,CAAA;AACjF,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAA;AAExC,iEAAiE;AACjE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,uBAAuB,CAAA"}
@@ -0,0 +1,25 @@
1
+ import { ValidatorMetadata } from '../models/validator.js';
2
+ /**
3
+ * Swappable seam for off-chain validator enrichment (name / logo / APY /
4
+ * score). The core stake/commission/activation data comes from the on-chain
5
+ * `getVoteAccounts` read; this interface only supplies display metadata, which
6
+ * is the part most likely to change source (Stakewiz today, validators.app or
7
+ * an in-house endpoint tomorrow). Keeping it behind an interface lets the picker
8
+ * and views stay independent of any single provider.
9
+ *
10
+ * Contract: implementations MUST NOT throw on a provider outage. A failed or
11
+ * rate-limited source returns a partial or empty map so callers degrade
12
+ * gracefully — falling back to a truncated vote pubkey and the on-chain
13
+ * commission, with no logo, never a crash.
14
+ *
15
+ * Port of iOS `ValidatorMetadataProvider`.
16
+ */
17
+ export type ValidatorMetadataProvider = {
18
+ /**
19
+ * Returns metadata keyed by vote pubkey for the requested validators. The
20
+ * returned map may be empty or cover only a subset of the input — a validator
21
+ * absent from the map simply has no enrichment available. Never throws.
22
+ */
23
+ metadata: (votePubkeys: string[]) => Promise<Record<string, ValidatorMetadata>>;
24
+ };
25
+ //# sourceMappingURL=ValidatorMetadataProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidatorMetadataProvider.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/metadata/ValidatorMetadataProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;;OAIG;IACH,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAA;CAChF,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ValidatorMetadataProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidatorMetadataProvider.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/metadata/ValidatorMetadataProvider.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import { SolanaValidator } from '../models/validator.js';
2
+ import { ValidatorMetadataProvider } from './ValidatorMetadataProvider.js';
3
+ /**
4
+ * Merges off-chain metadata (name / logo / APY) onto on-chain validator rows
5
+ * via the swappable provider. The provider never throws — on an outage the rows
6
+ * pass through with empty metadata and the display layer falls back to a
7
+ * truncated vote pubkey + on-chain commission.
8
+ *
9
+ * Replaces the call site where iOS's view models invoke the
10
+ * `ValidatorMetadataProvider`; the provider is injectable for tests.
11
+ */
12
+ export declare const enrichValidatorsWithMetadata: (validators: SolanaValidator[], provider?: ValidatorMetadataProvider) => Promise<SolanaValidator[]>;
13
+ //# sourceMappingURL=enrichValidators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrichValidators.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/metadata/enrichValidators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AAEvE;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,GACvC,YAAY,eAAe,EAAE,EAC7B,WAAU,yBAA6D,KACtE,OAAO,CAAC,eAAe,EAAE,CAM3B,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { stakewizValidatorMetadataProvider } from './stakewizProvider.js';
2
+ /**
3
+ * Merges off-chain metadata (name / logo / APY) onto on-chain validator rows
4
+ * via the swappable provider. The provider never throws — on an outage the rows
5
+ * pass through with empty metadata and the display layer falls back to a
6
+ * truncated vote pubkey + on-chain commission.
7
+ *
8
+ * Replaces the call site where iOS's view models invoke the
9
+ * `ValidatorMetadataProvider`; the provider is injectable for tests.
10
+ */
11
+ export const enrichValidatorsWithMetadata = async (validators, provider = stakewizValidatorMetadataProvider) => {
12
+ const metadataByVotePubkey = await provider.metadata(validators.map(v => v.votePubkey));
13
+ return validators.map(validator => {
14
+ const metadata = metadataByVotePubkey[validator.votePubkey];
15
+ return metadata ? { ...validator, metadata } : validator;
16
+ });
17
+ };
18
+ //# sourceMappingURL=enrichValidators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrichValidators.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/metadata/enrichValidators.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iCAAiC,EAAE,MAAM,oBAAoB,CAAA;AAGtE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,EAC/C,UAA6B,EAC7B,WAAsC,iCAAiC,EAC3C,EAAE;IAC9B,MAAM,oBAAoB,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;IACvF,OAAO,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;QAChC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QAC3D,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { ValidatorMetadataProvider } from './ValidatorMetadataProvider.js';
2
+ export declare const stakewizValidatorMetadataProvider: ValidatorMetadataProvider;
3
+ //# sourceMappingURL=stakewizProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stakewizProvider.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/metadata/stakewizProvider.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AAmDvE,eAAO,MAAM,iCAAiC,EAAE,yBAoC/C,CAAA"}
@@ -0,0 +1,73 @@
1
+ import { attempt } from '@vultisig/lib-utils/attempt';
2
+ /**
3
+ * Concrete `ValidatorMetadataProvider` backed by Stakewiz
4
+ * (https://api.stakewiz.com). The `/validators` endpoint returns the full
5
+ * validator set in one response, so a single fetch enriches an arbitrary batch
6
+ * of vote pubkeys. A failed or rate-limited fetch yields an empty map — the
7
+ * call never throws, so callers degrade to on-chain-only display. The ~1h cache
8
+ * is handled by the consuming react-query hook's `staleTime`.
9
+ *
10
+ * Field mapping (Stakewiz → ValidatorMetadata):
11
+ * name → name
12
+ * image → logoUrl
13
+ * apy_estimate → apyEstimate (percent on the wire, stored as a fraction)
14
+ * wiz_score → score
15
+ *
16
+ * Port of iOS `StakewizValidatorMetadataProvider`.
17
+ */
18
+ const stakewizValidatorsUrl = 'https://api.stakewiz.com/validators';
19
+ const asTrimmedString = (value) => typeof value === 'string' ? value.trim() || undefined : undefined;
20
+ const asFiniteNumber = (value) => typeof value === 'number' && Number.isFinite(value) ? value : undefined;
21
+ /**
22
+ * Stakewiz reports `apy_estimate` as a percentage (e.g. 5.72) — store as a
23
+ * fraction. A genuine `0` is preserved (0% APY ≠ "no APY"); only missing /
24
+ * non-finite / negative values collapse to `undefined`.
25
+ */
26
+ const apyFraction = (percent) => {
27
+ const value = asFiniteNumber(percent);
28
+ return value !== undefined && value >= 0 ? value / 100 : undefined;
29
+ };
30
+ const toMetadata = (row) => {
31
+ const wizScore = asFiniteNumber(row.wiz_score);
32
+ return {
33
+ name: asTrimmedString(row.name),
34
+ logoUrl: asTrimmedString(row.image),
35
+ apyEstimate: apyFraction(row.apy_estimate),
36
+ score: wizScore === undefined ? undefined : Math.round(wizScore),
37
+ };
38
+ };
39
+ export const stakewizValidatorMetadataProvider = {
40
+ metadata: async (votePubkeys) => {
41
+ const requested = new Set(votePubkeys.filter(Boolean));
42
+ if (requested.size === 0) {
43
+ return {};
44
+ }
45
+ const result = await attempt(async () => {
46
+ const response = await fetch(stakewizValidatorsUrl, {
47
+ headers: { Accept: 'application/json' },
48
+ });
49
+ if (!response.ok) {
50
+ throw new Error(`Stakewiz responded ${response.status}`);
51
+ }
52
+ return (await response.json());
53
+ });
54
+ // Outage / rate-limit / malformed response — degrade to on-chain-only.
55
+ if ('error' in result || !Array.isArray(result.data)) {
56
+ return {};
57
+ }
58
+ const map = {};
59
+ for (const row of result.data) {
60
+ // Skip malformed elements (`null`, primitives, missing/invalid pubkey)
61
+ // rather than letting a field access throw — the never-throw contract.
62
+ if (typeof row !== 'object' || row === null) {
63
+ continue;
64
+ }
65
+ const votePubkey = asTrimmedString(row.vote_identity);
66
+ if (votePubkey && requested.has(votePubkey)) {
67
+ map[votePubkey] = toMetadata(row);
68
+ }
69
+ }
70
+ return map;
71
+ },
72
+ };
73
+ //# sourceMappingURL=stakewizProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stakewizProvider.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/metadata/stakewizProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Parsed Solana stake account — the read-side model the staking UI binds to
3
+ * (delegation amount, validator, activation state, withdraw authority). One
4
+ * stake account delegates to exactly one validator; a wallet can hold N.
5
+ *
6
+ * Decoded from a `getAccountInfo` / `getProgramAccounts` `jsonParsed` row
7
+ * (`value.data.parsed.info.{meta,stake}`). The on-chain numbers
8
+ * (`activationEpoch`, `deactivationEpoch`, `stake`, `rentExemptReserve`) are
9
+ * serialized as decimal STRINGS in jsonParsed — they're u64 and exceed JSON's
10
+ * safe-integer range — so they are converted to `bigint` here.
11
+ *
12
+ * Port of iOS `SolanaStakeAccount`.
13
+ */
14
+ /**
15
+ * Activation lifecycle of a stake delegation, derived from the account's
16
+ * `activationEpoch` / `deactivationEpoch` relative to the current epoch.
17
+ * Solana stake activates at the next epoch boundary and cools down ~1 epoch
18
+ * after a deactivate before the funds can be withdrawn.
19
+ */
20
+ export type SolanaStakeActivationState = 'activating' | 'active' | 'deactivating' | 'inactive';
21
+ export type SolanaStakeDelegation = {
22
+ /** Vote account this stake is delegated to. */
23
+ votePubkey: string;
24
+ /** Epoch the delegation began activating. */
25
+ activationEpoch: bigint;
26
+ /**
27
+ * Epoch the delegation began deactivating, or `epochSentinel` (`u64::MAX`)
28
+ * while active (the Stake program's "not deactivating" sentinel).
29
+ */
30
+ deactivationEpoch: bigint;
31
+ /** Delegated lamports. */
32
+ stake: bigint;
33
+ };
34
+ export type SolanaStakeAccount = {
35
+ /** Stake account address (its own pubkey, not the owner's). */
36
+ pubkey: string;
37
+ /**
38
+ * The account's total lamports (delegated stake + rent reserve + any
39
+ * undelegated lamports).
40
+ */
41
+ lamports: bigint;
42
+ /**
43
+ * Rent-exempt reserve held by the account — not part of the delegated /
44
+ * withdrawable stake.
45
+ */
46
+ rentExemptReserve: bigint;
47
+ /** Authority allowed to delegate / deactivate the stake. */
48
+ staker: string;
49
+ /** Authority allowed to withdraw the stake. */
50
+ withdrawer: string;
51
+ /**
52
+ * The delegation, or `undefined` for an initialized-but-undelegated account
53
+ * (`parsed.type == "initialized"`, no `stake.delegation`).
54
+ */
55
+ delegation?: SolanaStakeDelegation;
56
+ };
57
+ /** `true` when no deactivation has been scheduled on the delegation. */
58
+ export declare const isDeactivationSentinel: (delegation: SolanaStakeDelegation) => boolean;
59
+ /**
60
+ * Derives the lifecycle state from the current epoch. Pure so the cooldown gate
61
+ * and the UI share one definition.
62
+ *
63
+ * - activating: delegation began this epoch and is not deactivating.
64
+ * - deactivating: a deactivation was scheduled and the current epoch has not
65
+ * yet passed it.
66
+ * - active: delegated in a prior epoch and not deactivating.
67
+ * - inactive: no delegation, or the deactivation epoch has passed.
68
+ */
69
+ export declare const stakeActivationState: (account: SolanaStakeAccount, currentEpoch: bigint) => SolanaStakeActivationState;
70
+ /**
71
+ * Mirrors the `jsonParsed` Stake-program account `info` shape. u64 fields arrive
72
+ * as decimal strings (or numbers); `toBigInt` coerces both.
73
+ */
74
+ type ParsedStakeInfo = {
75
+ meta?: {
76
+ rentExemptReserve?: string | number;
77
+ authorized?: {
78
+ staker?: string;
79
+ withdrawer?: string;
80
+ };
81
+ };
82
+ stake?: {
83
+ delegation?: {
84
+ voter?: string;
85
+ stake?: string | number;
86
+ activationEpoch?: string | number;
87
+ deactivationEpoch?: string | number;
88
+ };
89
+ };
90
+ };
91
+ /**
92
+ * Builds the model from a decoded jsonParsed Stake-program account. Returns
93
+ * `undefined` when the account is not a parsed stake account (e.g. a non-stake
94
+ * program account or a base64/dataSliced row with no `parsed` tree).
95
+ */
96
+ export declare const parseStakeAccount: ({ pubkey, lamports, parsedInfo, }: {
97
+ pubkey: string;
98
+ lamports: bigint;
99
+ parsedInfo: ParsedStakeInfo | undefined;
100
+ }) => SolanaStakeAccount | undefined;
101
+ export {};
102
+ //# sourceMappingURL=stakeAccount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stakeAccount.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/models/stakeAccount.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG,YAAY,GAAG,QAAQ,GAAG,cAAc,GAAG,UAAU,CAAA;AAE9F,MAAM,MAAM,qBAAqB,GAAG;IAClC,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAA;IAClB,6CAA6C;IAC7C,eAAe,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,CAAA;IACzB,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,CAAA;IACzB,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAA;IACd,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,qBAAqB,CAAA;CACnC,CAAA;AAED,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,GAAI,YAAY,qBAAqB,KAAG,OACP,CAAA;AAEpE;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,kBAAkB,EAAE,cAAc,MAAM,KAAG,0BAcxF,CAAA;AAID;;;GAGG;AACH,KAAK,eAAe,GAAG;IACrB,IAAI,CAAC,EAAE;QACL,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;QACnC,UAAU,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KACtD,CAAA;IACD,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE;YACX,KAAK,CAAC,EAAE,MAAM,CAAA;YACd,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;YACvB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;YACjC,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;SACpC,CAAA;KACF,CAAA;CACF,CAAA;AAaD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,mCAI/B;IACD,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,eAAe,GAAG,SAAS,CAAA;CACxC,KAAG,kBAAkB,GAAG,SA4CxB,CAAA"}
@@ -0,0 +1,85 @@
1
+ import { solanaStakingConfig } from '../config.js';
2
+ /** `true` when no deactivation has been scheduled on the delegation. */
3
+ export const isDeactivationSentinel = (delegation) => delegation.deactivationEpoch === solanaStakingConfig.epochSentinel;
4
+ /**
5
+ * Derives the lifecycle state from the current epoch. Pure so the cooldown gate
6
+ * and the UI share one definition.
7
+ *
8
+ * - activating: delegation began this epoch and is not deactivating.
9
+ * - deactivating: a deactivation was scheduled and the current epoch has not
10
+ * yet passed it.
11
+ * - active: delegated in a prior epoch and not deactivating.
12
+ * - inactive: no delegation, or the deactivation epoch has passed.
13
+ */
14
+ export const stakeActivationState = (account, currentEpoch) => {
15
+ const { delegation } = account;
16
+ if (!delegation) {
17
+ return 'inactive';
18
+ }
19
+ if (!isDeactivationSentinel(delegation)) {
20
+ // A deactivation is scheduled. Still cooling down until the current epoch
21
+ // passes the deactivation epoch; inactive afterwards.
22
+ return currentEpoch <= delegation.deactivationEpoch ? 'deactivating' : 'inactive';
23
+ }
24
+ // No deactivation scheduled — activating in its first epoch, active after.
25
+ return currentEpoch <= delegation.activationEpoch ? 'activating' : 'active';
26
+ };
27
+ const toBigInt = (value) => {
28
+ if (value === undefined) {
29
+ return undefined;
30
+ }
31
+ try {
32
+ return BigInt(typeof value === 'number' ? Math.trunc(value) : value);
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ };
38
+ /**
39
+ * Builds the model from a decoded jsonParsed Stake-program account. Returns
40
+ * `undefined` when the account is not a parsed stake account (e.g. a non-stake
41
+ * program account or a base64/dataSliced row with no `parsed` tree).
42
+ */
43
+ export const parseStakeAccount = ({ pubkey, lamports, parsedInfo, }) => {
44
+ // Reject partially-malformed payloads rather than coercing them into
45
+ // fabricated zero/empty values — a bogus `0n` stake or empty authority would
46
+ // surface downstream as wrong balances or a falsely inactive/available state.
47
+ const meta = parsedInfo?.meta;
48
+ if (!meta?.authorized?.staker || !meta.authorized.withdrawer) {
49
+ return undefined;
50
+ }
51
+ const rentExemptReserve = toBigInt(meta.rentExemptReserve);
52
+ if (rentExemptReserve === undefined) {
53
+ return undefined;
54
+ }
55
+ const delegationInfo = parsedInfo?.stake?.delegation;
56
+ let delegation;
57
+ if (delegationInfo) {
58
+ // A delegation object with no `voter` is a malformed row, not an
59
+ // undelegated account — reject it rather than fabricating "inactive".
60
+ if (!delegationInfo.voter) {
61
+ return undefined;
62
+ }
63
+ const activationEpoch = toBigInt(delegationInfo.activationEpoch);
64
+ const deactivationEpoch = toBigInt(delegationInfo.deactivationEpoch);
65
+ const stake = toBigInt(delegationInfo.stake);
66
+ if (activationEpoch === undefined || deactivationEpoch === undefined || stake === undefined) {
67
+ return undefined;
68
+ }
69
+ delegation = {
70
+ votePubkey: delegationInfo.voter,
71
+ activationEpoch,
72
+ deactivationEpoch,
73
+ stake,
74
+ };
75
+ }
76
+ return {
77
+ pubkey,
78
+ lamports,
79
+ rentExemptReserve,
80
+ staker: meta.authorized.staker,
81
+ withdrawer: meta.authorized.withdrawer,
82
+ delegation,
83
+ };
84
+ };
85
+ //# sourceMappingURL=stakeAccount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stakeAccount.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/models/stakeAccount.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * A validator row from `getVoteAccounts` plus an optional metadata enrichment
3
+ * struct (name / logo / APY / score) populated by the metadata-provider seam.
4
+ * The base row is decoded straight off the RPC; `ValidatorMetadata` starts
5
+ * empty so the read layer can ship before the enrichment source is wired.
6
+ *
7
+ * Port of iOS `SolanaValidator` / `ValidatorMetadata`.
8
+ */
9
+ /**
10
+ * Off-chain enrichment for a validator. All optional — populated from a
11
+ * metadata source; the base read layer leaves it empty.
12
+ */
13
+ export type ValidatorMetadata = {
14
+ name?: string;
15
+ logoUrl?: string;
16
+ /** Estimated APY as a fraction (e.g. 0.067 for 6.7%). */
17
+ apyEstimate?: number;
18
+ /** A 0–100 quality score from the metadata source. */
19
+ score?: number;
20
+ };
21
+ export type SolanaValidator = {
22
+ /** Vote account address — the delegation target a stake account points at. */
23
+ votePubkey: string;
24
+ /** The validator's identity (node) pubkey. */
25
+ nodePubkey: string;
26
+ /**
27
+ * Total active stake delegated to this validator, in lamports. Sourced from
28
+ * `getVoteAccounts`, which serializes it as a JSON number — so for very large
29
+ * validators this is already an approximate (>2^53) value. Kept as `number`
30
+ * rather than dressed up as an exact `bigint`; it drives sort / voting-power
31
+ * display only, never balance math.
32
+ */
33
+ activatedStake: number;
34
+ /** Commission percentage (0–100) the validator takes from rewards. */
35
+ commission: number;
36
+ /** Whether this vote account has voted in the current epoch. */
37
+ epochVoteAccount: boolean;
38
+ /**
39
+ * `true` when the validator is in the delinquent set (not voting). Carried
40
+ * from which `getVoteAccounts` bucket the row came from, not the wire.
41
+ */
42
+ isDelinquent: boolean;
43
+ /** Enrichment from the metadata provider — name, logo, APY estimate, score. */
44
+ metadata: ValidatorMetadata;
45
+ };
46
+ /**
47
+ * `prefix…suffix` form of a base58 pubkey for compact display. Returns the
48
+ * input unchanged when it is too short to truncate meaningfully.
49
+ */
50
+ export declare const truncatedPubkey: (pubkey: string, prefix?: number, suffix?: number) => string;
51
+ /**
52
+ * Name to show in the picker: the enriched metadata name when present,
53
+ * otherwise a truncated vote pubkey. Keeps the display layer independent of
54
+ * whether the metadata provider returned anything.
55
+ */
56
+ export declare const validatorDisplayName: (validator: SolanaValidator) => string;
57
+ /**
58
+ * The validator logo URL, or `undefined` when no metadata source supplied one —
59
+ * the display layer then renders a deterministic placeholder.
60
+ */
61
+ export declare const validatorLogoUrl: (validator: SolanaValidator) => string | undefined;
62
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/models/validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAA;IAClB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,CAAA;IACtB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAA;IAClB,gEAAgE;IAChE,gBAAgB,EAAE,OAAO,CAAA;IACzB;;;OAGG;IACH,YAAY,EAAE,OAAO,CAAA;IACrB,+EAA+E;IAC/E,QAAQ,EAAE,iBAAiB,CAAA;CAC5B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,EAAE,eAAU,EAAE,eAAU,KAAG,MAC6B,CAAA;AAEtG;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,WAAW,eAAe,KAAG,MAMjE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,eAAe,KAAG,MAAM,GAAG,SAGtE,CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A validator row from `getVoteAccounts` plus an optional metadata enrichment
3
+ * struct (name / logo / APY / score) populated by the metadata-provider seam.
4
+ * The base row is decoded straight off the RPC; `ValidatorMetadata` starts
5
+ * empty so the read layer can ship before the enrichment source is wired.
6
+ *
7
+ * Port of iOS `SolanaValidator` / `ValidatorMetadata`.
8
+ */
9
+ /**
10
+ * `prefix…suffix` form of a base58 pubkey for compact display. Returns the
11
+ * input unchanged when it is too short to truncate meaningfully.
12
+ */
13
+ export const truncatedPubkey = (pubkey, prefix = 4, suffix = 4) => pubkey.length > prefix + suffix + 1 ? `${pubkey.slice(0, prefix)}…${pubkey.slice(-suffix)}` : pubkey;
14
+ /**
15
+ * Name to show in the picker: the enriched metadata name when present,
16
+ * otherwise a truncated vote pubkey. Keeps the display layer independent of
17
+ * whether the metadata provider returned anything.
18
+ */
19
+ export const validatorDisplayName = (validator) => {
20
+ const name = validator.metadata.name?.trim();
21
+ if (name) {
22
+ return name;
23
+ }
24
+ return truncatedPubkey(validator.votePubkey);
25
+ };
26
+ /**
27
+ * The validator logo URL, or `undefined` when no metadata source supplied one —
28
+ * the display layer then renders a deterministic placeholder.
29
+ */
30
+ export const validatorLogoUrl = (validator) => {
31
+ const raw = validator.metadata.logoUrl?.trim();
32
+ return raw ? raw : undefined;
33
+ };
34
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/chains/solana/staking/models/validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyCH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAE,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAU,EAAE,CAChF,MAAM,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;AAEtG;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,SAA0B,EAAU,EAAE;IACzE,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAAA;IAC5C,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,eAAe,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;AAC9C,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAA0B,EAAsB,EAAE;IACjF,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,CAAA;IAC9C,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AAC9B,CAAC,CAAA"}
@@ -0,0 +1,49 @@
1
+ import { SolanaStakeAccount } from './models/stakeAccount.js';
2
+ import { SolanaValidator } from './models/validator.js';
3
+ /**
4
+ * Read-side Solana RPC for native staking. Thin wrappers over the shared
5
+ * `@solana/web3.js` connection (`getSolanaClient`) so the staking read layer
6
+ * stays one call away from the rest of the Solana chain code.
7
+ *
8
+ * Port of the Solana staking reads in iOS `SolanaService` / `SolanaAPI`.
9
+ */
10
+ /**
11
+ * Lists every validator from `getVoteAccounts`, tagging each with the
12
+ * delinquent flag derived from its bucket (`current` vs `delinquent`). The base
13
+ * metadata is left empty — the metadata-provider seam enriches it later.
14
+ */
15
+ export declare const fetchSolanaValidators: () => Promise<SolanaValidator[]>;
16
+ /**
17
+ * Fetches the owner's stake accounts via a Stake-program `getProgramAccounts`
18
+ * scan filtered on `dataSize: 200` (fully-initialized stake accounts) and a
19
+ * memcmp on the staker authority at offset 12. Uncached at the call site — the
20
+ * staking view must reflect just-submitted txs and newly accrued rewards.
21
+ */
22
+ export declare const fetchSolanaStakeAccounts: (owner: string) => Promise<SolanaStakeAccount[]>;
23
+ /**
24
+ * Fetches a single stake account's parsed state by address. Used by the
25
+ * unstake / withdraw / move flows that operate on a known account.
26
+ */
27
+ export declare const fetchSolanaStakeAccount: (pubkey: string) => Promise<SolanaStakeAccount | undefined>;
28
+ export type SolanaEpochInfo = {
29
+ epoch: bigint;
30
+ slotIndex: bigint;
31
+ slotsInEpoch: bigint;
32
+ };
33
+ /** Current epoch info — drives activation-state derivation and cooldown copy. */
34
+ export declare const fetchSolanaEpochInfo: () => Promise<SolanaEpochInfo>;
35
+ /**
36
+ * The rent-exempt reserve for a 200-byte stake account, in lamports. The new
37
+ * stake account must be funded with this on top of the delegated amount.
38
+ */
39
+ export declare const fetchSolanaRentReserve: () => Promise<bigint>;
40
+ /** Network inflation rate (total) — drives the on-chain APY fallback. */
41
+ export declare const fetchSolanaInflationRate: () => Promise<number>;
42
+ /**
43
+ * Total SOL supply in lamports — the denominator for the staked fraction in the
44
+ * APY fallback. `getSupply` returns a JSON number that exceeds 2^53, so it is
45
+ * already approximate; kept as `number` (the ratio it feeds only needs ~2dp),
46
+ * not minted into a falsely-exact bigint.
47
+ */
48
+ export declare const fetchSolanaTotalSupply: () => Promise<number>;
49
+ //# sourceMappingURL=rpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/staking/rpc.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEpD;;;;;;GAMG;AAEH;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,eAAe,EAAE,CAiBvE,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,GAAU,OAAO,MAAM,KAAG,OAAO,CAAC,kBAAkB,EAAE,CAqB1F,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAWpG,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,QAAa,OAAO,CAAC,eAAe,CAQpE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,MAAM,CAI7D,CAAA;AAED,yEAAyE;AACzE,eAAO,MAAM,wBAAwB,QAAa,OAAO,CAAC,MAAM,CAI/D,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,MAAM,CAI7D,CAAA"}
@@ -0,0 +1,112 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { getSolanaClient } from '../client.js';
3
+ import { solanaStakingConfig } from './config.js';
4
+ import { parseStakeAccount } from './models/stakeAccount.js';
5
+ /**
6
+ * Read-side Solana RPC for native staking. Thin wrappers over the shared
7
+ * `@solana/web3.js` connection (`getSolanaClient`) so the staking read layer
8
+ * stays one call away from the rest of the Solana chain code.
9
+ *
10
+ * Port of the Solana staking reads in iOS `SolanaService` / `SolanaAPI`.
11
+ */
12
+ /**
13
+ * Lists every validator from `getVoteAccounts`, tagging each with the
14
+ * delinquent flag derived from its bucket (`current` vs `delinquent`). The base
15
+ * metadata is left empty — the metadata-provider seam enriches it later.
16
+ */
17
+ export const fetchSolanaValidators = async () => {
18
+ const client = getSolanaClient();
19
+ const { current, delinquent } = await client.getVoteAccounts();
20
+ const toValidator = (account, isDelinquent) => ({
21
+ votePubkey: account.votePubkey,
22
+ nodePubkey: account.nodePubkey,
23
+ // `activatedStake` arrives from the RPC as a JSON number — keep it as-is
24
+ // rather than minting a falsely-exact bigint from an already-lossy value.
25
+ activatedStake: account.activatedStake,
26
+ commission: account.commission,
27
+ epochVoteAccount: account.epochVoteAccount,
28
+ isDelinquent,
29
+ metadata: {},
30
+ });
31
+ return [...current.map(a => toValidator(a, false)), ...delinquent.map(a => toValidator(a, true))];
32
+ };
33
+ /**
34
+ * Fetches the owner's stake accounts via a Stake-program `getProgramAccounts`
35
+ * scan filtered on `dataSize: 200` (fully-initialized stake accounts) and a
36
+ * memcmp on the staker authority at offset 12. Uncached at the call site — the
37
+ * staking view must reflect just-submitted txs and newly accrued rewards.
38
+ */
39
+ export const fetchSolanaStakeAccounts = async (owner) => {
40
+ const client = getSolanaClient();
41
+ const rows = await client.getParsedProgramAccounts(new PublicKey(solanaStakingConfig.stakeProgramId), {
42
+ filters: [
43
+ { dataSize: solanaStakingConfig.stakeStateSize },
44
+ { memcmp: { offset: solanaStakingConfig.stakerMemcmpOffset, bytes: owner } },
45
+ ],
46
+ });
47
+ return rows.flatMap(({ pubkey, account }) => {
48
+ const { data } = account;
49
+ if (!('parsed' in data)) {
50
+ return [];
51
+ }
52
+ const parsed = parseStakeAccount({
53
+ pubkey: pubkey.toBase58(),
54
+ lamports: BigInt(account.lamports),
55
+ parsedInfo: data.parsed?.info,
56
+ });
57
+ return parsed ? [parsed] : [];
58
+ });
59
+ };
60
+ /**
61
+ * Fetches a single stake account's parsed state by address. Used by the
62
+ * unstake / withdraw / move flows that operate on a known account.
63
+ */
64
+ export const fetchSolanaStakeAccount = async (pubkey) => {
65
+ const client = getSolanaClient();
66
+ const { value } = await client.getParsedAccountInfo(new PublicKey(pubkey));
67
+ if (!value || !('parsed' in value.data)) {
68
+ return undefined;
69
+ }
70
+ return parseStakeAccount({
71
+ pubkey,
72
+ lamports: BigInt(value.lamports),
73
+ parsedInfo: value.data.parsed?.info,
74
+ });
75
+ };
76
+ /** Current epoch info — drives activation-state derivation and cooldown copy. */
77
+ export const fetchSolanaEpochInfo = async () => {
78
+ const client = getSolanaClient();
79
+ const info = await client.getEpochInfo();
80
+ return {
81
+ epoch: BigInt(info.epoch),
82
+ slotIndex: BigInt(info.slotIndex),
83
+ slotsInEpoch: BigInt(info.slotsInEpoch),
84
+ };
85
+ };
86
+ /**
87
+ * The rent-exempt reserve for a 200-byte stake account, in lamports. The new
88
+ * stake account must be funded with this on top of the delegated amount.
89
+ */
90
+ export const fetchSolanaRentReserve = async () => {
91
+ const client = getSolanaClient();
92
+ const lamports = await client.getMinimumBalanceForRentExemption(solanaStakingConfig.stakeStateSize);
93
+ return BigInt(lamports);
94
+ };
95
+ /** Network inflation rate (total) — drives the on-chain APY fallback. */
96
+ export const fetchSolanaInflationRate = async () => {
97
+ const client = getSolanaClient();
98
+ const { total } = await client.getInflationRate();
99
+ return total;
100
+ };
101
+ /**
102
+ * Total SOL supply in lamports — the denominator for the staked fraction in the
103
+ * APY fallback. `getSupply` returns a JSON number that exceeds 2^53, so it is
104
+ * already approximate; kept as `number` (the ratio it feeds only needs ~2dp),
105
+ * not minted into a falsely-exact bigint.
106
+ */
107
+ export const fetchSolanaTotalSupply = async () => {
108
+ const client = getSolanaClient();
109
+ const { value } = await client.getSupply();
110
+ return value.total;
111
+ };
112
+ //# sourceMappingURL=rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/staking/rpc.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/core-chain",
3
- "version": "2.19.0",
3
+ "version": "2.21.0",
4
4
  "description": "Blockchain chain logic shared across Vultisig clients",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -680,6 +680,46 @@
680
680
  "import": "./dist/chains/solana/spl/getSplAssociatedAccount.js",
681
681
  "default": "./dist/chains/solana/spl/getSplAssociatedAccount.js"
682
682
  },
683
+ "./chains/solana/staking/config": {
684
+ "types": "./dist/chains/solana/staking/config.d.ts",
685
+ "import": "./dist/chains/solana/staking/config.js",
686
+ "default": "./dist/chains/solana/staking/config.js"
687
+ },
688
+ "./chains/solana/staking/cooldownGate": {
689
+ "types": "./dist/chains/solana/staking/cooldownGate.d.ts",
690
+ "import": "./dist/chains/solana/staking/cooldownGate.js",
691
+ "default": "./dist/chains/solana/staking/cooldownGate.js"
692
+ },
693
+ "./chains/solana/staking/metadata/enrichValidators": {
694
+ "types": "./dist/chains/solana/staking/metadata/enrichValidators.d.ts",
695
+ "import": "./dist/chains/solana/staking/metadata/enrichValidators.js",
696
+ "default": "./dist/chains/solana/staking/metadata/enrichValidators.js"
697
+ },
698
+ "./chains/solana/staking/metadata/stakewizProvider": {
699
+ "types": "./dist/chains/solana/staking/metadata/stakewizProvider.d.ts",
700
+ "import": "./dist/chains/solana/staking/metadata/stakewizProvider.js",
701
+ "default": "./dist/chains/solana/staking/metadata/stakewizProvider.js"
702
+ },
703
+ "./chains/solana/staking/metadata/ValidatorMetadataProvider": {
704
+ "types": "./dist/chains/solana/staking/metadata/ValidatorMetadataProvider.d.ts",
705
+ "import": "./dist/chains/solana/staking/metadata/ValidatorMetadataProvider.js",
706
+ "default": "./dist/chains/solana/staking/metadata/ValidatorMetadataProvider.js"
707
+ },
708
+ "./chains/solana/staking/models/stakeAccount": {
709
+ "types": "./dist/chains/solana/staking/models/stakeAccount.d.ts",
710
+ "import": "./dist/chains/solana/staking/models/stakeAccount.js",
711
+ "default": "./dist/chains/solana/staking/models/stakeAccount.js"
712
+ },
713
+ "./chains/solana/staking/models/validator": {
714
+ "types": "./dist/chains/solana/staking/models/validator.d.ts",
715
+ "import": "./dist/chains/solana/staking/models/validator.js",
716
+ "default": "./dist/chains/solana/staking/models/validator.js"
717
+ },
718
+ "./chains/solana/staking/rpc": {
719
+ "types": "./dist/chains/solana/staking/rpc.d.ts",
720
+ "import": "./dist/chains/solana/staking/rpc.js",
721
+ "default": "./dist/chains/solana/staking/rpc.js"
722
+ },
683
723
  "./chains/sui/buildTransactionFromJson": {
684
724
  "types": "./dist/chains/sui/buildTransactionFromJson.d.ts",
685
725
  "import": "./dist/chains/sui/buildTransactionFromJson.js",
@@ -1969,7 +2009,7 @@
1969
2009
  "@cosmjs/proto-signing": "^0.39.0",
1970
2010
  "@cosmjs/stargate": "^0.39.0",
1971
2011
  "@lifi/sdk": "^4.0.0",
1972
- "@mysten/sui": "^2.19.0",
2012
+ "@mysten/sui": "^2.20.1",
1973
2013
  "@noble/hashes": "^1.8.0",
1974
2014
  "@polkadot/api": "^16.5.6",
1975
2015
  "@polkadot/util": "^14.0.3",
@@ -1989,7 +2029,7 @@
1989
2029
  "date-fns": "^4.4.0",
1990
2030
  "ethers": "^6.17.0",
1991
2031
  "tiny-secp256k1": "^2.2.4",
1992
- "viem": "^2.52.2",
2032
+ "viem": "^2.53.1",
1993
2033
  "xrpl": "^5.0.0"
1994
2034
  }
1995
2035
  }