@ignitionfi/fogo-stake-pool 1.0.0 → 1.0.2

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.
@@ -425,7 +425,7 @@ const METADATA_MAX_URI_LENGTH = 200;
425
425
  // Public key that identifies the SPL Stake Pool program.
426
426
  const STAKE_POOL_PROGRAM_ID = new PublicKey('SP1s4uFeTAX9jsXXmwyDs1gxYYf7cdDZ8qHUHVxE1yr');
427
427
  // Public key that identifies the SPL Stake Pool program deployed to devnet.
428
- const DEVNET_STAKE_POOL_PROGRAM_ID = new PublicKey('DPoo15wWDqpPJJtS2MUZ49aRxqz5ZaaJCJP4z8bLuib');
428
+ const DEVNET_STAKE_POOL_PROGRAM_ID = STAKE_POOL_PROGRAM_ID;
429
429
  // Maximum number of validators to update during UpdateValidatorListBalance.
430
430
  const MAX_VALIDATORS_TO_UPDATE = 4;
431
431
  // Seed for ephemeral stake account
@@ -436,7 +436,7 @@ const TRANSIENT_STAKE_SEED_PREFIX = Buffer$1.from('transient');
436
436
  const USER_STAKE_SEED_PREFIX = Buffer$1.from('user_stake');
437
437
  // Minimum amount of staked SOL required in a validator stake account to allow
438
438
  // for merges without a mismatch on credits observed
439
- const MINIMUM_ACTIVE_STAKE = LAMPORTS_PER_SOL;
439
+ const MINIMUM_ACTIVE_STAKE = 1000000;
440
440
 
441
441
  /**
442
442
  * Populate a buffer of instruction data using an InstructionType
@@ -816,40 +816,63 @@ async function prepareWithdrawAccounts(connection, stakePool, stakePoolAddress,
816
816
  }
817
817
  const minBalanceForRentExemption = await connection.getMinimumBalanceForRentExemption(StakeProgram.space);
818
818
  const minBalance = new BN(minBalanceForRentExemption + MINIMUM_ACTIVE_STAKE);
819
- let accounts = [];
820
- // Prepare accounts
819
+ // First, collect all stake account addresses we need to check
820
+ const accountsToFetch = [];
821
821
  for (const validator of validatorList.validators) {
822
822
  if (validator.status !== ValidatorStakeInfoStatus.Active) {
823
823
  continue;
824
824
  }
825
825
  const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress);
826
- // For active stake accounts, subtract the minimum balance that must remain
827
- // to allow for merges and maintain rent exemption
828
- const availableActiveLamports = validator.activeStakeLamports.sub(minBalance);
829
- if (availableActiveLamports.gt(new BN(0))) {
830
- const isPreferred = (_a = stakePool === null || stakePool === void 0 ? void 0 : stakePool.preferredWithdrawValidatorVoteAddress) === null || _a === void 0 ? void 0 : _a.equals(validator.voteAccountAddress);
831
- accounts.push({
826
+ const isPreferred = (_a = stakePool === null || stakePool === void 0 ? void 0 : stakePool.preferredWithdrawValidatorVoteAddress) === null || _a === void 0 ? void 0 : _a.equals(validator.voteAccountAddress);
827
+ // Add active stake account if validator list indicates it has stake
828
+ if (validator.activeStakeLamports.gt(new BN(0))) {
829
+ accountsToFetch.push({
832
830
  type: isPreferred ? 'preferred' : 'active',
833
831
  voteAddress: validator.voteAccountAddress,
834
832
  stakeAddress: stakeAccountAddress,
835
- lamports: availableActiveLamports,
836
833
  });
837
834
  }
838
- const transientStakeLamports = validator.transientStakeLamports.sub(minBalance);
839
- if (transientStakeLamports.gt(new BN(0))) {
835
+ // Add transient stake account if validator list indicates it has stake
836
+ if (validator.transientStakeLamports.gt(new BN(0))) {
840
837
  const transientStakeAccountAddress = await findTransientStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress, validator.transientSeedSuffixStart);
841
- accounts.push({
838
+ accountsToFetch.push({
842
839
  type: 'transient',
843
840
  voteAddress: validator.voteAccountAddress,
844
841
  stakeAddress: transientStakeAccountAddress,
845
- lamports: transientStakeLamports,
842
+ });
843
+ }
844
+ }
845
+ // Fetch all stake accounts + reserve in one batch call
846
+ const addressesToFetch = [
847
+ ...accountsToFetch.map(a => a.stakeAddress),
848
+ stakePool.reserveStake,
849
+ ];
850
+ const accountInfos = await connection.getMultipleAccountsInfo(addressesToFetch);
851
+ // Build accounts list using actual on-chain balances
852
+ let accounts = [];
853
+ for (let i = 0; i < accountsToFetch.length; i++) {
854
+ const { type, voteAddress, stakeAddress } = accountsToFetch[i];
855
+ const accountInfo = accountInfos[i];
856
+ if (!accountInfo) {
857
+ continue;
858
+ }
859
+ // Use actual on-chain balance instead of validator list value
860
+ const actualLamports = new BN(accountInfo.lamports);
861
+ const availableLamports = actualLamports.sub(minBalance);
862
+ if (availableLamports.gt(new BN(0))) {
863
+ accounts.push({
864
+ type,
865
+ voteAddress,
866
+ stakeAddress,
867
+ lamports: availableLamports,
846
868
  });
847
869
  }
848
870
  }
849
871
  // Sort from highest to lowest balance
850
872
  accounts = accounts.sort(compareFn || ((a, b) => b.lamports.sub(a.lamports).toNumber()));
851
- const reserveStake = await connection.getAccountInfo(stakePool.reserveStake);
852
- const reserveStakeBalance = new BN(((_b = reserveStake === null || reserveStake === void 0 ? void 0 : reserveStake.lamports) !== null && _b !== void 0 ? _b : 0) - minBalanceForRentExemption);
873
+ // Add reserve stake using actual balance (last item in batch fetch)
874
+ const reserveAccountInfo = accountInfos[accountInfos.length - 1];
875
+ const reserveStakeBalance = new BN(((_b = reserveAccountInfo === null || reserveAccountInfo === void 0 ? void 0 : reserveAccountInfo.lamports) !== null && _b !== void 0 ? _b : 0) - minBalanceForRentExemption);
853
876
  if (reserveStakeBalance.gt(new BN(0))) {
854
877
  accounts.push({
855
878
  type: 'reserve',