@ignitionfi/fogo-stake-pool 1.0.2 → 1.1.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.
- package/dist/codecs.d.ts +10 -0
- package/dist/index.browser.cjs.js +369 -208
- package/dist/index.browser.cjs.js.map +1 -1
- package/dist/index.browser.esm.js +369 -208
- package/dist/index.browser.esm.js.map +1 -1
- package/dist/index.cjs.js +369 -208
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.esm.js +369 -208
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +403 -242
- package/dist/index.iife.js.map +1 -1
- package/dist/index.iife.min.js +1 -1
- package/dist/index.iife.min.js.map +1 -1
- package/dist/instructions.d.ts +31 -22
- package/dist/utils/stake.d.ts +19 -2
- package/package.json +1 -1
- package/src/codecs.ts +59 -6
- package/src/constants.ts +1 -1
- package/src/index.ts +79 -26
- package/src/instructions.ts +140 -67
- package/src/utils/stake.ts +133 -75
package/dist/index.iife.js
CHANGED
|
@@ -19026,124 +19026,6 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
19026
19026
|
// for merges without a mismatch on credits observed
|
|
19027
19027
|
const MINIMUM_ACTIVE_STAKE = 1000000;
|
|
19028
19028
|
|
|
19029
|
-
/**
|
|
19030
|
-
* Populate a buffer of instruction data using an InstructionType
|
|
19031
|
-
* @internal
|
|
19032
|
-
*/
|
|
19033
|
-
function encodeData(type, fields) {
|
|
19034
|
-
const allocLength = type.layout.span;
|
|
19035
|
-
const data = node_buffer.Buffer.alloc(allocLength);
|
|
19036
|
-
const layoutFields = Object.assign({ instruction: type.index }, fields);
|
|
19037
|
-
type.layout.encode(layoutFields, data);
|
|
19038
|
-
return data;
|
|
19039
|
-
}
|
|
19040
|
-
/**
|
|
19041
|
-
* Decode instruction data buffer using an InstructionType
|
|
19042
|
-
* @internal
|
|
19043
|
-
*/
|
|
19044
|
-
function decodeData(type, buffer) {
|
|
19045
|
-
let data;
|
|
19046
|
-
try {
|
|
19047
|
-
data = type.layout.decode(buffer);
|
|
19048
|
-
}
|
|
19049
|
-
catch (err) {
|
|
19050
|
-
throw new Error(`invalid instruction; ${err}`);
|
|
19051
|
-
}
|
|
19052
|
-
if (data.instruction !== type.index) {
|
|
19053
|
-
throw new Error(`invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`);
|
|
19054
|
-
}
|
|
19055
|
-
return data;
|
|
19056
|
-
}
|
|
19057
|
-
|
|
19058
|
-
function solToLamports(amount) {
|
|
19059
|
-
if (isNaN(amount)) {
|
|
19060
|
-
return Number(0);
|
|
19061
|
-
}
|
|
19062
|
-
return Number(amount * LAMPORTS_PER_SOL);
|
|
19063
|
-
}
|
|
19064
|
-
function lamportsToSol(lamports) {
|
|
19065
|
-
if (typeof lamports === 'number') {
|
|
19066
|
-
return Math.abs(lamports) / LAMPORTS_PER_SOL;
|
|
19067
|
-
}
|
|
19068
|
-
if (typeof lamports === 'bigint') {
|
|
19069
|
-
return Math.abs(Number(lamports)) / LAMPORTS_PER_SOL;
|
|
19070
|
-
}
|
|
19071
|
-
let signMultiplier = 1;
|
|
19072
|
-
if (lamports.isNeg()) {
|
|
19073
|
-
signMultiplier = -1;
|
|
19074
|
-
}
|
|
19075
|
-
const absLamports = lamports.abs();
|
|
19076
|
-
const lamportsString = absLamports.toString(10).padStart(10, '0');
|
|
19077
|
-
const splitIndex = lamportsString.length - 9;
|
|
19078
|
-
const solString = `${lamportsString.slice(0, splitIndex)}.${lamportsString.slice(splitIndex)}`;
|
|
19079
|
-
return signMultiplier * Number.parseFloat(solString);
|
|
19080
|
-
}
|
|
19081
|
-
|
|
19082
|
-
/**
|
|
19083
|
-
* Generates the wSOL transient program address for the stake pool
|
|
19084
|
-
*/
|
|
19085
|
-
function findWsolTransientProgramAddress(programId, userPubkey) {
|
|
19086
|
-
const [publicKey] = PublicKey.findProgramAddressSync([node_buffer.Buffer.from('transient_wsol'), userPubkey.toBuffer()], programId);
|
|
19087
|
-
return publicKey;
|
|
19088
|
-
}
|
|
19089
|
-
/**
|
|
19090
|
-
* Generates the withdraw authority program address for the stake pool
|
|
19091
|
-
*/
|
|
19092
|
-
async function findWithdrawAuthorityProgramAddress(programId, stakePoolAddress) {
|
|
19093
|
-
const [publicKey] = PublicKey.findProgramAddressSync([stakePoolAddress.toBuffer(), node_buffer.Buffer.from('withdraw')], programId);
|
|
19094
|
-
return publicKey;
|
|
19095
|
-
}
|
|
19096
|
-
/**
|
|
19097
|
-
* Generates the stake program address for a validator's vote account
|
|
19098
|
-
*/
|
|
19099
|
-
async function findStakeProgramAddress(programId, voteAccountAddress, stakePoolAddress, seed) {
|
|
19100
|
-
const [publicKey] = PublicKey.findProgramAddressSync([
|
|
19101
|
-
voteAccountAddress.toBuffer(),
|
|
19102
|
-
stakePoolAddress.toBuffer(),
|
|
19103
|
-
seed ? new BN(seed).toArrayLike(node_buffer.Buffer, 'le', 4) : node_buffer.Buffer.alloc(0),
|
|
19104
|
-
], programId);
|
|
19105
|
-
return publicKey;
|
|
19106
|
-
}
|
|
19107
|
-
/**
|
|
19108
|
-
* Generates the stake program address for a validator's vote account
|
|
19109
|
-
*/
|
|
19110
|
-
async function findTransientStakeProgramAddress(programId, voteAccountAddress, stakePoolAddress, seed) {
|
|
19111
|
-
const [publicKey] = PublicKey.findProgramAddressSync([
|
|
19112
|
-
TRANSIENT_STAKE_SEED_PREFIX,
|
|
19113
|
-
voteAccountAddress.toBuffer(),
|
|
19114
|
-
stakePoolAddress.toBuffer(),
|
|
19115
|
-
seed.toArrayLike(node_buffer.Buffer, 'le', 8),
|
|
19116
|
-
], programId);
|
|
19117
|
-
return publicKey;
|
|
19118
|
-
}
|
|
19119
|
-
/**
|
|
19120
|
-
* Generates the ephemeral program address for stake pool redelegation
|
|
19121
|
-
*/
|
|
19122
|
-
async function findEphemeralStakeProgramAddress(programId, stakePoolAddress, seed) {
|
|
19123
|
-
const [publicKey] = PublicKey.findProgramAddressSync([EPHEMERAL_STAKE_SEED_PREFIX, stakePoolAddress.toBuffer(), seed.toArrayLike(node_buffer.Buffer, 'le', 8)], programId);
|
|
19124
|
-
return publicKey;
|
|
19125
|
-
}
|
|
19126
|
-
/**
|
|
19127
|
-
* Generates the metadata program address for the stake pool
|
|
19128
|
-
*/
|
|
19129
|
-
function findMetadataAddress(stakePoolMintAddress) {
|
|
19130
|
-
const [publicKey] = PublicKey.findProgramAddressSync([node_buffer.Buffer.from('metadata'), METADATA_PROGRAM_ID.toBuffer(), stakePoolMintAddress.toBuffer()], METADATA_PROGRAM_ID);
|
|
19131
|
-
return publicKey;
|
|
19132
|
-
}
|
|
19133
|
-
/**
|
|
19134
|
-
* Generates the user stake account PDA for session-based withdrawals.
|
|
19135
|
-
* The PDA is derived from the user's wallet and a unique seed.
|
|
19136
|
-
*/
|
|
19137
|
-
function findUserStakeProgramAddress(programId, userWallet, seed) {
|
|
19138
|
-
const seedBN = typeof seed === 'number' ? new BN(seed) : seed;
|
|
19139
|
-
const [publicKey] = PublicKey.findProgramAddressSync([
|
|
19140
|
-
USER_STAKE_SEED_PREFIX,
|
|
19141
|
-
userWallet.toBuffer(),
|
|
19142
|
-
seedBN.toArrayLike(node_buffer.Buffer, 'le', 8),
|
|
19143
|
-
], programId);
|
|
19144
|
-
return publicKey;
|
|
19145
|
-
}
|
|
19146
|
-
|
|
19147
19029
|
var Layout = {};
|
|
19148
19030
|
|
|
19149
19031
|
/* The MIT License (MIT)
|
|
@@ -21758,14 +21640,18 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
21758
21640
|
|
|
21759
21641
|
var LayoutExports = /*@__PURE__*/ requireLayout();
|
|
21760
21642
|
|
|
21761
|
-
|
|
21643
|
+
/**
|
|
21644
|
+
* BN-based layout for data decoding using buffer-layout.
|
|
21645
|
+
* Used for decoding on-chain account data (StakePool, ValidatorList, etc.)
|
|
21646
|
+
*/
|
|
21647
|
+
class BNDataLayout extends LayoutExports.Layout {
|
|
21762
21648
|
constructor(span, signed, property) {
|
|
21763
21649
|
super(span, property);
|
|
21764
|
-
this.
|
|
21650
|
+
this.blobLayout = LayoutExports.blob(span);
|
|
21765
21651
|
this.signed = signed;
|
|
21766
21652
|
}
|
|
21767
21653
|
decode(b, offset = 0) {
|
|
21768
|
-
const num = new BN(this.
|
|
21654
|
+
const num = new BN(this.blobLayout.decode(b, offset), 10, 'le');
|
|
21769
21655
|
if (this.signed) {
|
|
21770
21656
|
return num.fromTwos(this.span * 8).clone();
|
|
21771
21657
|
}
|
|
@@ -21775,11 +21661,51 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
21775
21661
|
if (this.signed) {
|
|
21776
21662
|
src = src.toTwos(this.span * 8);
|
|
21777
21663
|
}
|
|
21778
|
-
return this.
|
|
21664
|
+
return this.blobLayout.encode(src.toArrayLike(Buffer, 'le', this.span), b, offset);
|
|
21779
21665
|
}
|
|
21780
21666
|
}
|
|
21667
|
+
/**
|
|
21668
|
+
* Creates a u64 layout for data decoding (account layouts).
|
|
21669
|
+
* Used in StakePoolLayout, ValidatorListLayout, etc.
|
|
21670
|
+
*/
|
|
21781
21671
|
function u64(property) {
|
|
21782
|
-
return new
|
|
21672
|
+
return new BNDataLayout(8, false, property);
|
|
21673
|
+
}
|
|
21674
|
+
/**
|
|
21675
|
+
* BN-based layout for 64-bit unsigned integers using @solana/buffer-layout.
|
|
21676
|
+
* Used for encoding instruction data with support for values > MAX_SAFE_INTEGER.
|
|
21677
|
+
*/
|
|
21678
|
+
class BNInstructionLayout extends LayoutExports$1.Layout {
|
|
21679
|
+
constructor(span, signed, property) {
|
|
21680
|
+
super(span, property);
|
|
21681
|
+
this.blobLayout = LayoutExports$1.blob(span);
|
|
21682
|
+
this.signed = signed;
|
|
21683
|
+
}
|
|
21684
|
+
decode(b, offset = 0) {
|
|
21685
|
+
const num = new BN(this.blobLayout.decode(b, offset), 10, 'le');
|
|
21686
|
+
if (this.signed) {
|
|
21687
|
+
return num.fromTwos(this.span * 8).clone();
|
|
21688
|
+
}
|
|
21689
|
+
return num;
|
|
21690
|
+
}
|
|
21691
|
+
encode(src, b, offset = 0) {
|
|
21692
|
+
if (this.signed) {
|
|
21693
|
+
src = src.toTwos(this.span * 8);
|
|
21694
|
+
}
|
|
21695
|
+
return this.blobLayout.encode(src.toArrayLike(Buffer, 'le', this.span), b, offset);
|
|
21696
|
+
}
|
|
21697
|
+
getSpan(_b, _offset) {
|
|
21698
|
+
return this.span;
|
|
21699
|
+
}
|
|
21700
|
+
}
|
|
21701
|
+
/**
|
|
21702
|
+
* Creates a u64 layout for instruction encoding.
|
|
21703
|
+
* Properly handles BN values larger than Number.MAX_SAFE_INTEGER.
|
|
21704
|
+
* Compatible with @solana/buffer-layout.struct().
|
|
21705
|
+
*/
|
|
21706
|
+
// eslint-disable-next-line ts/no-explicit-any
|
|
21707
|
+
function u64Instruction(property) {
|
|
21708
|
+
return new BNInstructionLayout(8, false, property);
|
|
21783
21709
|
}
|
|
21784
21710
|
class WrappedLayout extends LayoutExports.Layout {
|
|
21785
21711
|
constructor(layout, decoder, encoder, property) {
|
|
@@ -21847,6 +21773,124 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
21847
21773
|
return new WrappedLayout(layout, ({ values }) => values, values => ({ values }), property);
|
|
21848
21774
|
}
|
|
21849
21775
|
|
|
21776
|
+
/**
|
|
21777
|
+
* Populate a buffer of instruction data using an InstructionType
|
|
21778
|
+
* @internal
|
|
21779
|
+
*/
|
|
21780
|
+
function encodeData(type, fields) {
|
|
21781
|
+
const allocLength = type.layout.span;
|
|
21782
|
+
const data = node_buffer.Buffer.alloc(allocLength);
|
|
21783
|
+
const layoutFields = Object.assign({ instruction: type.index }, fields);
|
|
21784
|
+
type.layout.encode(layoutFields, data);
|
|
21785
|
+
return data;
|
|
21786
|
+
}
|
|
21787
|
+
/**
|
|
21788
|
+
* Decode instruction data buffer using an InstructionType
|
|
21789
|
+
* @internal
|
|
21790
|
+
*/
|
|
21791
|
+
function decodeData(type, buffer) {
|
|
21792
|
+
let data;
|
|
21793
|
+
try {
|
|
21794
|
+
data = type.layout.decode(buffer);
|
|
21795
|
+
}
|
|
21796
|
+
catch (err) {
|
|
21797
|
+
throw new Error(`invalid instruction; ${err}`);
|
|
21798
|
+
}
|
|
21799
|
+
if (data.instruction !== type.index) {
|
|
21800
|
+
throw new Error(`invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`);
|
|
21801
|
+
}
|
|
21802
|
+
return data;
|
|
21803
|
+
}
|
|
21804
|
+
|
|
21805
|
+
function solToLamports(amount) {
|
|
21806
|
+
if (isNaN(amount)) {
|
|
21807
|
+
return Number(0);
|
|
21808
|
+
}
|
|
21809
|
+
return Number(amount * LAMPORTS_PER_SOL);
|
|
21810
|
+
}
|
|
21811
|
+
function lamportsToSol(lamports) {
|
|
21812
|
+
if (typeof lamports === 'number') {
|
|
21813
|
+
return Math.abs(lamports) / LAMPORTS_PER_SOL;
|
|
21814
|
+
}
|
|
21815
|
+
if (typeof lamports === 'bigint') {
|
|
21816
|
+
return Math.abs(Number(lamports)) / LAMPORTS_PER_SOL;
|
|
21817
|
+
}
|
|
21818
|
+
let signMultiplier = 1;
|
|
21819
|
+
if (lamports.isNeg()) {
|
|
21820
|
+
signMultiplier = -1;
|
|
21821
|
+
}
|
|
21822
|
+
const absLamports = lamports.abs();
|
|
21823
|
+
const lamportsString = absLamports.toString(10).padStart(10, '0');
|
|
21824
|
+
const splitIndex = lamportsString.length - 9;
|
|
21825
|
+
const solString = `${lamportsString.slice(0, splitIndex)}.${lamportsString.slice(splitIndex)}`;
|
|
21826
|
+
return signMultiplier * Number.parseFloat(solString);
|
|
21827
|
+
}
|
|
21828
|
+
|
|
21829
|
+
/**
|
|
21830
|
+
* Generates the wSOL transient program address for the stake pool
|
|
21831
|
+
*/
|
|
21832
|
+
function findWsolTransientProgramAddress(programId, userPubkey) {
|
|
21833
|
+
const [publicKey] = PublicKey.findProgramAddressSync([node_buffer.Buffer.from('transient_wsol'), userPubkey.toBuffer()], programId);
|
|
21834
|
+
return publicKey;
|
|
21835
|
+
}
|
|
21836
|
+
/**
|
|
21837
|
+
* Generates the withdraw authority program address for the stake pool
|
|
21838
|
+
*/
|
|
21839
|
+
async function findWithdrawAuthorityProgramAddress(programId, stakePoolAddress) {
|
|
21840
|
+
const [publicKey] = PublicKey.findProgramAddressSync([stakePoolAddress.toBuffer(), node_buffer.Buffer.from('withdraw')], programId);
|
|
21841
|
+
return publicKey;
|
|
21842
|
+
}
|
|
21843
|
+
/**
|
|
21844
|
+
* Generates the stake program address for a validator's vote account
|
|
21845
|
+
*/
|
|
21846
|
+
async function findStakeProgramAddress(programId, voteAccountAddress, stakePoolAddress, seed) {
|
|
21847
|
+
const [publicKey] = PublicKey.findProgramAddressSync([
|
|
21848
|
+
voteAccountAddress.toBuffer(),
|
|
21849
|
+
stakePoolAddress.toBuffer(),
|
|
21850
|
+
seed ? new BN(seed).toArrayLike(node_buffer.Buffer, 'le', 4) : node_buffer.Buffer.alloc(0),
|
|
21851
|
+
], programId);
|
|
21852
|
+
return publicKey;
|
|
21853
|
+
}
|
|
21854
|
+
/**
|
|
21855
|
+
* Generates the stake program address for a validator's vote account
|
|
21856
|
+
*/
|
|
21857
|
+
async function findTransientStakeProgramAddress(programId, voteAccountAddress, stakePoolAddress, seed) {
|
|
21858
|
+
const [publicKey] = PublicKey.findProgramAddressSync([
|
|
21859
|
+
TRANSIENT_STAKE_SEED_PREFIX,
|
|
21860
|
+
voteAccountAddress.toBuffer(),
|
|
21861
|
+
stakePoolAddress.toBuffer(),
|
|
21862
|
+
seed.toArrayLike(node_buffer.Buffer, 'le', 8),
|
|
21863
|
+
], programId);
|
|
21864
|
+
return publicKey;
|
|
21865
|
+
}
|
|
21866
|
+
/**
|
|
21867
|
+
* Generates the ephemeral program address for stake pool redelegation
|
|
21868
|
+
*/
|
|
21869
|
+
async function findEphemeralStakeProgramAddress(programId, stakePoolAddress, seed) {
|
|
21870
|
+
const [publicKey] = PublicKey.findProgramAddressSync([EPHEMERAL_STAKE_SEED_PREFIX, stakePoolAddress.toBuffer(), seed.toArrayLike(node_buffer.Buffer, 'le', 8)], programId);
|
|
21871
|
+
return publicKey;
|
|
21872
|
+
}
|
|
21873
|
+
/**
|
|
21874
|
+
* Generates the metadata program address for the stake pool
|
|
21875
|
+
*/
|
|
21876
|
+
function findMetadataAddress(stakePoolMintAddress) {
|
|
21877
|
+
const [publicKey] = PublicKey.findProgramAddressSync([node_buffer.Buffer.from('metadata'), METADATA_PROGRAM_ID.toBuffer(), stakePoolMintAddress.toBuffer()], METADATA_PROGRAM_ID);
|
|
21878
|
+
return publicKey;
|
|
21879
|
+
}
|
|
21880
|
+
/**
|
|
21881
|
+
* Generates the user stake account PDA for session-based withdrawals.
|
|
21882
|
+
* The PDA is derived from the user's wallet and a unique seed.
|
|
21883
|
+
*/
|
|
21884
|
+
function findUserStakeProgramAddress(programId, userWallet, seed) {
|
|
21885
|
+
const seedBN = typeof seed === 'number' ? new BN(seed) : seed;
|
|
21886
|
+
const [publicKey] = PublicKey.findProgramAddressSync([
|
|
21887
|
+
USER_STAKE_SEED_PREFIX,
|
|
21888
|
+
userWallet.toBuffer(),
|
|
21889
|
+
seedBN.toArrayLike(node_buffer.Buffer, 'le', 8),
|
|
21890
|
+
], programId);
|
|
21891
|
+
return publicKey;
|
|
21892
|
+
}
|
|
21893
|
+
|
|
21850
21894
|
const feeFields = [u64('denominator'), u64('numerator')];
|
|
21851
21895
|
var AccountType;
|
|
21852
21896
|
(function (AccountType) {
|
|
@@ -22008,80 +22052,84 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22008
22052
|
},
|
|
22009
22053
|
};
|
|
22010
22054
|
}
|
|
22011
|
-
async function prepareWithdrawAccounts(connection, stakePool, stakePoolAddress, amount, compareFn, skipFee) {
|
|
22055
|
+
async function prepareWithdrawAccounts(connection, stakePool, stakePoolAddress, amount, compareFn, skipFee, allowPartial, prefetchedData) {
|
|
22012
22056
|
var _a, _b;
|
|
22013
22057
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
|
|
22014
|
-
|
|
22015
|
-
|
|
22016
|
-
|
|
22017
|
-
|
|
22058
|
+
// Use prefetched data if available, otherwise fetch from RPC
|
|
22059
|
+
let validatorListData;
|
|
22060
|
+
let minBalanceForRentExemption;
|
|
22061
|
+
let stakeMinimumDelegation;
|
|
22062
|
+
if (prefetchedData) {
|
|
22063
|
+
validatorListData = prefetchedData.validatorListData;
|
|
22064
|
+
minBalanceForRentExemption = prefetchedData.minBalanceForRentExemption;
|
|
22065
|
+
stakeMinimumDelegation = prefetchedData.stakeMinimumDelegation;
|
|
22018
22066
|
}
|
|
22019
|
-
|
|
22020
|
-
|
|
22021
|
-
|
|
22022
|
-
|
|
22067
|
+
else {
|
|
22068
|
+
const [validatorListAcc, rentExemption, stakeMinimumDelegationResponse] = await Promise.all([
|
|
22069
|
+
connection.getAccountInfo(stakePool.validatorList),
|
|
22070
|
+
connection.getMinimumBalanceForRentExemption(StakeProgram.space),
|
|
22071
|
+
connection.getStakeMinimumDelegation(),
|
|
22072
|
+
]);
|
|
22073
|
+
validatorListData = (_a = validatorListAcc === null || validatorListAcc === void 0 ? void 0 : validatorListAcc.data) !== null && _a !== void 0 ? _a : null;
|
|
22074
|
+
minBalanceForRentExemption = rentExemption;
|
|
22075
|
+
stakeMinimumDelegation = Number(stakeMinimumDelegationResponse.value);
|
|
22076
|
+
}
|
|
22077
|
+
if (!validatorListData) {
|
|
22078
|
+
throw new Error('No staked funds available for delayed unstake. Use instant unstake instead.');
|
|
22079
|
+
}
|
|
22080
|
+
const validatorList = ValidatorListLayout.decode(validatorListData);
|
|
22081
|
+
if (!(validatorList === null || validatorList === void 0 ? void 0 : validatorList.validators) || (validatorList === null || validatorList === void 0 ? void 0 : validatorList.validators.length) === 0) {
|
|
22082
|
+
throw new Error('No staked funds available for delayed unstake. Use instant unstake instead.');
|
|
22083
|
+
}
|
|
22084
|
+
// minBalance = rent + max(stake_minimum_delegation, MINIMUM_ACTIVE_STAKE)
|
|
22085
|
+
const minimumDelegation = Math.max(stakeMinimumDelegation, MINIMUM_ACTIVE_STAKE);
|
|
22086
|
+
const minBalance = new BN(minBalanceForRentExemption + minimumDelegation);
|
|
22087
|
+
// Threshold for has_active_stake check (ceiling division for lamports_per_pool_token)
|
|
22088
|
+
const lamportsPerPoolToken = stakePool.totalLamports
|
|
22089
|
+
.add(stakePool.poolTokenSupply)
|
|
22090
|
+
.sub(new BN(1))
|
|
22091
|
+
.div(stakePool.poolTokenSupply);
|
|
22092
|
+
const minimumLamportsWithTolerance = minBalance.add(lamportsPerPoolToken);
|
|
22093
|
+
const hasActiveStake = validatorList.validators.some(v => v.status === ValidatorStakeInfoStatus.Active
|
|
22094
|
+
&& v.activeStakeLamports.gt(minimumLamportsWithTolerance));
|
|
22095
|
+
const hasTransientStake = validatorList.validators.some(v => v.status === ValidatorStakeInfoStatus.Active
|
|
22096
|
+
&& v.transientStakeLamports.gt(minimumLamportsWithTolerance));
|
|
22097
|
+
// ValidatorRemoval mode: no validator above threshold
|
|
22098
|
+
const isValidatorRemovalMode = !hasActiveStake && !hasTransientStake;
|
|
22099
|
+
let accounts = [];
|
|
22023
22100
|
for (const validator of validatorList.validators) {
|
|
22024
22101
|
if (validator.status !== ValidatorStakeInfoStatus.Active) {
|
|
22025
22102
|
continue;
|
|
22026
22103
|
}
|
|
22027
22104
|
const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress);
|
|
22028
|
-
|
|
22029
|
-
|
|
22030
|
-
|
|
22031
|
-
|
|
22105
|
+
// ValidatorRemoval: full balance available; Normal: leave minBalance
|
|
22106
|
+
const availableActiveLamports = isValidatorRemovalMode
|
|
22107
|
+
? validator.activeStakeLamports
|
|
22108
|
+
: validator.activeStakeLamports.sub(minBalance);
|
|
22109
|
+
if (availableActiveLamports.gt(new BN(0))) {
|
|
22110
|
+
const isPreferred = (_b = stakePool === null || stakePool === void 0 ? void 0 : stakePool.preferredWithdrawValidatorVoteAddress) === null || _b === void 0 ? void 0 : _b.equals(validator.voteAccountAddress);
|
|
22111
|
+
accounts.push({
|
|
22032
22112
|
type: isPreferred ? 'preferred' : 'active',
|
|
22033
22113
|
voteAddress: validator.voteAccountAddress,
|
|
22034
22114
|
stakeAddress: stakeAccountAddress,
|
|
22115
|
+
lamports: availableActiveLamports,
|
|
22035
22116
|
});
|
|
22036
22117
|
}
|
|
22037
|
-
|
|
22038
|
-
|
|
22118
|
+
const availableTransientLamports = isValidatorRemovalMode
|
|
22119
|
+
? validator.transientStakeLamports
|
|
22120
|
+
: validator.transientStakeLamports.sub(minBalance);
|
|
22121
|
+
if (availableTransientLamports.gt(new BN(0))) {
|
|
22039
22122
|
const transientStakeAccountAddress = await findTransientStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress, validator.transientSeedSuffixStart);
|
|
22040
|
-
|
|
22123
|
+
accounts.push({
|
|
22041
22124
|
type: 'transient',
|
|
22042
22125
|
voteAddress: validator.voteAccountAddress,
|
|
22043
22126
|
stakeAddress: transientStakeAccountAddress,
|
|
22044
|
-
|
|
22045
|
-
}
|
|
22046
|
-
}
|
|
22047
|
-
// Fetch all stake accounts + reserve in one batch call
|
|
22048
|
-
const addressesToFetch = [
|
|
22049
|
-
...accountsToFetch.map(a => a.stakeAddress),
|
|
22050
|
-
stakePool.reserveStake,
|
|
22051
|
-
];
|
|
22052
|
-
const accountInfos = await connection.getMultipleAccountsInfo(addressesToFetch);
|
|
22053
|
-
// Build accounts list using actual on-chain balances
|
|
22054
|
-
let accounts = [];
|
|
22055
|
-
for (let i = 0; i < accountsToFetch.length; i++) {
|
|
22056
|
-
const { type, voteAddress, stakeAddress } = accountsToFetch[i];
|
|
22057
|
-
const accountInfo = accountInfos[i];
|
|
22058
|
-
if (!accountInfo) {
|
|
22059
|
-
continue;
|
|
22060
|
-
}
|
|
22061
|
-
// Use actual on-chain balance instead of validator list value
|
|
22062
|
-
const actualLamports = new BN(accountInfo.lamports);
|
|
22063
|
-
const availableLamports = actualLamports.sub(minBalance);
|
|
22064
|
-
if (availableLamports.gt(new BN(0))) {
|
|
22065
|
-
accounts.push({
|
|
22066
|
-
type,
|
|
22067
|
-
voteAddress,
|
|
22068
|
-
stakeAddress,
|
|
22069
|
-
lamports: availableLamports,
|
|
22127
|
+
lamports: availableTransientLamports,
|
|
22070
22128
|
});
|
|
22071
22129
|
}
|
|
22072
22130
|
}
|
|
22073
22131
|
// Sort from highest to lowest balance
|
|
22074
22132
|
accounts = accounts.sort(compareFn || ((a, b) => b.lamports.sub(a.lamports).toNumber()));
|
|
22075
|
-
// Add reserve stake using actual balance (last item in batch fetch)
|
|
22076
|
-
const reserveAccountInfo = accountInfos[accountInfos.length - 1];
|
|
22077
|
-
const reserveStakeBalance = new BN(((_b = reserveAccountInfo === null || reserveAccountInfo === void 0 ? void 0 : reserveAccountInfo.lamports) !== null && _b !== void 0 ? _b : 0) - minBalanceForRentExemption);
|
|
22078
|
-
if (reserveStakeBalance.gt(new BN(0))) {
|
|
22079
|
-
accounts.push({
|
|
22080
|
-
type: 'reserve',
|
|
22081
|
-
stakeAddress: stakePool.reserveStake,
|
|
22082
|
-
lamports: reserveStakeBalance,
|
|
22083
|
-
});
|
|
22084
|
-
}
|
|
22085
22133
|
// Prepare the list of accounts to withdraw from
|
|
22086
22134
|
const withdrawFrom = [];
|
|
22087
22135
|
let remainingAmount = new BN(amount);
|
|
@@ -22090,23 +22138,24 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22090
22138
|
numerator: fee.denominator.sub(fee.numerator),
|
|
22091
22139
|
denominator: fee.denominator,
|
|
22092
22140
|
};
|
|
22093
|
-
for (const type of ['preferred', 'active', 'transient'
|
|
22141
|
+
for (const type of ['preferred', 'active', 'transient']) {
|
|
22094
22142
|
const filteredAccounts = accounts.filter(a => a.type === type);
|
|
22095
22143
|
for (const { stakeAddress, voteAddress, lamports } of filteredAccounts) {
|
|
22096
|
-
if (lamports.lte(minBalance) && type === 'transient') {
|
|
22097
|
-
continue;
|
|
22098
|
-
}
|
|
22099
22144
|
let availableForWithdrawal = calcPoolTokensForDeposit(stakePool, lamports);
|
|
22100
22145
|
if (!skipFee && !inverseFee.numerator.isZero()) {
|
|
22101
22146
|
availableForWithdrawal = availableForWithdrawal
|
|
22102
22147
|
.mul(inverseFee.denominator)
|
|
22103
22148
|
.div(inverseFee.numerator);
|
|
22104
22149
|
}
|
|
22150
|
+
// In ValidatorRemoval mode, must withdraw full validator balance (no partial)
|
|
22151
|
+
// Skip if remaining amount is less than full validator balance
|
|
22152
|
+
if (isValidatorRemovalMode && remainingAmount.lt(availableForWithdrawal)) {
|
|
22153
|
+
continue;
|
|
22154
|
+
}
|
|
22105
22155
|
const poolAmount = BN.min(availableForWithdrawal, remainingAmount);
|
|
22106
22156
|
if (poolAmount.lte(new BN(0))) {
|
|
22107
22157
|
continue;
|
|
22108
22158
|
}
|
|
22109
|
-
// Those accounts will be withdrawn completely with `claim` instruction
|
|
22110
22159
|
withdrawFrom.push({ stakeAddress, voteAddress, poolAmount });
|
|
22111
22160
|
remainingAmount = remainingAmount.sub(poolAmount);
|
|
22112
22161
|
if (remainingAmount.isZero()) {
|
|
@@ -22119,7 +22168,23 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22119
22168
|
}
|
|
22120
22169
|
// Not enough stake to withdraw the specified amount
|
|
22121
22170
|
if (remainingAmount.gt(new BN(0))) {
|
|
22122
|
-
|
|
22171
|
+
if (allowPartial) {
|
|
22172
|
+
const delayedAmount = amount.sub(remainingAmount);
|
|
22173
|
+
return {
|
|
22174
|
+
withdrawAccounts: withdrawFrom,
|
|
22175
|
+
delayedAmount,
|
|
22176
|
+
remainingAmount,
|
|
22177
|
+
};
|
|
22178
|
+
}
|
|
22179
|
+
const availableAmount = amount.sub(remainingAmount);
|
|
22180
|
+
throw new Error(`Not enough staked funds for delayed unstake. Requested ${lamportsToSol(amount)} iFOGO, but only ${lamportsToSol(availableAmount)} available. Use instant unstake for the remaining amount.`);
|
|
22181
|
+
}
|
|
22182
|
+
if (allowPartial) {
|
|
22183
|
+
return {
|
|
22184
|
+
withdrawAccounts: withdrawFrom,
|
|
22185
|
+
delayedAmount: amount,
|
|
22186
|
+
remainingAmount: new BN(0),
|
|
22187
|
+
};
|
|
22123
22188
|
}
|
|
22124
22189
|
return withdrawFrom;
|
|
22125
22190
|
}
|
|
@@ -22168,11 +22233,50 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22168
22233
|
return result;
|
|
22169
22234
|
}
|
|
22170
22235
|
|
|
22236
|
+
/**
|
|
22237
|
+
* Converts various numeric types to BN for safe large number handling.
|
|
22238
|
+
* @internal
|
|
22239
|
+
*/
|
|
22240
|
+
function toBN(value) {
|
|
22241
|
+
if (BN.isBN(value)) {
|
|
22242
|
+
return value;
|
|
22243
|
+
}
|
|
22244
|
+
if (typeof value === 'bigint') {
|
|
22245
|
+
return new BN(value.toString());
|
|
22246
|
+
}
|
|
22247
|
+
if (typeof value === 'string') {
|
|
22248
|
+
// Validate string is a valid non-negative integer
|
|
22249
|
+
const trimmed = value.trim();
|
|
22250
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
22251
|
+
throw new Error(`Invalid amount string: "${value}". Must be a non-negative integer.`);
|
|
22252
|
+
}
|
|
22253
|
+
return new BN(trimmed);
|
|
22254
|
+
}
|
|
22255
|
+
if (typeof value === 'number') {
|
|
22256
|
+
if (!Number.isFinite(value)) {
|
|
22257
|
+
throw new Error('Invalid amount: must be a finite number');
|
|
22258
|
+
}
|
|
22259
|
+
if (value < 0) {
|
|
22260
|
+
throw new Error('Invalid amount: must be non-negative');
|
|
22261
|
+
}
|
|
22262
|
+
if (!Number.isInteger(value)) {
|
|
22263
|
+
throw new Error('Invalid amount: must be an integer (lamports)');
|
|
22264
|
+
}
|
|
22265
|
+
// CRITICAL: Numbers > MAX_SAFE_INTEGER have already lost precision
|
|
22266
|
+
// We throw an error instead of silently corrupting data
|
|
22267
|
+
if (value > Number.MAX_SAFE_INTEGER) {
|
|
22268
|
+
throw new Error(`Amount ${value} exceeds Number.MAX_SAFE_INTEGER (9,007,199,254,740,991). ` +
|
|
22269
|
+
`Use BigInt or BN for large values to avoid precision loss.`);
|
|
22270
|
+
}
|
|
22271
|
+
return new BN(value);
|
|
22272
|
+
}
|
|
22273
|
+
throw new Error(`Invalid amount type: ${typeof value}`);
|
|
22274
|
+
}
|
|
22171
22275
|
// 'UpdateTokenMetadata' and 'CreateTokenMetadata' have dynamic layouts
|
|
22172
22276
|
const MOVE_STAKE_LAYOUT = LayoutExports$1.struct([
|
|
22173
22277
|
LayoutExports$1.u8('instruction'),
|
|
22174
|
-
|
|
22175
|
-
|
|
22278
|
+
u64Instruction('lamports'),
|
|
22279
|
+
u64Instruction('transientStakeSeed'),
|
|
22176
22280
|
]);
|
|
22177
22281
|
const UPDATE_VALIDATOR_LIST_BALANCE_LAYOUT = LayoutExports$1.struct([
|
|
22178
22282
|
LayoutExports$1.u8('instruction'),
|
|
@@ -22247,7 +22351,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22247
22351
|
index: 10,
|
|
22248
22352
|
layout: LayoutExports$1.struct([
|
|
22249
22353
|
LayoutExports$1.u8('instruction'),
|
|
22250
|
-
|
|
22354
|
+
u64Instruction('poolTokens'),
|
|
22251
22355
|
]),
|
|
22252
22356
|
},
|
|
22253
22357
|
/// Deposit SOL directly into the pool's reserve account. The output is a "pool" token
|
|
@@ -22256,7 +22360,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22256
22360
|
index: 14,
|
|
22257
22361
|
layout: LayoutExports$1.struct([
|
|
22258
22362
|
LayoutExports$1.u8('instruction'),
|
|
22259
|
-
|
|
22363
|
+
u64Instruction('lamports'),
|
|
22260
22364
|
]),
|
|
22261
22365
|
},
|
|
22262
22366
|
/// Withdraw SOL directly from the pool's reserve account. Fails if the
|
|
@@ -22265,25 +22369,25 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22265
22369
|
index: 16,
|
|
22266
22370
|
layout: LayoutExports$1.struct([
|
|
22267
22371
|
LayoutExports$1.u8('instruction'),
|
|
22268
|
-
|
|
22372
|
+
u64Instruction('poolTokens'),
|
|
22269
22373
|
]),
|
|
22270
22374
|
},
|
|
22271
22375
|
IncreaseAdditionalValidatorStake: {
|
|
22272
22376
|
index: 19,
|
|
22273
22377
|
layout: LayoutExports$1.struct([
|
|
22274
22378
|
LayoutExports$1.u8('instruction'),
|
|
22275
|
-
|
|
22276
|
-
|
|
22277
|
-
|
|
22379
|
+
u64Instruction('lamports'),
|
|
22380
|
+
u64Instruction('transientStakeSeed'),
|
|
22381
|
+
u64Instruction('ephemeralStakeSeed'),
|
|
22278
22382
|
]),
|
|
22279
22383
|
},
|
|
22280
22384
|
DecreaseAdditionalValidatorStake: {
|
|
22281
22385
|
index: 20,
|
|
22282
22386
|
layout: LayoutExports$1.struct([
|
|
22283
22387
|
LayoutExports$1.u8('instruction'),
|
|
22284
|
-
|
|
22285
|
-
|
|
22286
|
-
|
|
22388
|
+
u64Instruction('lamports'),
|
|
22389
|
+
u64Instruction('transientStakeSeed'),
|
|
22390
|
+
u64Instruction('ephemeralStakeSeed'),
|
|
22287
22391
|
]),
|
|
22288
22392
|
},
|
|
22289
22393
|
DecreaseValidatorStakeWithReserve: {
|
|
@@ -22298,62 +22402,62 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22298
22402
|
index: 23,
|
|
22299
22403
|
layout: LayoutExports$1.struct([
|
|
22300
22404
|
LayoutExports$1.u8('instruction'),
|
|
22301
|
-
|
|
22405
|
+
u64Instruction('lamports'),
|
|
22302
22406
|
]),
|
|
22303
22407
|
},
|
|
22304
22408
|
WithdrawStakeWithSlippage: {
|
|
22305
22409
|
index: 24,
|
|
22306
22410
|
layout: LayoutExports$1.struct([
|
|
22307
22411
|
LayoutExports$1.u8('instruction'),
|
|
22308
|
-
|
|
22309
|
-
|
|
22412
|
+
u64Instruction('poolTokensIn'),
|
|
22413
|
+
u64Instruction('minimumLamportsOut'),
|
|
22310
22414
|
]),
|
|
22311
22415
|
},
|
|
22312
22416
|
DepositSolWithSlippage: {
|
|
22313
22417
|
index: 25,
|
|
22314
22418
|
layout: LayoutExports$1.struct([
|
|
22315
22419
|
LayoutExports$1.u8('instruction'),
|
|
22316
|
-
|
|
22420
|
+
u64Instruction('lamports'),
|
|
22317
22421
|
]),
|
|
22318
22422
|
},
|
|
22319
22423
|
WithdrawSolWithSlippage: {
|
|
22320
22424
|
index: 26,
|
|
22321
22425
|
layout: LayoutExports$1.struct([
|
|
22322
22426
|
LayoutExports$1.u8('instruction'),
|
|
22323
|
-
|
|
22427
|
+
u64Instruction('lamports'),
|
|
22324
22428
|
]),
|
|
22325
22429
|
},
|
|
22326
22430
|
DepositWsolWithSession: {
|
|
22327
22431
|
index: 27,
|
|
22328
22432
|
layout: LayoutExports$1.struct([
|
|
22329
22433
|
LayoutExports$1.u8('instruction'),
|
|
22330
|
-
|
|
22331
|
-
|
|
22434
|
+
u64Instruction('lamportsIn'),
|
|
22435
|
+
u64Instruction('minimumPoolTokensOut'),
|
|
22332
22436
|
]),
|
|
22333
22437
|
},
|
|
22334
22438
|
WithdrawWsolWithSession: {
|
|
22335
22439
|
index: 28,
|
|
22336
22440
|
layout: LayoutExports$1.struct([
|
|
22337
22441
|
LayoutExports$1.u8('instruction'),
|
|
22338
|
-
|
|
22339
|
-
|
|
22442
|
+
u64Instruction('poolTokensIn'),
|
|
22443
|
+
u64Instruction('minimumLamportsOut'),
|
|
22340
22444
|
]),
|
|
22341
22445
|
},
|
|
22342
22446
|
WithdrawStakeWithSession: {
|
|
22343
22447
|
index: 29,
|
|
22344
22448
|
layout: LayoutExports$1.struct([
|
|
22345
22449
|
LayoutExports$1.u8('instruction'),
|
|
22346
|
-
|
|
22347
|
-
|
|
22348
|
-
|
|
22450
|
+
u64Instruction('poolTokensIn'),
|
|
22451
|
+
u64Instruction('minimumLamportsOut'),
|
|
22452
|
+
u64Instruction('userStakeSeed'),
|
|
22349
22453
|
]),
|
|
22350
22454
|
},
|
|
22351
22455
|
WithdrawFromStakeAccountWithSession: {
|
|
22352
22456
|
index: 30,
|
|
22353
22457
|
layout: LayoutExports$1.struct([
|
|
22354
22458
|
LayoutExports$1.u8('instruction'),
|
|
22355
|
-
|
|
22356
|
-
|
|
22459
|
+
u64Instruction('lamports'),
|
|
22460
|
+
u64Instruction('userStakeSeed'),
|
|
22357
22461
|
]),
|
|
22358
22462
|
},
|
|
22359
22463
|
});
|
|
@@ -22485,7 +22589,10 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22485
22589
|
static increaseValidatorStake(params) {
|
|
22486
22590
|
const { programId, stakePool, staker, withdrawAuthority, validatorList, reserveStake, transientStake, validatorStake, validatorVote, lamports, transientStakeSeed, } = params;
|
|
22487
22591
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.IncreaseValidatorStake;
|
|
22488
|
-
const data = encodeData(type, {
|
|
22592
|
+
const data = encodeData(type, {
|
|
22593
|
+
lamports: toBN(lamports),
|
|
22594
|
+
transientStakeSeed: toBN(transientStakeSeed),
|
|
22595
|
+
});
|
|
22489
22596
|
const keys = [
|
|
22490
22597
|
{ pubkey: stakePool, isSigner: false, isWritable: false },
|
|
22491
22598
|
{ pubkey: staker, isSigner: true, isWritable: false },
|
|
@@ -22515,7 +22622,11 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22515
22622
|
static increaseAdditionalValidatorStake(params) {
|
|
22516
22623
|
const { programId, stakePool, staker, withdrawAuthority, validatorList, reserveStake, transientStake, validatorStake, validatorVote, lamports, transientStakeSeed, ephemeralStake, ephemeralStakeSeed, } = params;
|
|
22517
22624
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.IncreaseAdditionalValidatorStake;
|
|
22518
|
-
const data = encodeData(type, {
|
|
22625
|
+
const data = encodeData(type, {
|
|
22626
|
+
lamports: toBN(lamports),
|
|
22627
|
+
transientStakeSeed: toBN(transientStakeSeed),
|
|
22628
|
+
ephemeralStakeSeed: toBN(ephemeralStakeSeed),
|
|
22629
|
+
});
|
|
22519
22630
|
const keys = [
|
|
22520
22631
|
{ pubkey: stakePool, isSigner: false, isWritable: false },
|
|
22521
22632
|
{ pubkey: staker, isSigner: true, isWritable: false },
|
|
@@ -22545,7 +22656,10 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22545
22656
|
static decreaseValidatorStake(params) {
|
|
22546
22657
|
const { programId, stakePool, staker, withdrawAuthority, validatorList, validatorStake, transientStake, lamports, transientStakeSeed, } = params;
|
|
22547
22658
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseValidatorStake;
|
|
22548
|
-
const data = encodeData(type, {
|
|
22659
|
+
const data = encodeData(type, {
|
|
22660
|
+
lamports: toBN(lamports),
|
|
22661
|
+
transientStakeSeed: toBN(transientStakeSeed),
|
|
22662
|
+
});
|
|
22549
22663
|
const keys = [
|
|
22550
22664
|
{ pubkey: stakePool, isSigner: false, isWritable: false },
|
|
22551
22665
|
{ pubkey: staker, isSigner: true, isWritable: false },
|
|
@@ -22571,7 +22685,10 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22571
22685
|
static decreaseValidatorStakeWithReserve(params) {
|
|
22572
22686
|
const { programId, stakePool, staker, withdrawAuthority, validatorList, reserveStake, validatorStake, transientStake, lamports, transientStakeSeed, } = params;
|
|
22573
22687
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseValidatorStakeWithReserve;
|
|
22574
|
-
const data = encodeData(type, {
|
|
22688
|
+
const data = encodeData(type, {
|
|
22689
|
+
lamports: toBN(lamports),
|
|
22690
|
+
transientStakeSeed: toBN(transientStakeSeed),
|
|
22691
|
+
});
|
|
22575
22692
|
const keys = [
|
|
22576
22693
|
{ pubkey: stakePool, isSigner: false, isWritable: false },
|
|
22577
22694
|
{ pubkey: staker, isSigner: true, isWritable: false },
|
|
@@ -22598,7 +22715,11 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22598
22715
|
static decreaseAdditionalValidatorStake(params) {
|
|
22599
22716
|
const { programId, stakePool, staker, withdrawAuthority, validatorList, reserveStake, validatorStake, transientStake, lamports, transientStakeSeed, ephemeralStakeSeed, ephemeralStake, } = params;
|
|
22600
22717
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseAdditionalValidatorStake;
|
|
22601
|
-
const data = encodeData(type, {
|
|
22718
|
+
const data = encodeData(type, {
|
|
22719
|
+
lamports: toBN(lamports),
|
|
22720
|
+
transientStakeSeed: toBN(transientStakeSeed),
|
|
22721
|
+
ephemeralStakeSeed: toBN(ephemeralStakeSeed),
|
|
22722
|
+
});
|
|
22602
22723
|
const keys = [
|
|
22603
22724
|
{ pubkey: stakePool, isSigner: false, isWritable: false },
|
|
22604
22725
|
{ pubkey: staker, isSigner: true, isWritable: false },
|
|
@@ -22655,7 +22776,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22655
22776
|
static depositSol(params) {
|
|
22656
22777
|
const { programId, stakePool, withdrawAuthority, depositAuthority, reserveStake, fundingAccount, destinationPoolAccount, managerFeeAccount, referralPoolAccount, poolMint, lamports, } = params;
|
|
22657
22778
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DepositSol;
|
|
22658
|
-
const data = encodeData(type, { lamports });
|
|
22779
|
+
const data = encodeData(type, { lamports: toBN(lamports) });
|
|
22659
22780
|
const keys = [
|
|
22660
22781
|
{ pubkey: stakePool, isSigner: false, isWritable: true },
|
|
22661
22782
|
{ pubkey: withdrawAuthority, isSigner: false, isWritable: false },
|
|
@@ -22688,8 +22809,8 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22688
22809
|
var _a;
|
|
22689
22810
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DepositWsolWithSession;
|
|
22690
22811
|
const data = encodeData(type, {
|
|
22691
|
-
lamportsIn: params.lamportsIn,
|
|
22692
|
-
minimumPoolTokensOut: params.minimumPoolTokensOut,
|
|
22812
|
+
lamportsIn: toBN(params.lamportsIn),
|
|
22813
|
+
minimumPoolTokensOut: toBN(params.minimumPoolTokensOut),
|
|
22693
22814
|
});
|
|
22694
22815
|
const keys = [
|
|
22695
22816
|
{ pubkey: params.stakePool, isSigner: false, isWritable: true },
|
|
@@ -22731,7 +22852,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22731
22852
|
static withdrawStake(params) {
|
|
22732
22853
|
const { programId, stakePool, validatorList, withdrawAuthority, validatorStake, destinationStake, destinationStakeAuthority, sourceTransferAuthority, sourcePoolAccount, managerFeeAccount, poolMint, poolTokens, } = params;
|
|
22733
22854
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawStake;
|
|
22734
|
-
const data = encodeData(type, { poolTokens });
|
|
22855
|
+
const data = encodeData(type, { poolTokens: toBN(poolTokens) });
|
|
22735
22856
|
const keys = [
|
|
22736
22857
|
{ pubkey: stakePool, isSigner: false, isWritable: true },
|
|
22737
22858
|
{ pubkey: validatorList, isSigner: false, isWritable: true },
|
|
@@ -22759,7 +22880,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22759
22880
|
static withdrawSol(params) {
|
|
22760
22881
|
const { programId, stakePool, withdrawAuthority, sourceTransferAuthority, sourcePoolAccount, reserveStake, destinationSystemAccount, managerFeeAccount, solWithdrawAuthority, poolMint, poolTokens, } = params;
|
|
22761
22882
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawSol;
|
|
22762
|
-
const data = encodeData(type, { poolTokens });
|
|
22883
|
+
const data = encodeData(type, { poolTokens: toBN(poolTokens) });
|
|
22763
22884
|
const keys = [
|
|
22764
22885
|
{ pubkey: stakePool, isSigner: false, isWritable: true },
|
|
22765
22886
|
{ pubkey: withdrawAuthority, isSigner: false, isWritable: false },
|
|
@@ -22794,8 +22915,8 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22794
22915
|
static withdrawWsolWithSession(params) {
|
|
22795
22916
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawWsolWithSession;
|
|
22796
22917
|
const data = encodeData(type, {
|
|
22797
|
-
poolTokensIn: params.poolTokensIn,
|
|
22798
|
-
minimumLamportsOut: params.minimumLamportsOut,
|
|
22918
|
+
poolTokensIn: toBN(params.poolTokensIn),
|
|
22919
|
+
minimumLamportsOut: toBN(params.minimumLamportsOut),
|
|
22799
22920
|
});
|
|
22800
22921
|
const keys = [
|
|
22801
22922
|
{ pubkey: params.stakePool, isSigner: false, isWritable: true },
|
|
@@ -22832,14 +22953,14 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22832
22953
|
}
|
|
22833
22954
|
/**
|
|
22834
22955
|
* Creates a transaction instruction to withdraw stake from a stake pool using a Fogo session.
|
|
22835
|
-
* The stake account is created as a PDA and rent is
|
|
22956
|
+
* The stake account is created as a PDA and rent is funded from the reserve.
|
|
22836
22957
|
*/
|
|
22837
22958
|
static withdrawStakeWithSession(params) {
|
|
22838
22959
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawStakeWithSession;
|
|
22839
22960
|
const data = encodeData(type, {
|
|
22840
|
-
poolTokensIn: params.poolTokensIn,
|
|
22841
|
-
minimumLamportsOut: params.minimumLamportsOut,
|
|
22842
|
-
userStakeSeed: params.userStakeSeed,
|
|
22961
|
+
poolTokensIn: toBN(params.poolTokensIn),
|
|
22962
|
+
minimumLamportsOut: toBN(params.minimumLamportsOut),
|
|
22963
|
+
userStakeSeed: toBN(params.userStakeSeed),
|
|
22843
22964
|
});
|
|
22844
22965
|
const keys = [
|
|
22845
22966
|
{ pubkey: params.stakePool, isSigner: false, isWritable: true },
|
|
@@ -22847,17 +22968,19 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22847
22968
|
{ pubkey: params.withdrawAuthority, isSigner: false, isWritable: false },
|
|
22848
22969
|
{ pubkey: params.stakeToSplit, isSigner: false, isWritable: true },
|
|
22849
22970
|
{ pubkey: params.stakeToReceive, isSigner: false, isWritable: true },
|
|
22850
|
-
{ pubkey: params.sessionSigner, isSigner: true, isWritable: false }, // user_stake_authority_info
|
|
22851
|
-
{ pubkey: params.sessionSigner, isSigner: false, isWritable: false }, // user_transfer_authority_info (
|
|
22971
|
+
{ pubkey: params.sessionSigner, isSigner: true, isWritable: false }, // user_stake_authority_info
|
|
22972
|
+
{ pubkey: params.sessionSigner, isSigner: false, isWritable: false }, // user_transfer_authority_info (unused in session path)
|
|
22852
22973
|
{ pubkey: params.burnFromPool, isSigner: false, isWritable: true },
|
|
22853
22974
|
{ pubkey: params.managerFeeAccount, isSigner: false, isWritable: true },
|
|
22854
22975
|
{ pubkey: params.poolMint, isSigner: false, isWritable: true },
|
|
22855
22976
|
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
|
|
22856
22977
|
{ pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
|
|
22857
22978
|
{ pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
|
|
22979
|
+
// Session-specific accounts
|
|
22858
22980
|
{ pubkey: params.programSigner, isSigner: false, isWritable: false },
|
|
22859
22981
|
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
|
|
22860
|
-
{ pubkey: params.
|
|
22982
|
+
{ pubkey: params.reserveStake, isSigner: false, isWritable: true },
|
|
22983
|
+
{ pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
|
|
22861
22984
|
];
|
|
22862
22985
|
return new TransactionInstruction({
|
|
22863
22986
|
programId: params.programId,
|
|
@@ -22872,8 +22995,8 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
22872
22995
|
static withdrawFromStakeAccountWithSession(params) {
|
|
22873
22996
|
const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawFromStakeAccountWithSession;
|
|
22874
22997
|
const data = encodeData(type, {
|
|
22875
|
-
lamports: params.lamports,
|
|
22876
|
-
userStakeSeed: params.userStakeSeed,
|
|
22998
|
+
lamports: toBN(params.lamports),
|
|
22999
|
+
userStakeSeed: toBN(params.userStakeSeed),
|
|
22877
23000
|
});
|
|
22878
23001
|
const keys = [
|
|
22879
23002
|
{ pubkey: params.userStakeAccount, isSigner: false, isWritable: true },
|
|
@@ -23162,10 +23285,18 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
23162
23285
|
if (!skipBalanceCheck) {
|
|
23163
23286
|
const tokenAccountInfo = await connection.getTokenAccountBalance(wsolTokenAccount, 'confirmed');
|
|
23164
23287
|
const wsolBalance = tokenAccountInfo
|
|
23165
|
-
?
|
|
23166
|
-
: 0;
|
|
23167
|
-
|
|
23168
|
-
|
|
23288
|
+
? BigInt(tokenAccountInfo.value.amount)
|
|
23289
|
+
: BigInt(0);
|
|
23290
|
+
// Convert lamports to BigInt for comparison
|
|
23291
|
+
const lamportsBigInt = typeof lamports === 'bigint'
|
|
23292
|
+
? lamports
|
|
23293
|
+
: typeof lamports === 'string'
|
|
23294
|
+
? BigInt(lamports)
|
|
23295
|
+
: BN.isBN(lamports)
|
|
23296
|
+
? BigInt(lamports.toString())
|
|
23297
|
+
: BigInt(lamports);
|
|
23298
|
+
if (wsolBalance < lamportsBigInt) {
|
|
23299
|
+
throw new Error(`Not enough WSOL to deposit into pool. Maximum deposit amount is ${lamportsToSol(Number(wsolBalance))} WSOL.`);
|
|
23169
23300
|
}
|
|
23170
23301
|
}
|
|
23171
23302
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
@@ -23211,7 +23342,15 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
23211
23342
|
*/
|
|
23212
23343
|
async function depositSol(connection, stakePoolAddress, from, lamports, destinationTokenAccount, referrerTokenAccount, depositAuthority) {
|
|
23213
23344
|
const fromBalance = await connection.getBalance(from, 'confirmed');
|
|
23214
|
-
|
|
23345
|
+
// Convert lamports to BigInt for comparison
|
|
23346
|
+
const lamportsBigInt = typeof lamports === 'bigint'
|
|
23347
|
+
? lamports
|
|
23348
|
+
: typeof lamports === 'string'
|
|
23349
|
+
? BigInt(lamports)
|
|
23350
|
+
: BN.isBN(lamports)
|
|
23351
|
+
? BigInt(lamports.toString())
|
|
23352
|
+
: BigInt(lamports);
|
|
23353
|
+
if (BigInt(fromBalance) < lamportsBigInt) {
|
|
23215
23354
|
throw new Error(`Not enough SOL to deposit into pool. Maximum deposit amount is ${lamportsToSol(fromBalance)} SOL.`);
|
|
23216
23355
|
}
|
|
23217
23356
|
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
@@ -23225,7 +23364,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
23225
23364
|
instructions.push(SystemProgram.transfer({
|
|
23226
23365
|
fromPubkey: from,
|
|
23227
23366
|
toPubkey: userSolTransfer.publicKey,
|
|
23228
|
-
lamports,
|
|
23367
|
+
lamports: lamportsBigInt,
|
|
23229
23368
|
}));
|
|
23230
23369
|
// Create token account if not specified
|
|
23231
23370
|
if (!destinationTokenAccount) {
|
|
@@ -23597,37 +23736,51 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
23597
23736
|
* Withdraws stake from a stake pool using a Fogo session.
|
|
23598
23737
|
*
|
|
23599
23738
|
* The on-chain program creates stake account PDAs. The rent for these accounts
|
|
23600
|
-
* is
|
|
23739
|
+
* is funded from the reserve stake.
|
|
23601
23740
|
*
|
|
23602
23741
|
* @param connection - Solana connection
|
|
23603
23742
|
* @param stakePoolAddress - The stake pool to withdraw from
|
|
23604
23743
|
* @param signerOrSession - The session signer public key
|
|
23605
23744
|
* @param userPubkey - User's wallet (used for PDA derivation and token ownership)
|
|
23606
|
-
* @param payer - Payer for stake account rent (typically paymaster)
|
|
23607
23745
|
* @param amount - Amount of pool tokens to withdraw
|
|
23608
23746
|
* @param userStakeSeedStart - Starting seed for user stake PDA derivation (default: 0)
|
|
23609
23747
|
* @param useReserve - Whether to withdraw from reserve (default: false)
|
|
23610
23748
|
* @param voteAccountAddress - Optional specific validator to withdraw from
|
|
23611
23749
|
* @param minimumLamportsOut - Minimum lamports to receive (slippage protection)
|
|
23612
23750
|
* @param validatorComparator - Optional comparator for validator selection
|
|
23751
|
+
* @param allowPartial - If true, returns partial results instead of throwing when not enough stake available
|
|
23613
23752
|
*/
|
|
23614
|
-
async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSession, userPubkey,
|
|
23615
|
-
|
|
23753
|
+
async function withdrawStakeWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, userStakeSeedStart = 0, useReserve = false, voteAccountAddress, minimumLamportsOut = 0, validatorComparator, allowPartial = false) {
|
|
23754
|
+
var _c;
|
|
23616
23755
|
const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
|
|
23756
|
+
// First fetch: get stake pool to know other account addresses
|
|
23757
|
+
const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
|
|
23617
23758
|
const stakePool = stakePoolAccount.account.data;
|
|
23618
23759
|
const poolTokens = solToLamports(amount);
|
|
23619
23760
|
const poolAmount = new BN(poolTokens);
|
|
23620
23761
|
const poolTokenAccount = getAssociatedTokenAddressSync(stakePool.poolMint, userPubkey);
|
|
23621
|
-
|
|
23762
|
+
// Second fetch: get ALL remaining data in parallel
|
|
23763
|
+
const [tokenAccount, stakeAccountRentExemption, validatorListAcc, stakeMinimumDelegationResponse] = await Promise.all([
|
|
23764
|
+
getAccount(connection, poolTokenAccount),
|
|
23765
|
+
connection.getMinimumBalanceForRentExemption(StakeProgram.space),
|
|
23766
|
+
connection.getAccountInfo(stakePool.validatorList),
|
|
23767
|
+
connection.getStakeMinimumDelegation(),
|
|
23768
|
+
]);
|
|
23769
|
+
// Pre-fetch data to avoid duplicate RPC calls in prepareWithdrawAccounts
|
|
23770
|
+
const prefetchedData = {
|
|
23771
|
+
validatorListData: (_c = validatorListAcc === null || validatorListAcc === void 0 ? void 0 : validatorListAcc.data) !== null && _c !== void 0 ? _c : null,
|
|
23772
|
+
minBalanceForRentExemption: stakeAccountRentExemption,
|
|
23773
|
+
stakeMinimumDelegation: Number(stakeMinimumDelegationResponse.value),
|
|
23774
|
+
};
|
|
23622
23775
|
if (tokenAccount.amount < poolTokens) {
|
|
23623
23776
|
throw new Error(`Not enough token balance to withdraw ${amount} pool tokens.
|
|
23624
23777
|
Maximum withdraw amount is ${lamportsToSol(tokenAccount.amount)} pool tokens.`);
|
|
23625
23778
|
}
|
|
23626
23779
|
const [programSigner] = PublicKey.findProgramAddressSync([Buffer.from('fogo_session_program_signer')], stakePoolProgramId);
|
|
23627
23780
|
const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
|
|
23628
|
-
const stakeAccountRentExemption = await connection.getMinimumBalanceForRentExemption(StakeProgram.space);
|
|
23629
23781
|
// Determine which stake accounts to withdraw from
|
|
23630
23782
|
const withdrawAccounts = [];
|
|
23783
|
+
let partialRemainingAmount;
|
|
23631
23784
|
if (useReserve) {
|
|
23632
23785
|
withdrawAccounts.push({
|
|
23633
23786
|
stakeAddress: stakePool.reserveStake,
|
|
@@ -23658,7 +23811,14 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
23658
23811
|
}
|
|
23659
23812
|
else {
|
|
23660
23813
|
// Get the list of accounts to withdraw from automatically
|
|
23661
|
-
|
|
23814
|
+
if (allowPartial) {
|
|
23815
|
+
const result = await prepareWithdrawAccounts(connection, stakePool, stakePoolAddress, poolAmount, validatorComparator, poolTokenAccount.equals(stakePool.managerFeeAccount), true, prefetchedData);
|
|
23816
|
+
withdrawAccounts.push(...result.withdrawAccounts);
|
|
23817
|
+
partialRemainingAmount = result.remainingAmount;
|
|
23818
|
+
}
|
|
23819
|
+
else {
|
|
23820
|
+
withdrawAccounts.push(...(await prepareWithdrawAccounts(connection, stakePool, stakePoolAddress, poolAmount, validatorComparator, poolTokenAccount.equals(stakePool.managerFeeAccount), undefined, prefetchedData)));
|
|
23821
|
+
}
|
|
23662
23822
|
}
|
|
23663
23823
|
const instructions = [];
|
|
23664
23824
|
const stakeAccountPubkeys = [];
|
|
@@ -23675,7 +23835,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
23675
23835
|
const stakeReceiverPubkey = findUserStakeProgramAddress(stakePoolProgramId, userPubkey, userStakeSeed);
|
|
23676
23836
|
stakeAccountPubkeys.push(stakeReceiverPubkey);
|
|
23677
23837
|
userStakeSeeds.push(userStakeSeed);
|
|
23678
|
-
// The on-chain program creates the stake account PDA and rent is
|
|
23838
|
+
// The on-chain program creates the stake account PDA and rent is funded from reserve.
|
|
23679
23839
|
instructions.push(StakePoolInstruction.withdrawStakeWithSession({
|
|
23680
23840
|
programId: stakePoolProgramId,
|
|
23681
23841
|
stakePool: stakePoolAddress,
|
|
@@ -23689,7 +23849,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
23689
23849
|
poolMint: stakePool.poolMint,
|
|
23690
23850
|
tokenProgramId: stakePool.tokenProgramId,
|
|
23691
23851
|
programSigner,
|
|
23692
|
-
|
|
23852
|
+
reserveStake: stakePool.reserveStake,
|
|
23693
23853
|
poolTokensIn: withdrawAccount.poolAmount.toNumber(),
|
|
23694
23854
|
minimumLamportsOut,
|
|
23695
23855
|
userStakeSeed,
|
|
@@ -23700,6 +23860,7 @@ var solanaStakePool = (function (exports, node_buffer) {
|
|
|
23700
23860
|
instructions,
|
|
23701
23861
|
stakeAccountPubkeys,
|
|
23702
23862
|
userStakeSeeds,
|
|
23863
|
+
remainingPoolTokens: partialRemainingAmount ? lamportsToSol(partialRemainingAmount) : 0,
|
|
23703
23864
|
};
|
|
23704
23865
|
}
|
|
23705
23866
|
async function addValidatorToPool(connection, stakePoolAddress, validatorVote, seed) {
|