@@ -41,14 +41,14 @@ export interface ValidatorAccount {
41
41
type : 'preferred' | 'active' | 'transient' | 'reserve' ;
42
42
voteAddress ?: PublicKey | undefined ;
43
43
stakeAddress : PublicKey ;
44
- lamports : number ;
44
+ lamports : BN ;
45
45
}
46
46
47
47
export async function prepareWithdrawAccounts (
48
48
connection : Connection ,
49
49
stakePool : StakePool ,
50
50
stakePoolAddress : PublicKey ,
51
- amount : number ,
51
+ amount : BN ,
52
52
compareFn ?: ( a : ValidatorAccount , b : ValidatorAccount ) => number ,
53
53
skipFee ?: boolean ,
54
54
) : Promise < WithdrawAccount [ ] > {
@@ -62,13 +62,13 @@ export async function prepareWithdrawAccounts(
62
62
const minBalanceForRentExemption = await connection . getMinimumBalanceForRentExemption (
63
63
StakeProgram . space ,
64
64
) ;
65
- const minBalance = minBalanceForRentExemption + MINIMUM_ACTIVE_STAKE ;
65
+ const minBalance = new BN ( minBalanceForRentExemption + MINIMUM_ACTIVE_STAKE ) ;
66
66
67
67
let accounts = [ ] as Array < {
68
68
type : 'preferred' | 'active' | 'transient' | 'reserve' ;
69
69
voteAddress ?: PublicKey | undefined ;
70
70
stakeAddress : PublicKey ;
71
- lamports : number ;
71
+ lamports : BN ;
72
72
} > ;
73
73
74
74
// Prepare accounts
@@ -91,12 +91,12 @@ export async function prepareWithdrawAccounts(
91
91
type : isPreferred ? 'preferred' : 'active' ,
92
92
voteAddress : validator . voteAccountAddress ,
93
93
stakeAddress : stakeAccountAddress ,
94
- lamports : validator . activeStakeLamports . toNumber ( ) ,
94
+ lamports : validator . activeStakeLamports ,
95
95
} ) ;
96
96
}
97
97
98
- const transientStakeLamports = validator . transientStakeLamports . toNumber ( ) - minBalance ;
99
- if ( transientStakeLamports > 0 ) {
98
+ const transientStakeLamports = validator . transientStakeLamports . sub ( minBalance ) ;
99
+ if ( transientStakeLamports . gt ( new BN ( 0 ) ) ) {
100
100
const transientStakeAccountAddress = await findTransientStakeProgramAddress (
101
101
STAKE_POOL_PROGRAM_ID ,
102
102
validator . voteAccountAddress ,
@@ -113,11 +113,11 @@ export async function prepareWithdrawAccounts(
113
113
}
114
114
115
115
// Sort from highest to lowest balance
116
- accounts = accounts . sort ( compareFn ? compareFn : ( a , b ) => b . lamports - a . lamports ) ;
116
+ accounts = accounts . sort ( compareFn ? compareFn : ( a , b ) => b . lamports . sub ( a . lamports ) . toNumber ( ) ) ;
117
117
118
118
const reserveStake = await connection . getAccountInfo ( stakePool . reserveStake ) ;
119
- const reserveStakeBalance = ( reserveStake ?. lamports ?? 0 ) - minBalanceForRentExemption ;
120
- if ( reserveStakeBalance > 0 ) {
119
+ const reserveStakeBalance = new BN ( ( reserveStake ?. lamports ?? 0 ) - minBalanceForRentExemption ) ;
120
+ if ( reserveStakeBalance . gt ( new BN ( 0 ) ) ) {
121
121
accounts . push ( {
122
122
type : 'reserve' ,
123
123
stakeAddress : stakePool . reserveStake ,
@@ -127,7 +127,7 @@ export async function prepareWithdrawAccounts(
127
127
128
128
// Prepare the list of accounts to withdraw from
129
129
const withdrawFrom : WithdrawAccount [ ] = [ ] ;
130
- let remainingAmount = amount ;
130
+ let remainingAmount = new BN ( amount ) ;
131
131
132
132
const fee = stakePool . stakeWithdrawalFee ;
133
133
const inverseFee : Fee = {
@@ -139,40 +139,39 @@ export async function prepareWithdrawAccounts(
139
139
const filteredAccounts = accounts . filter ( ( a ) => a . type == type ) ;
140
140
141
141
for ( const { stakeAddress, voteAddress, lamports } of filteredAccounts ) {
142
- if ( lamports <= minBalance && type == 'transient' ) {
142
+ if ( lamports . lte ( minBalance ) && type == 'transient' ) {
143
143
continue ;
144
144
}
145
145
146
146
let availableForWithdrawal = calcPoolTokensForDeposit ( stakePool , lamports ) ;
147
147
148
148
if ( ! skipFee && ! inverseFee . numerator . isZero ( ) ) {
149
- availableForWithdrawal = divideBnToNumber (
150
- new BN ( availableForWithdrawal ) . mul ( inverseFee . denominator ) ,
151
- inverseFee . numerator ,
152
- ) ;
149
+ availableForWithdrawal = availableForWithdrawal
150
+ . mul ( inverseFee . denominator )
151
+ . div ( inverseFee . numerator ) ;
153
152
}
154
153
155
- const poolAmount = Math . min ( availableForWithdrawal , remainingAmount ) ;
156
- if ( poolAmount <= 0 ) {
154
+ const poolAmount = BN . min ( availableForWithdrawal , remainingAmount ) ;
155
+ if ( poolAmount . lte ( new BN ( 0 ) ) ) {
157
156
continue ;
158
157
}
159
158
160
159
// Those accounts will be withdrawn completely with `claim` instruction
161
160
withdrawFrom . push ( { stakeAddress, voteAddress, poolAmount } ) ;
162
- remainingAmount -= poolAmount ;
161
+ remainingAmount = remainingAmount . sub ( poolAmount ) ;
163
162
164
- if ( remainingAmount == 0 ) {
163
+ if ( remainingAmount . isZero ( ) ) {
165
164
break ;
166
165
}
167
166
}
168
167
169
- if ( remainingAmount == 0 ) {
168
+ if ( remainingAmount . isZero ( ) ) {
170
169
break ;
171
170
}
172
171
}
173
172
174
173
// Not enough stake to withdraw the specified amount
175
- if ( remainingAmount > 0 ) {
174
+ if ( remainingAmount . gt ( new BN ( 0 ) ) ) {
176
175
throw new Error (
177
176
`No stake accounts found in this pool with enough balance to withdraw ${ lamportsToSol (
178
177
amount ,
@@ -186,35 +185,24 @@ export async function prepareWithdrawAccounts(
186
185
/**
187
186
* Calculate the pool tokens that should be minted for a deposit of `stakeLamports`
188
187
*/
189
- export function calcPoolTokensForDeposit ( stakePool : StakePool , stakeLamports : number ) : number {
188
+ export function calcPoolTokensForDeposit ( stakePool : StakePool , stakeLamports : BN ) : BN {
190
189
if ( stakePool . poolTokenSupply . isZero ( ) || stakePool . totalLamports . isZero ( ) ) {
191
190
return stakeLamports ;
192
191
}
193
- return Math . floor (
194
- divideBnToNumber ( new BN ( stakeLamports ) . mul ( stakePool . poolTokenSupply ) , stakePool . totalLamports ) ,
195
- ) ;
192
+ const numerator = stakeLamports . mul ( stakePool . poolTokenSupply ) ;
193
+ return numerator . div ( stakePool . totalLamports ) ;
196
194
}
197
195
198
196
/**
199
197
* Calculate lamports amount on withdrawal
200
198
*/
201
- export function calcLamportsWithdrawAmount ( stakePool : StakePool , poolTokens : number ) : number {
202
- const numerator = new BN ( poolTokens ) . mul ( stakePool . totalLamports ) ;
199
+ export function calcLamportsWithdrawAmount ( stakePool : StakePool , poolTokens : BN ) : BN {
200
+ const numerator = poolTokens . mul ( stakePool . totalLamports ) ;
203
201
const denominator = stakePool . poolTokenSupply ;
204
202
if ( numerator . lt ( denominator ) ) {
205
- return 0 ;
206
- }
207
- return divideBnToNumber ( numerator , denominator ) ;
208
- }
209
-
210
- export function divideBnToNumber ( numerator : BN , denominator : BN ) : number {
211
- if ( denominator . isZero ( ) ) {
212
- return 0 ;
203
+ return new BN ( 0 ) ;
213
204
}
214
- const quotient = numerator . div ( denominator ) . toNumber ( ) ;
215
- const rem = numerator . umod ( denominator ) ;
216
- const gcd = rem . gcd ( denominator ) ;
217
- return quotient + rem . div ( gcd ) . toNumber ( ) / denominator . div ( gcd ) . toNumber ( ) ;
205
+ return numerator . div ( denominator ) ;
218
206
}
219
207
220
208
export function newStakeAccount (
0 commit comments