@ignitionfi/spl-stake-pool 1.1.8

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.
@@ -0,0 +1,2524 @@
1
+ import { TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, createAssociatedTokenAccountIdempotentInstruction, NATIVE_MINT, getAccount, createApproveInstruction } from '@solana/spl-token';
2
+ import { PublicKey, LAMPORTS_PER_SOL, StakeProgram, Keypair, SystemProgram, SYSVAR_RENT_PUBKEY, SYSVAR_CLOCK_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY, STAKE_CONFIG_ID, TransactionInstruction, StakeAuthorizationLayout } from '@solana/web3.js';
3
+ import BN from 'bn.js';
4
+ import { Buffer as Buffer$1 } from 'node:buffer';
5
+ import * as BufferLayout from '@solana/buffer-layout';
6
+ import { blob, u32, struct, seq, offset, Layout, u8 } from 'buffer-layout';
7
+
8
+ /**
9
+ * A `StructFailure` represents a single specific failure in validation.
10
+ */
11
+ /**
12
+ * `StructError` objects are thrown (or returned) when validation fails.
13
+ *
14
+ * Validation logic is design to exit early for maximum performance. The error
15
+ * represents the first error encountered during validation. For more detail,
16
+ * the `error.failures` property is a generator function that can be run to
17
+ * continue validation and receive all the failures in the data.
18
+ */
19
+ class StructError extends TypeError {
20
+ constructor(failure, failures) {
21
+ let cached;
22
+ const { message, explanation, ...rest } = failure;
23
+ const { path } = failure;
24
+ const msg = path.length === 0 ? message : `At path: ${path.join('.')} -- ${message}`;
25
+ super(explanation ?? msg);
26
+ if (explanation != null)
27
+ this.cause = msg;
28
+ Object.assign(this, rest);
29
+ this.name = this.constructor.name;
30
+ this.failures = () => {
31
+ return (cached ?? (cached = [failure, ...failures()]));
32
+ };
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Check if a value is an iterator.
38
+ */
39
+ function isIterable(x) {
40
+ return isObject(x) && typeof x[Symbol.iterator] === 'function';
41
+ }
42
+ /**
43
+ * Check if a value is a plain object.
44
+ */
45
+ function isObject(x) {
46
+ return typeof x === 'object' && x != null;
47
+ }
48
+ /**
49
+ * Check if a value is a non-array object.
50
+ */
51
+ function isNonArrayObject(x) {
52
+ return isObject(x) && !Array.isArray(x);
53
+ }
54
+ /**
55
+ * Return a value as a printable string.
56
+ */
57
+ function print(value) {
58
+ if (typeof value === 'symbol') {
59
+ return value.toString();
60
+ }
61
+ return typeof value === 'string' ? JSON.stringify(value) : `${value}`;
62
+ }
63
+ /**
64
+ * Shifts (removes and returns) the first value from the `input` iterator.
65
+ * Like `Array.prototype.shift()` but for an `Iterator`.
66
+ */
67
+ function shiftIterator(input) {
68
+ const { done, value } = input.next();
69
+ return done ? undefined : value;
70
+ }
71
+ /**
72
+ * Convert a single validation result to a failure.
73
+ */
74
+ function toFailure(result, context, struct, value) {
75
+ if (result === true) {
76
+ return;
77
+ }
78
+ else if (result === false) {
79
+ result = {};
80
+ }
81
+ else if (typeof result === 'string') {
82
+ result = { message: result };
83
+ }
84
+ const { path, branch } = context;
85
+ const { type } = struct;
86
+ const { refinement, message = `Expected a value of type \`${type}\`${refinement ? ` with refinement \`${refinement}\`` : ''}, but received: \`${print(value)}\``, } = result;
87
+ return {
88
+ value,
89
+ type,
90
+ refinement,
91
+ key: path[path.length - 1],
92
+ path,
93
+ branch,
94
+ ...result,
95
+ message,
96
+ };
97
+ }
98
+ /**
99
+ * Convert a validation result to an iterable of failures.
100
+ */
101
+ function* toFailures(result, context, struct, value) {
102
+ if (!isIterable(result)) {
103
+ result = [result];
104
+ }
105
+ for (const r of result) {
106
+ const failure = toFailure(r, context, struct, value);
107
+ if (failure) {
108
+ yield failure;
109
+ }
110
+ }
111
+ }
112
+ /**
113
+ * Check a value against a struct, traversing deeply into nested values, and
114
+ * returning an iterator of failures or success.
115
+ */
116
+ function* run(value, struct, options = {}) {
117
+ const { path = [], branch = [value], coerce = false, mask = false } = options;
118
+ const ctx = { path, branch, mask };
119
+ if (coerce) {
120
+ value = struct.coercer(value, ctx);
121
+ }
122
+ let status = 'valid';
123
+ for (const failure of struct.validator(value, ctx)) {
124
+ failure.explanation = options.message;
125
+ status = 'not_valid';
126
+ yield [failure, undefined];
127
+ }
128
+ for (let [k, v, s] of struct.entries(value, ctx)) {
129
+ const ts = run(v, s, {
130
+ path: k === undefined ? path : [...path, k],
131
+ branch: k === undefined ? branch : [...branch, v],
132
+ coerce,
133
+ mask,
134
+ message: options.message,
135
+ });
136
+ for (const t of ts) {
137
+ if (t[0]) {
138
+ status = t[0].refinement != null ? 'not_refined' : 'not_valid';
139
+ yield [t[0], undefined];
140
+ }
141
+ else if (coerce) {
142
+ v = t[1];
143
+ if (k === undefined) {
144
+ value = v;
145
+ }
146
+ else if (value instanceof Map) {
147
+ value.set(k, v);
148
+ }
149
+ else if (value instanceof Set) {
150
+ value.add(v);
151
+ }
152
+ else if (isObject(value)) {
153
+ if (v !== undefined || k in value)
154
+ value[k] = v;
155
+ }
156
+ }
157
+ }
158
+ }
159
+ if (status !== 'not_valid') {
160
+ for (const failure of struct.refiner(value, ctx)) {
161
+ failure.explanation = options.message;
162
+ status = 'not_refined';
163
+ yield [failure, undefined];
164
+ }
165
+ }
166
+ if (status === 'valid') {
167
+ yield [undefined, value];
168
+ }
169
+ }
170
+
171
+ /**
172
+ * `Struct` objects encapsulate the validation logic for a specific type of
173
+ * values. Once constructed, you use the `assert`, `is` or `validate` helpers to
174
+ * validate unknown input data against the struct.
175
+ */
176
+ class Struct {
177
+ constructor(props) {
178
+ const { type, schema, validator, refiner, coercer = (value) => value, entries = function* () { }, } = props;
179
+ this.type = type;
180
+ this.schema = schema;
181
+ this.entries = entries;
182
+ this.coercer = coercer;
183
+ if (validator) {
184
+ this.validator = (value, context) => {
185
+ const result = validator(value, context);
186
+ return toFailures(result, context, this, value);
187
+ };
188
+ }
189
+ else {
190
+ this.validator = () => [];
191
+ }
192
+ if (refiner) {
193
+ this.refiner = (value, context) => {
194
+ const result = refiner(value, context);
195
+ return toFailures(result, context, this, value);
196
+ };
197
+ }
198
+ else {
199
+ this.refiner = () => [];
200
+ }
201
+ }
202
+ /**
203
+ * Assert that a value passes the struct's validation, throwing if it doesn't.
204
+ */
205
+ assert(value, message) {
206
+ return assert(value, this, message);
207
+ }
208
+ /**
209
+ * Create a value with the struct's coercion logic, then validate it.
210
+ */
211
+ create(value, message) {
212
+ return create(value, this, message);
213
+ }
214
+ /**
215
+ * Check if a value passes the struct's validation.
216
+ */
217
+ is(value) {
218
+ return is(value, this);
219
+ }
220
+ /**
221
+ * Mask a value, coercing and validating it, but returning only the subset of
222
+ * properties defined by the struct's schema. Masking applies recursively to
223
+ * props of `object` structs only.
224
+ */
225
+ mask(value, message) {
226
+ return mask(value, this, message);
227
+ }
228
+ /**
229
+ * Validate a value with the struct's validation logic, returning a tuple
230
+ * representing the result.
231
+ *
232
+ * You may optionally pass `true` for the `coerce` argument to coerce
233
+ * the value before attempting to validate it. If you do, the result will
234
+ * contain the coerced result when successful. Also, `mask` will turn on
235
+ * masking of the unknown `object` props recursively if passed.
236
+ */
237
+ validate(value, options = {}) {
238
+ return validate(value, this, options);
239
+ }
240
+ }
241
+ /**
242
+ * Assert that a value passes a struct, throwing if it doesn't.
243
+ */
244
+ function assert(value, struct, message) {
245
+ const result = validate(value, struct, { message });
246
+ if (result[0]) {
247
+ throw result[0];
248
+ }
249
+ }
250
+ /**
251
+ * Create a value with the coercion logic of struct and validate it.
252
+ */
253
+ function create(value, struct, message) {
254
+ const result = validate(value, struct, { coerce: true, message });
255
+ if (result[0]) {
256
+ throw result[0];
257
+ }
258
+ else {
259
+ return result[1];
260
+ }
261
+ }
262
+ /**
263
+ * Mask a value, returning only the subset of properties defined by a struct.
264
+ */
265
+ function mask(value, struct, message) {
266
+ const result = validate(value, struct, { coerce: true, mask: true, message });
267
+ if (result[0]) {
268
+ throw result[0];
269
+ }
270
+ else {
271
+ return result[1];
272
+ }
273
+ }
274
+ /**
275
+ * Check if a value passes a struct.
276
+ */
277
+ function is(value, struct) {
278
+ const result = validate(value, struct);
279
+ return !result[0];
280
+ }
281
+ /**
282
+ * Validate a value against a struct, returning an error if invalid, or the
283
+ * value (with potential coercion) if valid.
284
+ */
285
+ function validate(value, struct, options = {}) {
286
+ const tuples = run(value, struct, options);
287
+ const tuple = shiftIterator(tuples);
288
+ if (tuple[0]) {
289
+ const error = new StructError(tuple[0], function* () {
290
+ for (const t of tuples) {
291
+ if (t[0]) {
292
+ yield t[0];
293
+ }
294
+ }
295
+ });
296
+ return [error, undefined];
297
+ }
298
+ else {
299
+ const v = tuple[1];
300
+ return [undefined, v];
301
+ }
302
+ }
303
+ /**
304
+ * Define a new struct type with a custom validation function.
305
+ */
306
+ function define(name, validator) {
307
+ return new Struct({ type: name, schema: null, validator });
308
+ }
309
+ function enums(values) {
310
+ const schema = {};
311
+ const description = values.map((v) => print(v)).join();
312
+ for (const key of values) {
313
+ schema[key] = key;
314
+ }
315
+ return new Struct({
316
+ type: 'enums',
317
+ schema,
318
+ validator(value) {
319
+ return (values.includes(value) ||
320
+ `Expected one of \`${description}\`, but received: ${print(value)}`);
321
+ },
322
+ });
323
+ }
324
+ /**
325
+ * Ensure that a value is an instance of a specific class.
326
+ */
327
+ function instance(Class) {
328
+ return define('instance', (value) => {
329
+ return (value instanceof Class ||
330
+ `Expected a \`${Class.name}\` instance, but received: ${print(value)}`);
331
+ });
332
+ }
333
+ /**
334
+ * Augment an existing struct to allow `null` values.
335
+ */
336
+ function nullable(struct) {
337
+ return new Struct({
338
+ ...struct,
339
+ validator: (value, ctx) => value === null || struct.validator(value, ctx),
340
+ refiner: (value, ctx) => value === null || struct.refiner(value, ctx),
341
+ });
342
+ }
343
+ /**
344
+ * Ensure that a value is a number.
345
+ */
346
+ function number() {
347
+ return define('number', (value) => {
348
+ return ((typeof value === 'number' && !isNaN(value)) ||
349
+ `Expected a number, but received: ${print(value)}`);
350
+ });
351
+ }
352
+ /**
353
+ * Augment a struct to allow `undefined` values.
354
+ */
355
+ function optional(struct) {
356
+ return new Struct({
357
+ ...struct,
358
+ validator: (value, ctx) => value === undefined || struct.validator(value, ctx),
359
+ refiner: (value, ctx) => value === undefined || struct.refiner(value, ctx),
360
+ });
361
+ }
362
+ /**
363
+ * Ensure that a value is a string.
364
+ */
365
+ function string() {
366
+ return define('string', (value) => {
367
+ return (typeof value === 'string' ||
368
+ `Expected a string, but received: ${print(value)}`);
369
+ });
370
+ }
371
+ /**
372
+ * Ensure that a value has a set of known properties of specific types.
373
+ *
374
+ * Note: Unrecognized properties are allowed and untouched. This is similar to
375
+ * how TypeScript's structural typing works.
376
+ */
377
+ function type(schema) {
378
+ const keys = Object.keys(schema);
379
+ return new Struct({
380
+ type: 'type',
381
+ schema,
382
+ *entries(value) {
383
+ if (isObject(value)) {
384
+ for (const k of keys) {
385
+ yield [k, value[k], schema[k]];
386
+ }
387
+ }
388
+ },
389
+ validator(value) {
390
+ return (isNonArrayObject(value) ||
391
+ `Expected an object, but received: ${print(value)}`);
392
+ },
393
+ coercer(value) {
394
+ return isNonArrayObject(value) ? { ...value } : value;
395
+ },
396
+ });
397
+ }
398
+
399
+ /**
400
+ * Augment a `Struct` to add an additional coercion step to its input.
401
+ *
402
+ * This allows you to transform input data before validating it, to increase the
403
+ * likelihood that it passes validation—for example for default values, parsing
404
+ * different formats, etc.
405
+ *
406
+ * Note: You must use `create(value, Struct)` on the value to have the coercion
407
+ * take effect! Using simply `assert()` or `is()` will not use coercion.
408
+ */
409
+ function coerce(struct, condition, coercer) {
410
+ return new Struct({
411
+ ...struct,
412
+ coercer: (value, ctx) => {
413
+ return is(value, condition)
414
+ ? struct.coercer(coercer(value, ctx), ctx)
415
+ : struct.coercer(value, ctx);
416
+ },
417
+ });
418
+ }
419
+
420
+ // Public key that identifies the metadata program.
421
+ const METADATA_PROGRAM_ID = new PublicKey('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s');
422
+ const METADATA_MAX_NAME_LENGTH = 32;
423
+ const METADATA_MAX_SYMBOL_LENGTH = 10;
424
+ const METADATA_MAX_URI_LENGTH = 200;
425
+ // Public key that identifies the SPL Stake Pool program.
426
+ const STAKE_POOL_PROGRAM_ID = new PublicKey('SP1s4uFeTAX9jsXXmwyDs1gxYYf7cdDZ8qHUHVxE1yr');
427
+ // Public key that identifies the SPL Stake Pool program deployed to devnet.
428
+ const DEVNET_STAKE_POOL_PROGRAM_ID = new PublicKey('DPoo15wWDqpPJJtS2MUZ49aRxqz5ZaaJCJP4z8bLuib');
429
+ // Maximum number of validators to update during UpdateValidatorListBalance.
430
+ const MAX_VALIDATORS_TO_UPDATE = 4;
431
+ // Seed for ephemeral stake account
432
+ const EPHEMERAL_STAKE_SEED_PREFIX = Buffer$1.from('ephemeral');
433
+ // Seed used to derive transient stake accounts.
434
+ const TRANSIENT_STAKE_SEED_PREFIX = Buffer$1.from('transient');
435
+ // Minimum amount of staked SOL required in a validator stake account to allow
436
+ // for merges without a mismatch on credits observed
437
+ const MINIMUM_ACTIVE_STAKE = LAMPORTS_PER_SOL;
438
+
439
+ /**
440
+ * Populate a buffer of instruction data using an InstructionType
441
+ * @internal
442
+ */
443
+ function encodeData(type, fields) {
444
+ const allocLength = type.layout.span;
445
+ const data = Buffer$1.alloc(allocLength);
446
+ const layoutFields = Object.assign({ instruction: type.index }, fields);
447
+ type.layout.encode(layoutFields, data);
448
+ return data;
449
+ }
450
+ /**
451
+ * Decode instruction data buffer using an InstructionType
452
+ * @internal
453
+ */
454
+ function decodeData(type, buffer) {
455
+ let data;
456
+ try {
457
+ data = type.layout.decode(buffer);
458
+ }
459
+ catch (err) {
460
+ throw new Error(`invalid instruction; ${err}`);
461
+ }
462
+ if (data.instruction !== type.index) {
463
+ throw new Error(`invalid instruction; instruction index mismatch ${data.instruction} != ${type.index}`);
464
+ }
465
+ return data;
466
+ }
467
+
468
+ function solToLamports(amount) {
469
+ if (isNaN(amount)) {
470
+ return Number(0);
471
+ }
472
+ return Number(amount * LAMPORTS_PER_SOL);
473
+ }
474
+ function lamportsToSol(lamports) {
475
+ if (typeof lamports === 'number') {
476
+ return Math.abs(lamports) / LAMPORTS_PER_SOL;
477
+ }
478
+ if (typeof lamports === 'bigint') {
479
+ return Math.abs(Number(lamports)) / LAMPORTS_PER_SOL;
480
+ }
481
+ let signMultiplier = 1;
482
+ if (lamports.isNeg()) {
483
+ signMultiplier = -1;
484
+ }
485
+ const absLamports = lamports.abs();
486
+ const lamportsString = absLamports.toString(10).padStart(10, '0');
487
+ const splitIndex = lamportsString.length - 9;
488
+ const solString = `${lamportsString.slice(0, splitIndex)}.${lamportsString.slice(splitIndex)}`;
489
+ return signMultiplier * Number.parseFloat(solString);
490
+ }
491
+
492
+ /**
493
+ * Generates the wSOL transient program address for the stake pool
494
+ */
495
+ function findWsolTransientProgramAddress(programId, userPubkey) {
496
+ const [publicKey] = PublicKey.findProgramAddressSync([Buffer$1.from('transient_wsol'), userPubkey.toBuffer()], programId);
497
+ return publicKey;
498
+ }
499
+ /**
500
+ * Generates the withdraw authority program address for the stake pool
501
+ */
502
+ async function findWithdrawAuthorityProgramAddress(programId, stakePoolAddress) {
503
+ const [publicKey] = PublicKey.findProgramAddressSync([stakePoolAddress.toBuffer(), Buffer$1.from('withdraw')], programId);
504
+ return publicKey;
505
+ }
506
+ /**
507
+ * Generates the stake program address for a validator's vote account
508
+ */
509
+ async function findStakeProgramAddress(programId, voteAccountAddress, stakePoolAddress, seed) {
510
+ const [publicKey] = PublicKey.findProgramAddressSync([
511
+ voteAccountAddress.toBuffer(),
512
+ stakePoolAddress.toBuffer(),
513
+ seed ? new BN(seed).toArrayLike(Buffer$1, 'le', 4) : Buffer$1.alloc(0),
514
+ ], programId);
515
+ return publicKey;
516
+ }
517
+ /**
518
+ * Generates the stake program address for a validator's vote account
519
+ */
520
+ async function findTransientStakeProgramAddress(programId, voteAccountAddress, stakePoolAddress, seed) {
521
+ const [publicKey] = PublicKey.findProgramAddressSync([
522
+ TRANSIENT_STAKE_SEED_PREFIX,
523
+ voteAccountAddress.toBuffer(),
524
+ stakePoolAddress.toBuffer(),
525
+ seed.toArrayLike(Buffer$1, 'le', 8),
526
+ ], programId);
527
+ return publicKey;
528
+ }
529
+ /**
530
+ * Generates the ephemeral program address for stake pool redelegation
531
+ */
532
+ async function findEphemeralStakeProgramAddress(programId, stakePoolAddress, seed) {
533
+ const [publicKey] = PublicKey.findProgramAddressSync([EPHEMERAL_STAKE_SEED_PREFIX, stakePoolAddress.toBuffer(), seed.toArrayLike(Buffer$1, 'le', 8)], programId);
534
+ return publicKey;
535
+ }
536
+ /**
537
+ * Generates the metadata program address for the stake pool
538
+ */
539
+ function findMetadataAddress(stakePoolMintAddress) {
540
+ const [publicKey] = PublicKey.findProgramAddressSync([Buffer$1.from('metadata'), METADATA_PROGRAM_ID.toBuffer(), stakePoolMintAddress.toBuffer()], METADATA_PROGRAM_ID);
541
+ return publicKey;
542
+ }
543
+
544
+ class BNLayout extends Layout {
545
+ constructor(span, signed, property) {
546
+ super(span, property);
547
+ this.blob = blob(span);
548
+ this.signed = signed;
549
+ }
550
+ decode(b, offset = 0) {
551
+ const num = new BN(this.blob.decode(b, offset), 10, 'le');
552
+ if (this.signed) {
553
+ return num.fromTwos(this.span * 8).clone();
554
+ }
555
+ return num;
556
+ }
557
+ encode(src, b, offset = 0) {
558
+ if (this.signed) {
559
+ src = src.toTwos(this.span * 8);
560
+ }
561
+ return this.blob.encode(src.toArrayLike(Buffer, 'le', this.span), b, offset);
562
+ }
563
+ }
564
+ function u64(property) {
565
+ return new BNLayout(8, false, property);
566
+ }
567
+ class WrappedLayout extends Layout {
568
+ constructor(layout, decoder, encoder, property) {
569
+ super(layout.span, property);
570
+ this.layout = layout;
571
+ this.decoder = decoder;
572
+ this.encoder = encoder;
573
+ }
574
+ decode(b, offset) {
575
+ return this.decoder(this.layout.decode(b, offset));
576
+ }
577
+ encode(src, b, offset) {
578
+ return this.layout.encode(this.encoder(src), b, offset);
579
+ }
580
+ getSpan(b, offset) {
581
+ return this.layout.getSpan(b, offset);
582
+ }
583
+ }
584
+ function publicKey(property) {
585
+ return new WrappedLayout(blob(32), (b) => new PublicKey(b), (key) => key.toBuffer(), property);
586
+ }
587
+ class OptionLayout extends Layout {
588
+ constructor(layout, property) {
589
+ super(-1, property);
590
+ this.layout = layout;
591
+ this.discriminator = u8();
592
+ }
593
+ encode(src, b, offset = 0) {
594
+ if (src === null || src === undefined) {
595
+ return this.discriminator.encode(0, b, offset);
596
+ }
597
+ this.discriminator.encode(1, b, offset);
598
+ return this.layout.encode(src, b, offset + 1) + 1;
599
+ }
600
+ decode(b, offset = 0) {
601
+ const discriminator = this.discriminator.decode(b, offset);
602
+ if (discriminator === 0) {
603
+ return null;
604
+ }
605
+ else if (discriminator === 1) {
606
+ return this.layout.decode(b, offset + 1);
607
+ }
608
+ throw new Error(`Invalid option ${this.property}`);
609
+ }
610
+ getSpan(b, offset = 0) {
611
+ const discriminator = this.discriminator.decode(b, offset);
612
+ if (discriminator === 0) {
613
+ return 1;
614
+ }
615
+ else if (discriminator === 1) {
616
+ return this.layout.getSpan(b, offset + 1) + 1;
617
+ }
618
+ throw new Error(`Invalid option ${this.property}`);
619
+ }
620
+ }
621
+ function option(layout, property) {
622
+ return new OptionLayout(layout, property);
623
+ }
624
+ function vec(elementLayout, property) {
625
+ const length = u32('length');
626
+ const layout = struct([
627
+ length,
628
+ seq(elementLayout, offset(length, -length.span), 'values'),
629
+ ]);
630
+ return new WrappedLayout(layout, ({ values }) => values, values => ({ values }), property);
631
+ }
632
+
633
+ const feeFields = [u64('denominator'), u64('numerator')];
634
+ var AccountType;
635
+ (function (AccountType) {
636
+ AccountType[AccountType["Uninitialized"] = 0] = "Uninitialized";
637
+ AccountType[AccountType["StakePool"] = 1] = "StakePool";
638
+ AccountType[AccountType["ValidatorList"] = 2] = "ValidatorList";
639
+ })(AccountType || (AccountType = {}));
640
+ const BigNumFromString = coerce(instance(BN), string(), (value) => {
641
+ if (typeof value === 'string') {
642
+ return new BN(value, 10);
643
+ }
644
+ throw new Error('invalid big num');
645
+ });
646
+ const PublicKeyFromString = coerce(instance(PublicKey), string(), value => new PublicKey(value));
647
+ class FutureEpochLayout extends Layout {
648
+ constructor(layout, property) {
649
+ super(-1, property);
650
+ this.layout = layout;
651
+ this.discriminator = u8();
652
+ }
653
+ encode(src, b, offset = 0) {
654
+ if (src === null || src === undefined) {
655
+ return this.discriminator.encode(0, b, offset);
656
+ }
657
+ // This isn't right, but we don't typically encode outside of tests
658
+ this.discriminator.encode(2, b, offset);
659
+ return this.layout.encode(src, b, offset + 1) + 1;
660
+ }
661
+ decode(b, offset = 0) {
662
+ const discriminator = this.discriminator.decode(b, offset);
663
+ if (discriminator === 0) {
664
+ return null;
665
+ }
666
+ else if (discriminator === 1 || discriminator === 2) {
667
+ return this.layout.decode(b, offset + 1);
668
+ }
669
+ throw new Error(`Invalid future epoch ${this.property}`);
670
+ }
671
+ getSpan(b, offset = 0) {
672
+ const discriminator = this.discriminator.decode(b, offset);
673
+ if (discriminator === 0) {
674
+ return 1;
675
+ }
676
+ else if (discriminator === 1 || discriminator === 2) {
677
+ return this.layout.getSpan(b, offset + 1) + 1;
678
+ }
679
+ throw new Error(`Invalid future epoch ${this.property}`);
680
+ }
681
+ }
682
+ function futureEpoch(layout, property) {
683
+ return new FutureEpochLayout(layout, property);
684
+ }
685
+ const StakeAccountType = enums(['uninitialized', 'initialized', 'delegated', 'rewardsPool']);
686
+ const StakeMeta = type({
687
+ rentExemptReserve: BigNumFromString,
688
+ authorized: type({
689
+ staker: PublicKeyFromString,
690
+ withdrawer: PublicKeyFromString,
691
+ }),
692
+ lockup: type({
693
+ unixTimestamp: number(),
694
+ epoch: number(),
695
+ custodian: PublicKeyFromString,
696
+ }),
697
+ });
698
+ const StakeAccountInfo = type({
699
+ meta: StakeMeta,
700
+ stake: nullable(type({
701
+ delegation: type({
702
+ voter: PublicKeyFromString,
703
+ stake: BigNumFromString,
704
+ activationEpoch: BigNumFromString,
705
+ deactivationEpoch: BigNumFromString,
706
+ warmupCooldownRate: number(),
707
+ }),
708
+ creditsObserved: number(),
709
+ })),
710
+ });
711
+ const StakeAccount = type({
712
+ type: StakeAccountType,
713
+ info: optional(StakeAccountInfo),
714
+ });
715
+ const StakePoolLayout = struct([
716
+ u8('accountType'),
717
+ publicKey('manager'),
718
+ publicKey('staker'),
719
+ publicKey('stakeDepositAuthority'),
720
+ u8('stakeWithdrawBumpSeed'),
721
+ publicKey('validatorList'),
722
+ publicKey('reserveStake'),
723
+ publicKey('poolMint'),
724
+ publicKey('managerFeeAccount'),
725
+ publicKey('tokenProgramId'),
726
+ u64('totalLamports'),
727
+ u64('poolTokenSupply'),
728
+ u64('lastUpdateEpoch'),
729
+ struct([u64('unixTimestamp'), u64('epoch'), publicKey('custodian')], 'lockup'),
730
+ struct(feeFields, 'epochFee'),
731
+ futureEpoch(struct(feeFields), 'nextEpochFee'),
732
+ option(publicKey(), 'preferredDepositValidatorVoteAddress'),
733
+ option(publicKey(), 'preferredWithdrawValidatorVoteAddress'),
734
+ struct(feeFields, 'stakeDepositFee'),
735
+ struct(feeFields, 'stakeWithdrawalFee'),
736
+ futureEpoch(struct(feeFields), 'nextStakeWithdrawalFee'),
737
+ u8('stakeReferralFee'),
738
+ option(publicKey(), 'solDepositAuthority'),
739
+ struct(feeFields, 'solDepositFee'),
740
+ u8('solReferralFee'),
741
+ option(publicKey(), 'solWithdrawAuthority'),
742
+ struct(feeFields, 'solWithdrawalFee'),
743
+ futureEpoch(struct(feeFields), 'nextSolWithdrawalFee'),
744
+ u64('lastEpochPoolTokenSupply'),
745
+ u64('lastEpochTotalLamports'),
746
+ ]);
747
+ var ValidatorStakeInfoStatus;
748
+ (function (ValidatorStakeInfoStatus) {
749
+ ValidatorStakeInfoStatus[ValidatorStakeInfoStatus["Active"] = 0] = "Active";
750
+ ValidatorStakeInfoStatus[ValidatorStakeInfoStatus["DeactivatingTransient"] = 1] = "DeactivatingTransient";
751
+ ValidatorStakeInfoStatus[ValidatorStakeInfoStatus["ReadyForRemoval"] = 2] = "ReadyForRemoval";
752
+ })(ValidatorStakeInfoStatus || (ValidatorStakeInfoStatus = {}));
753
+ const ValidatorStakeInfoLayout = struct([
754
+ /// Amount of active stake delegated to this validator
755
+ /// Note that if `last_update_epoch` does not match the current epoch then
756
+ /// this field may not be accurate
757
+ u64('activeStakeLamports'),
758
+ /// Amount of transient stake delegated to this validator
759
+ /// Note that if `last_update_epoch` does not match the current epoch then
760
+ /// this field may not be accurate
761
+ u64('transientStakeLamports'),
762
+ /// Last epoch the active and transient stake lamports fields were updated
763
+ u64('lastUpdateEpoch'),
764
+ /// Start of the validator transient account seed suffixes
765
+ u64('transientSeedSuffixStart'),
766
+ /// End of the validator transient account seed suffixes
767
+ u64('transientSeedSuffixEnd'),
768
+ /// Status of the validator stake account
769
+ u8('status'),
770
+ /// Validator vote account address
771
+ publicKey('voteAccountAddress'),
772
+ ]);
773
+ const ValidatorListLayout = struct([
774
+ u8('accountType'),
775
+ u32('maxValidators'),
776
+ vec(ValidatorStakeInfoLayout, 'validators'),
777
+ ]);
778
+
779
+ async function getValidatorListAccount(connection, pubkey) {
780
+ const account = await connection.getAccountInfo(pubkey);
781
+ if (!account) {
782
+ throw new Error('Invalid validator list account');
783
+ }
784
+ return {
785
+ pubkey,
786
+ account: {
787
+ data: ValidatorListLayout.decode(account === null || account === void 0 ? void 0 : account.data),
788
+ executable: account.executable,
789
+ lamports: account.lamports,
790
+ owner: account.owner,
791
+ },
792
+ };
793
+ }
794
+ async function prepareWithdrawAccounts(connection, stakePool, stakePoolAddress, amount, compareFn, skipFee) {
795
+ var _a, _b;
796
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
797
+ const validatorListAcc = await connection.getAccountInfo(stakePool.validatorList);
798
+ const validatorList = ValidatorListLayout.decode(validatorListAcc === null || validatorListAcc === void 0 ? void 0 : validatorListAcc.data);
799
+ if (!(validatorList === null || validatorList === void 0 ? void 0 : validatorList.validators) || (validatorList === null || validatorList === void 0 ? void 0 : validatorList.validators.length) == 0) {
800
+ throw new Error('No accounts found');
801
+ }
802
+ const minBalanceForRentExemption = await connection.getMinimumBalanceForRentExemption(StakeProgram.space);
803
+ const minBalance = new BN(minBalanceForRentExemption + MINIMUM_ACTIVE_STAKE);
804
+ let accounts = [];
805
+ // Prepare accounts
806
+ for (const validator of validatorList.validators) {
807
+ if (validator.status !== ValidatorStakeInfoStatus.Active) {
808
+ continue;
809
+ }
810
+ const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress);
811
+ if (!validator.activeStakeLamports.isZero()) {
812
+ const isPreferred = (_a = stakePool === null || stakePool === void 0 ? void 0 : stakePool.preferredWithdrawValidatorVoteAddress) === null || _a === void 0 ? void 0 : _a.equals(validator.voteAccountAddress);
813
+ accounts.push({
814
+ type: isPreferred ? 'preferred' : 'active',
815
+ voteAddress: validator.voteAccountAddress,
816
+ stakeAddress: stakeAccountAddress,
817
+ lamports: validator.activeStakeLamports,
818
+ });
819
+ }
820
+ const transientStakeLamports = validator.transientStakeLamports.sub(minBalance);
821
+ if (transientStakeLamports.gt(new BN(0))) {
822
+ const transientStakeAccountAddress = await findTransientStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress, validator.transientSeedSuffixStart);
823
+ accounts.push({
824
+ type: 'transient',
825
+ voteAddress: validator.voteAccountAddress,
826
+ stakeAddress: transientStakeAccountAddress,
827
+ lamports: transientStakeLamports,
828
+ });
829
+ }
830
+ }
831
+ // Sort from highest to lowest balance
832
+ accounts = accounts.sort(compareFn || ((a, b) => b.lamports.sub(a.lamports).toNumber()));
833
+ const reserveStake = await connection.getAccountInfo(stakePool.reserveStake);
834
+ const reserveStakeBalance = new BN(((_b = reserveStake === null || reserveStake === void 0 ? void 0 : reserveStake.lamports) !== null && _b !== void 0 ? _b : 0) - minBalanceForRentExemption);
835
+ if (reserveStakeBalance.gt(new BN(0))) {
836
+ accounts.push({
837
+ type: 'reserve',
838
+ stakeAddress: stakePool.reserveStake,
839
+ lamports: reserveStakeBalance,
840
+ });
841
+ }
842
+ // Prepare the list of accounts to withdraw from
843
+ const withdrawFrom = [];
844
+ let remainingAmount = new BN(amount);
845
+ const fee = stakePool.stakeWithdrawalFee;
846
+ const inverseFee = {
847
+ numerator: fee.denominator.sub(fee.numerator),
848
+ denominator: fee.denominator,
849
+ };
850
+ for (const type of ['preferred', 'active', 'transient', 'reserve']) {
851
+ const filteredAccounts = accounts.filter(a => a.type == type);
852
+ for (const { stakeAddress, voteAddress, lamports } of filteredAccounts) {
853
+ if (lamports.lte(minBalance) && type == 'transient') {
854
+ continue;
855
+ }
856
+ let availableForWithdrawal = calcPoolTokensForDeposit(stakePool, lamports);
857
+ if (!skipFee && !inverseFee.numerator.isZero()) {
858
+ availableForWithdrawal = availableForWithdrawal
859
+ .mul(inverseFee.denominator)
860
+ .div(inverseFee.numerator);
861
+ }
862
+ const poolAmount = BN.min(availableForWithdrawal, remainingAmount);
863
+ if (poolAmount.lte(new BN(0))) {
864
+ continue;
865
+ }
866
+ // Those accounts will be withdrawn completely with `claim` instruction
867
+ withdrawFrom.push({ stakeAddress, voteAddress, poolAmount });
868
+ remainingAmount = remainingAmount.sub(poolAmount);
869
+ if (remainingAmount.isZero()) {
870
+ break;
871
+ }
872
+ }
873
+ if (remainingAmount.isZero()) {
874
+ break;
875
+ }
876
+ }
877
+ // Not enough stake to withdraw the specified amount
878
+ if (remainingAmount.gt(new BN(0))) {
879
+ throw new Error(`No stake accounts found in this pool with enough balance to withdraw ${lamportsToSol(amount)} pool tokens.`);
880
+ }
881
+ return withdrawFrom;
882
+ }
883
+ /**
884
+ * Calculate the pool tokens that should be minted for a deposit of `stakeLamports`
885
+ */
886
+ function calcPoolTokensForDeposit(stakePool, stakeLamports) {
887
+ if (stakePool.poolTokenSupply.isZero() || stakePool.totalLamports.isZero()) {
888
+ return stakeLamports;
889
+ }
890
+ const numerator = stakeLamports.mul(stakePool.poolTokenSupply);
891
+ return numerator.div(stakePool.totalLamports);
892
+ }
893
+ /**
894
+ * Calculate lamports amount on withdrawal
895
+ */
896
+ function calcLamportsWithdrawAmount(stakePool, poolTokens) {
897
+ const numerator = poolTokens.mul(stakePool.totalLamports);
898
+ const denominator = stakePool.poolTokenSupply;
899
+ if (numerator.lt(denominator)) {
900
+ return new BN(0);
901
+ }
902
+ return numerator.div(denominator);
903
+ }
904
+ function newStakeAccount(feePayer, instructions, lamports) {
905
+ // Account for tokens not specified, creating one
906
+ const stakeReceiverKeypair = Keypair.generate();
907
+ console.log(`Creating account to receive stake ${stakeReceiverKeypair.publicKey}`);
908
+ instructions.push(
909
+ // Creating new account
910
+ SystemProgram.createAccount({
911
+ fromPubkey: feePayer,
912
+ newAccountPubkey: stakeReceiverKeypair.publicKey,
913
+ lamports,
914
+ space: StakeProgram.space,
915
+ programId: StakeProgram.programId,
916
+ }));
917
+ return stakeReceiverKeypair;
918
+ }
919
+
920
+ function arrayChunk(array, size) {
921
+ const result = [];
922
+ for (let i = 0; i < array.length; i += size) {
923
+ result.push(array.slice(i, i + size));
924
+ }
925
+ return result;
926
+ }
927
+
928
+ // 'UpdateTokenMetadata' and 'CreateTokenMetadata' have dynamic layouts
929
+ const MOVE_STAKE_LAYOUT = BufferLayout.struct([
930
+ BufferLayout.u8('instruction'),
931
+ BufferLayout.ns64('lamports'),
932
+ BufferLayout.ns64('transientStakeSeed'),
933
+ ]);
934
+ const UPDATE_VALIDATOR_LIST_BALANCE_LAYOUT = BufferLayout.struct([
935
+ BufferLayout.u8('instruction'),
936
+ BufferLayout.u32('startIndex'),
937
+ BufferLayout.u8('noMerge'),
938
+ ]);
939
+ function tokenMetadataLayout(instruction, nameLength, symbolLength, uriLength) {
940
+ if (nameLength > METADATA_MAX_NAME_LENGTH) {
941
+ // eslint-disable-next-line no-throw-literal
942
+ throw 'maximum token name length is 32 characters';
943
+ }
944
+ if (symbolLength > METADATA_MAX_SYMBOL_LENGTH) {
945
+ // eslint-disable-next-line no-throw-literal
946
+ throw 'maximum token symbol length is 10 characters';
947
+ }
948
+ if (uriLength > METADATA_MAX_URI_LENGTH) {
949
+ // eslint-disable-next-line no-throw-literal
950
+ throw 'maximum token uri length is 200 characters';
951
+ }
952
+ return {
953
+ index: instruction,
954
+ layout: BufferLayout.struct([
955
+ BufferLayout.u8('instruction'),
956
+ BufferLayout.u32('nameLen'),
957
+ BufferLayout.blob(nameLength, 'name'),
958
+ BufferLayout.u32('symbolLen'),
959
+ BufferLayout.blob(symbolLength, 'symbol'),
960
+ BufferLayout.u32('uriLen'),
961
+ BufferLayout.blob(uriLength, 'uri'),
962
+ ]),
963
+ };
964
+ }
965
+ /**
966
+ * An enumeration of valid stake InstructionType's
967
+ * @internal
968
+ */
969
+ const STAKE_POOL_INSTRUCTION_LAYOUTS = Object.freeze({
970
+ AddValidatorToPool: {
971
+ index: 1,
972
+ layout: BufferLayout.struct([BufferLayout.u8('instruction'), BufferLayout.u32('seed')]),
973
+ },
974
+ RemoveValidatorFromPool: {
975
+ index: 2,
976
+ layout: BufferLayout.struct([BufferLayout.u8('instruction')]),
977
+ },
978
+ DecreaseValidatorStake: {
979
+ index: 3,
980
+ layout: MOVE_STAKE_LAYOUT,
981
+ },
982
+ IncreaseValidatorStake: {
983
+ index: 4,
984
+ layout: MOVE_STAKE_LAYOUT,
985
+ },
986
+ UpdateValidatorListBalance: {
987
+ index: 6,
988
+ layout: UPDATE_VALIDATOR_LIST_BALANCE_LAYOUT,
989
+ },
990
+ UpdateStakePoolBalance: {
991
+ index: 7,
992
+ layout: BufferLayout.struct([BufferLayout.u8('instruction')]),
993
+ },
994
+ CleanupRemovedValidatorEntries: {
995
+ index: 8,
996
+ layout: BufferLayout.struct([BufferLayout.u8('instruction')]),
997
+ },
998
+ DepositStake: {
999
+ index: 9,
1000
+ layout: BufferLayout.struct([BufferLayout.u8('instruction')]),
1001
+ },
1002
+ /// Withdraw the token from the pool at the current ratio.
1003
+ WithdrawStake: {
1004
+ index: 10,
1005
+ layout: BufferLayout.struct([
1006
+ BufferLayout.u8('instruction'),
1007
+ BufferLayout.ns64('poolTokens'),
1008
+ ]),
1009
+ },
1010
+ /// Deposit SOL directly into the pool's reserve account. The output is a "pool" token
1011
+ /// representing ownership into the pool. Inputs are converted to the current ratio.
1012
+ DepositSol: {
1013
+ index: 14,
1014
+ layout: BufferLayout.struct([
1015
+ BufferLayout.u8('instruction'),
1016
+ BufferLayout.ns64('lamports'),
1017
+ ]),
1018
+ },
1019
+ /// Withdraw SOL directly from the pool's reserve account. Fails if the
1020
+ /// reserve does not have enough SOL.
1021
+ WithdrawSol: {
1022
+ index: 16,
1023
+ layout: BufferLayout.struct([
1024
+ BufferLayout.u8('instruction'),
1025
+ BufferLayout.ns64('poolTokens'),
1026
+ ]),
1027
+ },
1028
+ IncreaseAdditionalValidatorStake: {
1029
+ index: 19,
1030
+ layout: BufferLayout.struct([
1031
+ BufferLayout.u8('instruction'),
1032
+ BufferLayout.ns64('lamports'),
1033
+ BufferLayout.ns64('transientStakeSeed'),
1034
+ BufferLayout.ns64('ephemeralStakeSeed'),
1035
+ ]),
1036
+ },
1037
+ DecreaseAdditionalValidatorStake: {
1038
+ index: 20,
1039
+ layout: BufferLayout.struct([
1040
+ BufferLayout.u8('instruction'),
1041
+ BufferLayout.ns64('lamports'),
1042
+ BufferLayout.ns64('transientStakeSeed'),
1043
+ BufferLayout.ns64('ephemeralStakeSeed'),
1044
+ ]),
1045
+ },
1046
+ DecreaseValidatorStakeWithReserve: {
1047
+ index: 21,
1048
+ layout: MOVE_STAKE_LAYOUT,
1049
+ },
1050
+ Redelegate: {
1051
+ index: 22,
1052
+ layout: BufferLayout.struct([BufferLayout.u8('instruction')]),
1053
+ },
1054
+ DepositStakeWithSlippage: {
1055
+ index: 23,
1056
+ layout: BufferLayout.struct([
1057
+ BufferLayout.u8('instruction'),
1058
+ BufferLayout.ns64('lamports'),
1059
+ ]),
1060
+ },
1061
+ WithdrawStakeWithSlippage: {
1062
+ index: 24,
1063
+ layout: BufferLayout.struct([
1064
+ BufferLayout.u8('instruction'),
1065
+ BufferLayout.ns64('lamports'),
1066
+ ]),
1067
+ },
1068
+ DepositSolWithSlippage: {
1069
+ index: 25,
1070
+ layout: BufferLayout.struct([
1071
+ BufferLayout.u8('instruction'),
1072
+ BufferLayout.ns64('lamports'),
1073
+ ]),
1074
+ },
1075
+ WithdrawSolWithSlippage: {
1076
+ index: 26,
1077
+ layout: BufferLayout.struct([
1078
+ BufferLayout.u8('instruction'),
1079
+ BufferLayout.ns64('lamports'),
1080
+ ]),
1081
+ },
1082
+ DepositWsolWithSession: {
1083
+ index: 27,
1084
+ layout: BufferLayout.struct([
1085
+ BufferLayout.u8('instruction'),
1086
+ BufferLayout.ns64('lamports'),
1087
+ ]),
1088
+ },
1089
+ WithdrawWsolWithSession: {
1090
+ index: 28,
1091
+ layout: BufferLayout.struct([
1092
+ BufferLayout.u8('instruction'),
1093
+ BufferLayout.ns64('poolTokens'),
1094
+ ]),
1095
+ },
1096
+ });
1097
+ /**
1098
+ * Stake Pool Instruction class
1099
+ */
1100
+ class StakePoolInstruction {
1101
+ /**
1102
+ * Creates instruction to add a validator into the stake pool.
1103
+ */
1104
+ static addValidatorToPool(params) {
1105
+ const { programId, stakePool, staker, reserveStake, withdrawAuthority, validatorList, validatorStake, validatorVote, seed, } = params;
1106
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.AddValidatorToPool;
1107
+ const data = encodeData(type, { seed: seed !== null && seed !== void 0 ? seed : 0 });
1108
+ const keys = [
1109
+ { pubkey: stakePool, isSigner: false, isWritable: true },
1110
+ { pubkey: staker, isSigner: true, isWritable: false },
1111
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1112
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1113
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1114
+ { pubkey: validatorStake, isSigner: false, isWritable: true },
1115
+ { pubkey: validatorVote, isSigner: false, isWritable: false },
1116
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
1117
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1118
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1119
+ { pubkey: STAKE_CONFIG_ID, isSigner: false, isWritable: false },
1120
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1121
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1122
+ ];
1123
+ return new TransactionInstruction({
1124
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1125
+ keys,
1126
+ data,
1127
+ });
1128
+ }
1129
+ /**
1130
+ * Creates instruction to remove a validator from the stake pool.
1131
+ */
1132
+ static removeValidatorFromPool(params) {
1133
+ const { programId, stakePool, staker, withdrawAuthority, validatorList, validatorStake, transientStake, } = params;
1134
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.RemoveValidatorFromPool;
1135
+ const data = encodeData(type);
1136
+ const keys = [
1137
+ { pubkey: stakePool, isSigner: false, isWritable: true },
1138
+ { pubkey: staker, isSigner: true, isWritable: false },
1139
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1140
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1141
+ { pubkey: validatorStake, isSigner: false, isWritable: true },
1142
+ { pubkey: transientStake, isSigner: false, isWritable: true },
1143
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1144
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1145
+ ];
1146
+ return new TransactionInstruction({
1147
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1148
+ keys,
1149
+ data,
1150
+ });
1151
+ }
1152
+ /**
1153
+ * Creates instruction to update a set of validators in the stake pool.
1154
+ */
1155
+ static updateValidatorListBalance(params) {
1156
+ const { programId, stakePool, withdrawAuthority, validatorList, reserveStake, startIndex, noMerge, validatorAndTransientStakePairs, } = params;
1157
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.UpdateValidatorListBalance;
1158
+ const data = encodeData(type, { startIndex, noMerge: noMerge ? 1 : 0 });
1159
+ const keys = [
1160
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1161
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1162
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1163
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1164
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1165
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1166
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1167
+ ...validatorAndTransientStakePairs.map(pubkey => ({
1168
+ pubkey,
1169
+ isSigner: false,
1170
+ isWritable: true,
1171
+ })),
1172
+ ];
1173
+ return new TransactionInstruction({
1174
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1175
+ keys,
1176
+ data,
1177
+ });
1178
+ }
1179
+ /**
1180
+ * Creates instruction to update the overall stake pool balance.
1181
+ */
1182
+ static updateStakePoolBalance(params) {
1183
+ const { programId, stakePool, withdrawAuthority, validatorList, reserveStake, managerFeeAccount, poolMint, } = params;
1184
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.UpdateStakePoolBalance;
1185
+ const data = encodeData(type);
1186
+ const keys = [
1187
+ { pubkey: stakePool, isSigner: false, isWritable: true },
1188
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1189
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1190
+ { pubkey: reserveStake, isSigner: false, isWritable: false },
1191
+ { pubkey: managerFeeAccount, isSigner: false, isWritable: true },
1192
+ { pubkey: poolMint, isSigner: false, isWritable: true },
1193
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1194
+ ];
1195
+ return new TransactionInstruction({
1196
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1197
+ keys,
1198
+ data,
1199
+ });
1200
+ }
1201
+ /**
1202
+ * Creates instruction to cleanup removed validator entries.
1203
+ */
1204
+ static cleanupRemovedValidatorEntries(params) {
1205
+ const { programId, stakePool, validatorList } = params;
1206
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.CleanupRemovedValidatorEntries;
1207
+ const data = encodeData(type);
1208
+ const keys = [
1209
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1210
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1211
+ ];
1212
+ return new TransactionInstruction({
1213
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1214
+ keys,
1215
+ data,
1216
+ });
1217
+ }
1218
+ /**
1219
+ * Creates `IncreaseValidatorStake` instruction (rebalance from reserve account to
1220
+ * transient account)
1221
+ */
1222
+ static increaseValidatorStake(params) {
1223
+ const { programId, stakePool, staker, withdrawAuthority, validatorList, reserveStake, transientStake, validatorStake, validatorVote, lamports, transientStakeSeed, } = params;
1224
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.IncreaseValidatorStake;
1225
+ const data = encodeData(type, { lamports, transientStakeSeed });
1226
+ const keys = [
1227
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1228
+ { pubkey: staker, isSigner: true, isWritable: false },
1229
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1230
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1231
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1232
+ { pubkey: transientStake, isSigner: false, isWritable: true },
1233
+ { pubkey: validatorStake, isSigner: false, isWritable: false },
1234
+ { pubkey: validatorVote, isSigner: false, isWritable: false },
1235
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1236
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
1237
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1238
+ { pubkey: STAKE_CONFIG_ID, isSigner: false, isWritable: false },
1239
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1240
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1241
+ ];
1242
+ return new TransactionInstruction({
1243
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1244
+ keys,
1245
+ data,
1246
+ });
1247
+ }
1248
+ /**
1249
+ * Creates `IncreaseAdditionalValidatorStake` instruction (rebalance from reserve account to
1250
+ * transient account)
1251
+ */
1252
+ static increaseAdditionalValidatorStake(params) {
1253
+ const { programId, stakePool, staker, withdrawAuthority, validatorList, reserveStake, transientStake, validatorStake, validatorVote, lamports, transientStakeSeed, ephemeralStake, ephemeralStakeSeed, } = params;
1254
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.IncreaseAdditionalValidatorStake;
1255
+ const data = encodeData(type, { lamports, transientStakeSeed, ephemeralStakeSeed });
1256
+ const keys = [
1257
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1258
+ { pubkey: staker, isSigner: true, isWritable: false },
1259
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1260
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1261
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1262
+ { pubkey: ephemeralStake, isSigner: false, isWritable: true },
1263
+ { pubkey: transientStake, isSigner: false, isWritable: true },
1264
+ { pubkey: validatorStake, isSigner: false, isWritable: false },
1265
+ { pubkey: validatorVote, isSigner: false, isWritable: false },
1266
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1267
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1268
+ { pubkey: STAKE_CONFIG_ID, isSigner: false, isWritable: false },
1269
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1270
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1271
+ ];
1272
+ return new TransactionInstruction({
1273
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1274
+ keys,
1275
+ data,
1276
+ });
1277
+ }
1278
+ /**
1279
+ * Creates `DecreaseValidatorStake` instruction (rebalance from validator account to
1280
+ * transient account)
1281
+ */
1282
+ static decreaseValidatorStake(params) {
1283
+ const { programId, stakePool, staker, withdrawAuthority, validatorList, validatorStake, transientStake, lamports, transientStakeSeed, } = params;
1284
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseValidatorStake;
1285
+ const data = encodeData(type, { lamports, transientStakeSeed });
1286
+ const keys = [
1287
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1288
+ { pubkey: staker, isSigner: true, isWritable: false },
1289
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1290
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1291
+ { pubkey: validatorStake, isSigner: false, isWritable: true },
1292
+ { pubkey: transientStake, isSigner: false, isWritable: true },
1293
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1294
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
1295
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1296
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1297
+ ];
1298
+ return new TransactionInstruction({
1299
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1300
+ keys,
1301
+ data,
1302
+ });
1303
+ }
1304
+ /**
1305
+ * Creates `DecreaseValidatorStakeWithReserve` instruction (rebalance from
1306
+ * validator account to transient account)
1307
+ */
1308
+ static decreaseValidatorStakeWithReserve(params) {
1309
+ const { programId, stakePool, staker, withdrawAuthority, validatorList, reserveStake, validatorStake, transientStake, lamports, transientStakeSeed, } = params;
1310
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseValidatorStakeWithReserve;
1311
+ const data = encodeData(type, { lamports, transientStakeSeed });
1312
+ const keys = [
1313
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1314
+ { pubkey: staker, isSigner: true, isWritable: false },
1315
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1316
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1317
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1318
+ { pubkey: validatorStake, isSigner: false, isWritable: true },
1319
+ { pubkey: transientStake, isSigner: false, isWritable: true },
1320
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1321
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1322
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1323
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1324
+ ];
1325
+ return new TransactionInstruction({
1326
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1327
+ keys,
1328
+ data,
1329
+ });
1330
+ }
1331
+ /**
1332
+ * Creates `DecreaseAdditionalValidatorStake` instruction (rebalance from
1333
+ * validator account to transient account)
1334
+ */
1335
+ static decreaseAdditionalValidatorStake(params) {
1336
+ const { programId, stakePool, staker, withdrawAuthority, validatorList, reserveStake, validatorStake, transientStake, lamports, transientStakeSeed, ephemeralStakeSeed, ephemeralStake, } = params;
1337
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DecreaseAdditionalValidatorStake;
1338
+ const data = encodeData(type, { lamports, transientStakeSeed, ephemeralStakeSeed });
1339
+ const keys = [
1340
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1341
+ { pubkey: staker, isSigner: true, isWritable: false },
1342
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1343
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1344
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1345
+ { pubkey: validatorStake, isSigner: false, isWritable: true },
1346
+ { pubkey: ephemeralStake, isSigner: false, isWritable: true },
1347
+ { pubkey: transientStake, isSigner: false, isWritable: true },
1348
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1349
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1350
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1351
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1352
+ ];
1353
+ return new TransactionInstruction({
1354
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1355
+ keys,
1356
+ data,
1357
+ });
1358
+ }
1359
+ /**
1360
+ * Creates a transaction instruction to deposit a stake account into a stake pool.
1361
+ */
1362
+ static depositStake(params) {
1363
+ const { programId, stakePool, validatorList, depositAuthority, withdrawAuthority, depositStake, validatorStake, reserveStake, destinationPoolAccount, managerFeeAccount, referralPoolAccount, poolMint, } = params;
1364
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DepositStake;
1365
+ const data = encodeData(type);
1366
+ const keys = [
1367
+ { pubkey: stakePool, isSigner: false, isWritable: true },
1368
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1369
+ { pubkey: depositAuthority, isSigner: false, isWritable: false },
1370
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1371
+ { pubkey: depositStake, isSigner: false, isWritable: true },
1372
+ { pubkey: validatorStake, isSigner: false, isWritable: true },
1373
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1374
+ { pubkey: destinationPoolAccount, isSigner: false, isWritable: true },
1375
+ { pubkey: managerFeeAccount, isSigner: false, isWritable: true },
1376
+ { pubkey: referralPoolAccount, isSigner: false, isWritable: true },
1377
+ { pubkey: poolMint, isSigner: false, isWritable: true },
1378
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1379
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1380
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1381
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1382
+ ];
1383
+ return new TransactionInstruction({
1384
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1385
+ keys,
1386
+ data,
1387
+ });
1388
+ }
1389
+ /**
1390
+ * Creates a transaction instruction to deposit SOL into a stake pool.
1391
+ */
1392
+ static depositSol(params) {
1393
+ const { programId, stakePool, withdrawAuthority, depositAuthority, reserveStake, fundingAccount, destinationPoolAccount, managerFeeAccount, referralPoolAccount, poolMint, lamports, } = params;
1394
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DepositSol;
1395
+ const data = encodeData(type, { lamports });
1396
+ const keys = [
1397
+ { pubkey: stakePool, isSigner: false, isWritable: true },
1398
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1399
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1400
+ { pubkey: fundingAccount, isSigner: true, isWritable: true },
1401
+ { pubkey: destinationPoolAccount, isSigner: false, isWritable: true },
1402
+ { pubkey: managerFeeAccount, isSigner: false, isWritable: true },
1403
+ { pubkey: referralPoolAccount, isSigner: false, isWritable: true },
1404
+ { pubkey: poolMint, isSigner: false, isWritable: true },
1405
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1406
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1407
+ ];
1408
+ if (depositAuthority) {
1409
+ keys.push({
1410
+ pubkey: depositAuthority,
1411
+ isSigner: true,
1412
+ isWritable: false,
1413
+ });
1414
+ }
1415
+ return new TransactionInstruction({
1416
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1417
+ keys,
1418
+ data,
1419
+ });
1420
+ }
1421
+ /**
1422
+ * Creates a transaction instruction to deposit WSOL into a stake pool.
1423
+ */
1424
+ static depositWsolWithSession(params) {
1425
+ var _a;
1426
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.DepositWsolWithSession;
1427
+ const data = encodeData(type, { lamports: params.lamports });
1428
+ const keys = [
1429
+ { pubkey: params.stakePool, isSigner: false, isWritable: true },
1430
+ { pubkey: params.withdrawAuthority, isSigner: false, isWritable: false },
1431
+ { pubkey: params.reserveStake, isSigner: false, isWritable: true },
1432
+ { pubkey: params.fundingAccount, isSigner: true, isWritable: true },
1433
+ { pubkey: params.destinationPoolAccount, isSigner: false, isWritable: true },
1434
+ { pubkey: params.managerFeeAccount, isSigner: false, isWritable: true },
1435
+ { pubkey: params.referralPoolAccount, isSigner: false, isWritable: true },
1436
+ { pubkey: params.poolMint, isSigner: false, isWritable: true },
1437
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1438
+ { pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
1439
+ // wsol specific accounts
1440
+ { pubkey: params.wsolMint, isSigner: false, isWritable: false },
1441
+ { pubkey: params.wsolTokenAccount, isSigner: false, isWritable: true },
1442
+ { pubkey: params.wsolTransientAccount, isSigner: false, isWritable: true },
1443
+ { pubkey: params.programSigner, isSigner: false, isWritable: true },
1444
+ { pubkey: (_a = params.payer) !== null && _a !== void 0 ? _a : params.fundingAccount, isSigner: true, isWritable: true },
1445
+ ];
1446
+ if (params.depositAuthority) {
1447
+ keys.push({
1448
+ pubkey: params.depositAuthority,
1449
+ isSigner: true,
1450
+ isWritable: false,
1451
+ });
1452
+ }
1453
+ return new TransactionInstruction({
1454
+ programId: params.programId,
1455
+ keys,
1456
+ data,
1457
+ });
1458
+ }
1459
+ /**
1460
+ * Creates a transaction instruction to withdraw active stake from a stake pool.
1461
+ */
1462
+ static withdrawStake(params) {
1463
+ const { programId, stakePool, validatorList, withdrawAuthority, validatorStake, destinationStake, destinationStakeAuthority, sourceTransferAuthority, sourcePoolAccount, managerFeeAccount, poolMint, poolTokens, } = params;
1464
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawStake;
1465
+ const data = encodeData(type, { poolTokens });
1466
+ const keys = [
1467
+ { pubkey: stakePool, isSigner: false, isWritable: true },
1468
+ { pubkey: validatorList, isSigner: false, isWritable: true },
1469
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1470
+ { pubkey: validatorStake, isSigner: false, isWritable: true },
1471
+ { pubkey: destinationStake, isSigner: false, isWritable: true },
1472
+ { pubkey: destinationStakeAuthority, isSigner: false, isWritable: false },
1473
+ { pubkey: sourceTransferAuthority, isSigner: true, isWritable: false },
1474
+ { pubkey: sourcePoolAccount, isSigner: false, isWritable: true },
1475
+ { pubkey: managerFeeAccount, isSigner: false, isWritable: true },
1476
+ { pubkey: poolMint, isSigner: false, isWritable: true },
1477
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1478
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1479
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1480
+ ];
1481
+ return new TransactionInstruction({
1482
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1483
+ keys,
1484
+ data,
1485
+ });
1486
+ }
1487
+ /**
1488
+ * Creates a transaction instruction to withdraw SOL from a stake pool.
1489
+ */
1490
+ static withdrawSol(params) {
1491
+ const { programId, stakePool, withdrawAuthority, sourceTransferAuthority, sourcePoolAccount, reserveStake, destinationSystemAccount, managerFeeAccount, solWithdrawAuthority, poolMint, poolTokens, } = params;
1492
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawSol;
1493
+ const data = encodeData(type, { poolTokens });
1494
+ const keys = [
1495
+ { pubkey: stakePool, isSigner: false, isWritable: true },
1496
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1497
+ { pubkey: sourceTransferAuthority, isSigner: true, isWritable: false },
1498
+ { pubkey: sourcePoolAccount, isSigner: false, isWritable: true },
1499
+ { pubkey: reserveStake, isSigner: false, isWritable: true },
1500
+ { pubkey: destinationSystemAccount, isSigner: false, isWritable: true },
1501
+ { pubkey: managerFeeAccount, isSigner: false, isWritable: true },
1502
+ { pubkey: poolMint, isSigner: false, isWritable: true },
1503
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1504
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1505
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1506
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
1507
+ ];
1508
+ if (solWithdrawAuthority) {
1509
+ keys.push({
1510
+ pubkey: solWithdrawAuthority,
1511
+ isSigner: true,
1512
+ isWritable: false,
1513
+ });
1514
+ }
1515
+ return new TransactionInstruction({
1516
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1517
+ keys,
1518
+ data,
1519
+ });
1520
+ }
1521
+ /**
1522
+ * Creates a transaction instruction to withdraw WSOL from a stake pool using a session.
1523
+ */
1524
+ static withdrawWsolWithSession(params) {
1525
+ const type = STAKE_POOL_INSTRUCTION_LAYOUTS.WithdrawWsolWithSession;
1526
+ const data = encodeData(type, { poolTokens: params.poolTokens });
1527
+ const keys = [
1528
+ { pubkey: params.stakePool, isSigner: false, isWritable: true },
1529
+ { pubkey: params.withdrawAuthority, isSigner: false, isWritable: false },
1530
+ { pubkey: params.userTransferAuthority, isSigner: true, isWritable: true },
1531
+ { pubkey: params.poolTokensFrom, isSigner: false, isWritable: true },
1532
+ { pubkey: params.reserveStake, isSigner: false, isWritable: true },
1533
+ { pubkey: params.userWsolAccount, isSigner: false, isWritable: true },
1534
+ { pubkey: params.managerFeeAccount, isSigner: false, isWritable: true },
1535
+ { pubkey: params.poolMint, isSigner: false, isWritable: true },
1536
+ { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
1537
+ { pubkey: SYSVAR_STAKE_HISTORY_PUBKEY, isSigner: false, isWritable: false },
1538
+ { pubkey: StakeProgram.programId, isSigner: false, isWritable: false },
1539
+ { pubkey: params.tokenProgramId, isSigner: false, isWritable: false },
1540
+ { pubkey: params.wsolMint, isSigner: false, isWritable: false },
1541
+ { pubkey: params.programSigner, isSigner: false, isWritable: true },
1542
+ ];
1543
+ if (params.solWithdrawAuthority) {
1544
+ keys.push({
1545
+ pubkey: params.solWithdrawAuthority,
1546
+ isSigner: true,
1547
+ isWritable: false,
1548
+ });
1549
+ }
1550
+ return new TransactionInstruction({
1551
+ programId: params.programId,
1552
+ keys,
1553
+ data,
1554
+ });
1555
+ }
1556
+ /**
1557
+ * Creates an instruction to create metadata
1558
+ * using the mpl token metadata program for the pool token
1559
+ */
1560
+ static createTokenMetadata(params) {
1561
+ const { programId, stakePool, withdrawAuthority, tokenMetadata, manager, payer, poolMint, name, symbol, uri, } = params;
1562
+ const keys = [
1563
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1564
+ { pubkey: manager, isSigner: true, isWritable: false },
1565
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1566
+ { pubkey: poolMint, isSigner: false, isWritable: false },
1567
+ { pubkey: payer, isSigner: true, isWritable: true },
1568
+ { pubkey: tokenMetadata, isSigner: false, isWritable: true },
1569
+ { pubkey: METADATA_PROGRAM_ID, isSigner: false, isWritable: false },
1570
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
1571
+ { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
1572
+ ];
1573
+ const type = tokenMetadataLayout(17, name.length, symbol.length, uri.length);
1574
+ const data = encodeData(type, {
1575
+ nameLen: name.length,
1576
+ name: Buffer.from(name),
1577
+ symbolLen: symbol.length,
1578
+ symbol: Buffer.from(symbol),
1579
+ uriLen: uri.length,
1580
+ uri: Buffer.from(uri),
1581
+ });
1582
+ return new TransactionInstruction({
1583
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1584
+ keys,
1585
+ data,
1586
+ });
1587
+ }
1588
+ /**
1589
+ * Creates an instruction to update metadata
1590
+ * in the mpl token metadata program account for the pool token
1591
+ */
1592
+ static updateTokenMetadata(params) {
1593
+ const { programId, stakePool, withdrawAuthority, tokenMetadata, manager, name, symbol, uri } = params;
1594
+ const keys = [
1595
+ { pubkey: stakePool, isSigner: false, isWritable: false },
1596
+ { pubkey: manager, isSigner: true, isWritable: false },
1597
+ { pubkey: withdrawAuthority, isSigner: false, isWritable: false },
1598
+ { pubkey: tokenMetadata, isSigner: false, isWritable: true },
1599
+ { pubkey: METADATA_PROGRAM_ID, isSigner: false, isWritable: false },
1600
+ ];
1601
+ const type = tokenMetadataLayout(18, name.length, symbol.length, uri.length);
1602
+ const data = encodeData(type, {
1603
+ nameLen: name.length,
1604
+ name: Buffer.from(name),
1605
+ symbolLen: symbol.length,
1606
+ symbol: Buffer.from(symbol),
1607
+ uriLen: uri.length,
1608
+ uri: Buffer.from(uri),
1609
+ });
1610
+ return new TransactionInstruction({
1611
+ programId: programId !== null && programId !== void 0 ? programId : STAKE_POOL_PROGRAM_ID,
1612
+ keys,
1613
+ data,
1614
+ });
1615
+ }
1616
+ /**
1617
+ * Decode a deposit stake pool instruction and retrieve the instruction params.
1618
+ */
1619
+ static decodeDepositStake(instruction) {
1620
+ this.checkProgramId(instruction.programId);
1621
+ this.checkKeyLength(instruction.keys, 11);
1622
+ decodeData(STAKE_POOL_INSTRUCTION_LAYOUTS.DepositStake, instruction.data);
1623
+ return {
1624
+ programId: instruction.programId,
1625
+ stakePool: instruction.keys[0].pubkey,
1626
+ validatorList: instruction.keys[1].pubkey,
1627
+ depositAuthority: instruction.keys[2].pubkey,
1628
+ withdrawAuthority: instruction.keys[3].pubkey,
1629
+ depositStake: instruction.keys[4].pubkey,
1630
+ validatorStake: instruction.keys[5].pubkey,
1631
+ reserveStake: instruction.keys[6].pubkey,
1632
+ destinationPoolAccount: instruction.keys[7].pubkey,
1633
+ managerFeeAccount: instruction.keys[8].pubkey,
1634
+ referralPoolAccount: instruction.keys[9].pubkey,
1635
+ poolMint: instruction.keys[10].pubkey,
1636
+ };
1637
+ }
1638
+ /**
1639
+ * Decode a deposit sol instruction and retrieve the instruction params.
1640
+ */
1641
+ static decodeDepositSol(instruction) {
1642
+ this.checkProgramId(instruction.programId);
1643
+ this.checkKeyLength(instruction.keys, 9);
1644
+ const { amount } = decodeData(STAKE_POOL_INSTRUCTION_LAYOUTS.DepositSol, instruction.data);
1645
+ return {
1646
+ programId: instruction.programId,
1647
+ stakePool: instruction.keys[0].pubkey,
1648
+ depositAuthority: instruction.keys[1].pubkey,
1649
+ withdrawAuthority: instruction.keys[2].pubkey,
1650
+ reserveStake: instruction.keys[3].pubkey,
1651
+ fundingAccount: instruction.keys[4].pubkey,
1652
+ destinationPoolAccount: instruction.keys[5].pubkey,
1653
+ managerFeeAccount: instruction.keys[6].pubkey,
1654
+ referralPoolAccount: instruction.keys[7].pubkey,
1655
+ poolMint: instruction.keys[8].pubkey,
1656
+ lamports: amount,
1657
+ };
1658
+ }
1659
+ /**
1660
+ * @internal
1661
+ */
1662
+ static checkProgramId(programId) {
1663
+ if (!programId.equals(STAKE_POOL_PROGRAM_ID)
1664
+ && !programId.equals(DEVNET_STAKE_POOL_PROGRAM_ID)) {
1665
+ throw new Error('Invalid instruction; programId is not the stake pool program');
1666
+ }
1667
+ }
1668
+ /**
1669
+ * @internal
1670
+ */
1671
+ static checkKeyLength(keys, expectedLength) {
1672
+ if (keys.length < expectedLength) {
1673
+ throw new Error(`Invalid instruction; found ${keys.length} keys, expected at least ${expectedLength}`);
1674
+ }
1675
+ }
1676
+ }
1677
+
1678
+ function getStakePoolProgramId(rpcEndpoint) {
1679
+ if (rpcEndpoint.includes('devnet')) {
1680
+ return DEVNET_STAKE_POOL_PROGRAM_ID;
1681
+ }
1682
+ else {
1683
+ return STAKE_POOL_PROGRAM_ID;
1684
+ }
1685
+ }
1686
+ /**
1687
+ * Retrieves and deserializes a StakePool account using a web3js connection and the stake pool address.
1688
+ * @param connection An active web3js connection.
1689
+ * @param stakePoolAddress The public key (address) of the stake pool account.
1690
+ */
1691
+ async function getStakePoolAccount(connection, stakePoolAddress) {
1692
+ const account = await connection.getAccountInfo(stakePoolAddress);
1693
+ if (!account) {
1694
+ throw new Error('Invalid stake pool account');
1695
+ }
1696
+ return {
1697
+ pubkey: stakePoolAddress,
1698
+ account: {
1699
+ data: StakePoolLayout.decode(account.data),
1700
+ executable: account.executable,
1701
+ lamports: account.lamports,
1702
+ owner: account.owner,
1703
+ },
1704
+ };
1705
+ }
1706
+ /**
1707
+ * Retrieves and deserializes a Stake account using a web3js connection and the stake address.
1708
+ * @param connection An active web3js connection.
1709
+ * @param stakeAccount The public key (address) of the stake account.
1710
+ */
1711
+ async function getStakeAccount(connection, stakeAccount) {
1712
+ const result = (await connection.getParsedAccountInfo(stakeAccount)).value;
1713
+ if (!result || !('parsed' in result.data)) {
1714
+ throw new Error('Invalid stake account');
1715
+ }
1716
+ const program = result.data.program;
1717
+ if (program !== 'stake') {
1718
+ throw new Error('Not a stake account');
1719
+ }
1720
+ return create(result.data.parsed, StakeAccount);
1721
+ }
1722
+ /**
1723
+ * Retrieves all StakePool and ValidatorList accounts that are running a particular StakePool program.
1724
+ * @param connection An active web3js connection.
1725
+ * @param stakePoolProgramAddress The public key (address) of the StakePool program.
1726
+ */
1727
+ async function getStakePoolAccounts(connection, stakePoolProgramAddress) {
1728
+ const response = await connection.getProgramAccounts(stakePoolProgramAddress);
1729
+ return response
1730
+ .map((a) => {
1731
+ try {
1732
+ if (a.account.data.readUInt8() === 1) {
1733
+ const data = StakePoolLayout.decode(a.account.data);
1734
+ return {
1735
+ pubkey: a.pubkey,
1736
+ account: {
1737
+ data,
1738
+ executable: a.account.executable,
1739
+ lamports: a.account.lamports,
1740
+ owner: a.account.owner,
1741
+ },
1742
+ };
1743
+ }
1744
+ else if (a.account.data.readUInt8() === 2) {
1745
+ const data = ValidatorListLayout.decode(a.account.data);
1746
+ return {
1747
+ pubkey: a.pubkey,
1748
+ account: {
1749
+ data,
1750
+ executable: a.account.executable,
1751
+ lamports: a.account.lamports,
1752
+ owner: a.account.owner,
1753
+ },
1754
+ };
1755
+ }
1756
+ else {
1757
+ console.error(`Could not decode. StakePoolAccount Enum is ${a.account.data.readUInt8()}, expected 1 or 2!`);
1758
+ return undefined;
1759
+ }
1760
+ }
1761
+ catch (error) {
1762
+ console.error('Could not decode account. Error:', error);
1763
+ return undefined;
1764
+ }
1765
+ })
1766
+ .filter(a => a !== undefined);
1767
+ }
1768
+ /**
1769
+ * Creates instructions required to deposit stake to stake pool.
1770
+ */
1771
+ async function depositStake(connection, stakePoolAddress, authorizedPubkey, validatorVote, depositStake, poolTokenReceiverAccount) {
1772
+ const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
1773
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
1774
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
1775
+ const validatorStake = await findStakeProgramAddress(stakePoolProgramId, validatorVote, stakePoolAddress);
1776
+ const instructions = [];
1777
+ const signers = [];
1778
+ const poolMint = stakePool.account.data.poolMint;
1779
+ // Create token account if not specified
1780
+ if (!poolTokenReceiverAccount) {
1781
+ const associatedAddress = getAssociatedTokenAddressSync(poolMint, authorizedPubkey);
1782
+ instructions.push(createAssociatedTokenAccountIdempotentInstruction(authorizedPubkey, associatedAddress, authorizedPubkey, poolMint));
1783
+ poolTokenReceiverAccount = associatedAddress;
1784
+ }
1785
+ instructions.push(...StakeProgram.authorize({
1786
+ stakePubkey: depositStake,
1787
+ authorizedPubkey,
1788
+ newAuthorizedPubkey: stakePool.account.data.stakeDepositAuthority,
1789
+ stakeAuthorizationType: StakeAuthorizationLayout.Staker,
1790
+ }).instructions);
1791
+ instructions.push(...StakeProgram.authorize({
1792
+ stakePubkey: depositStake,
1793
+ authorizedPubkey,
1794
+ newAuthorizedPubkey: stakePool.account.data.stakeDepositAuthority,
1795
+ stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
1796
+ }).instructions);
1797
+ instructions.push(StakePoolInstruction.depositStake({
1798
+ programId: stakePoolProgramId,
1799
+ stakePool: stakePoolAddress,
1800
+ validatorList: stakePool.account.data.validatorList,
1801
+ depositAuthority: stakePool.account.data.stakeDepositAuthority,
1802
+ reserveStake: stakePool.account.data.reserveStake,
1803
+ managerFeeAccount: stakePool.account.data.managerFeeAccount,
1804
+ referralPoolAccount: poolTokenReceiverAccount,
1805
+ destinationPoolAccount: poolTokenReceiverAccount,
1806
+ withdrawAuthority,
1807
+ depositStake,
1808
+ validatorStake,
1809
+ poolMint,
1810
+ }));
1811
+ return {
1812
+ instructions,
1813
+ signers,
1814
+ };
1815
+ }
1816
+ /**
1817
+ * Creates instructions required to deposit sol to stake pool.
1818
+ */
1819
+ async function depositWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, lamports, destinationTokenAccount, referrerTokenAccount, depositAuthority, payer) {
1820
+ const wsolTokenAccount = getAssociatedTokenAddressSync(NATIVE_MINT, userPubkey);
1821
+ const tokenAccountInfo = await connection.getTokenAccountBalance(wsolTokenAccount, 'confirmed');
1822
+ const wsolBalance = tokenAccountInfo
1823
+ ? parseInt(tokenAccountInfo.value.amount)
1824
+ : 0;
1825
+ if (wsolBalance < lamports) {
1826
+ throw new Error(`Not enough WSOL to deposit into pool. Maximum deposit amount is ${lamportsToSol(wsolBalance)} WSOL.`);
1827
+ }
1828
+ const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
1829
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
1830
+ const stakePool = stakePoolAccount.account.data;
1831
+ // stakePool.tokenProgramId
1832
+ const instructions = [];
1833
+ // Create token account if not specified
1834
+ if (!destinationTokenAccount) {
1835
+ const associatedAddress = getAssociatedTokenAddressSync(stakePool.poolMint, userPubkey);
1836
+ instructions.push(createAssociatedTokenAccountIdempotentInstruction(payer !== null && payer !== void 0 ? payer : signerOrSession, associatedAddress, userPubkey, stakePool.poolMint));
1837
+ destinationTokenAccount = associatedAddress;
1838
+ }
1839
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
1840
+ const [programSigner] = PublicKey.findProgramAddressSync([Buffer.from('fogo_session_program_signer')], stakePoolProgramId);
1841
+ const wsolTransientAccount = findWsolTransientProgramAddress(stakePoolProgramId, userPubkey);
1842
+ instructions.push(StakePoolInstruction.depositWsolWithSession({
1843
+ programId: stakePoolProgramId,
1844
+ stakePool: stakePoolAddress,
1845
+ reserveStake: stakePool.reserveStake,
1846
+ fundingAccount: signerOrSession,
1847
+ destinationPoolAccount: destinationTokenAccount,
1848
+ managerFeeAccount: stakePool.managerFeeAccount,
1849
+ referralPoolAccount: referrerTokenAccount !== null && referrerTokenAccount !== void 0 ? referrerTokenAccount : destinationTokenAccount,
1850
+ poolMint: stakePool.poolMint,
1851
+ lamports,
1852
+ withdrawAuthority,
1853
+ depositAuthority,
1854
+ wsolMint: NATIVE_MINT,
1855
+ wsolTokenAccount,
1856
+ wsolTransientAccount,
1857
+ tokenProgramId: stakePool.tokenProgramId,
1858
+ programSigner,
1859
+ payer,
1860
+ }));
1861
+ return {
1862
+ instructions,
1863
+ signers: [],
1864
+ };
1865
+ }
1866
+ /**
1867
+ * Creates instructions required to deposit sol to stake pool.
1868
+ */
1869
+ async function depositSol(connection, stakePoolAddress, from, lamports, destinationTokenAccount, referrerTokenAccount, depositAuthority) {
1870
+ const fromBalance = await connection.getBalance(from, 'confirmed');
1871
+ if (fromBalance < lamports) {
1872
+ throw new Error(`Not enough SOL to deposit into pool. Maximum deposit amount is ${lamportsToSol(fromBalance)} SOL.`);
1873
+ }
1874
+ const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
1875
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
1876
+ const stakePool = stakePoolAccount.account.data;
1877
+ // Ephemeral SOL account just to do the transfer
1878
+ const userSolTransfer = new Keypair();
1879
+ const signers = [userSolTransfer];
1880
+ const instructions = [];
1881
+ // Create the ephemeral SOL account
1882
+ instructions.push(SystemProgram.transfer({
1883
+ fromPubkey: from,
1884
+ toPubkey: userSolTransfer.publicKey,
1885
+ lamports,
1886
+ }));
1887
+ // Create token account if not specified
1888
+ if (!destinationTokenAccount) {
1889
+ const associatedAddress = getAssociatedTokenAddressSync(stakePool.poolMint, from);
1890
+ instructions.push(createAssociatedTokenAccountIdempotentInstruction(from, associatedAddress, from, stakePool.poolMint));
1891
+ destinationTokenAccount = associatedAddress;
1892
+ }
1893
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
1894
+ instructions.push(StakePoolInstruction.depositSol({
1895
+ programId: stakePoolProgramId,
1896
+ stakePool: stakePoolAddress,
1897
+ reserveStake: stakePool.reserveStake,
1898
+ fundingAccount: userSolTransfer.publicKey,
1899
+ destinationPoolAccount: destinationTokenAccount,
1900
+ managerFeeAccount: stakePool.managerFeeAccount,
1901
+ referralPoolAccount: referrerTokenAccount !== null && referrerTokenAccount !== void 0 ? referrerTokenAccount : destinationTokenAccount,
1902
+ poolMint: stakePool.poolMint,
1903
+ lamports,
1904
+ withdrawAuthority,
1905
+ depositAuthority,
1906
+ }));
1907
+ return {
1908
+ instructions,
1909
+ signers,
1910
+ };
1911
+ }
1912
+ /**
1913
+ * Creates instructions required to withdraw stake from a stake pool.
1914
+ */
1915
+ async function withdrawStake(connection, stakePoolAddress, tokenOwner, amount, useReserve = false, voteAccountAddress, stakeReceiver, poolTokenAccount, validatorComparator) {
1916
+ var _c, _d, _e, _f;
1917
+ const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
1918
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
1919
+ const poolAmount = new BN(solToLamports(amount));
1920
+ if (!poolTokenAccount) {
1921
+ poolTokenAccount = getAssociatedTokenAddressSync(stakePool.account.data.poolMint, tokenOwner);
1922
+ }
1923
+ const tokenAccount = await getAccount(connection, poolTokenAccount);
1924
+ // Check withdrawFrom balance
1925
+ if (tokenAccount.amount < poolAmount.toNumber()) {
1926
+ throw new Error(`Not enough token balance to withdraw ${lamportsToSol(poolAmount)} pool tokens.
1927
+ Maximum withdraw amount is ${lamportsToSol(tokenAccount.amount)} pool tokens.`);
1928
+ }
1929
+ const stakeAccountRentExemption = await connection.getMinimumBalanceForRentExemption(StakeProgram.space);
1930
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
1931
+ let stakeReceiverAccount = null;
1932
+ if (stakeReceiver) {
1933
+ stakeReceiverAccount = await getStakeAccount(connection, stakeReceiver);
1934
+ }
1935
+ const withdrawAccounts = [];
1936
+ if (useReserve) {
1937
+ withdrawAccounts.push({
1938
+ stakeAddress: stakePool.account.data.reserveStake,
1939
+ voteAddress: undefined,
1940
+ poolAmount,
1941
+ });
1942
+ }
1943
+ else if (stakeReceiverAccount
1944
+ && (stakeReceiverAccount === null || stakeReceiverAccount === void 0 ? void 0 : stakeReceiverAccount.type) === 'delegated') {
1945
+ const voteAccount = (_d = (_c = stakeReceiverAccount.info) === null || _c === void 0 ? void 0 : _c.stake) === null || _d === void 0 ? void 0 : _d.delegation.voter;
1946
+ if (!voteAccount) {
1947
+ throw new Error(`Invalid stake receiver ${stakeReceiver} delegation`);
1948
+ }
1949
+ const validatorListAccount = await connection.getAccountInfo(stakePool.account.data.validatorList);
1950
+ const validatorList = ValidatorListLayout.decode(validatorListAccount === null || validatorListAccount === void 0 ? void 0 : validatorListAccount.data);
1951
+ const isValidVoter = validatorList.validators.find(val => val.voteAccountAddress.equals(voteAccount));
1952
+ if (voteAccountAddress && voteAccountAddress !== voteAccount) {
1953
+ throw new Error(`Provided withdrawal vote account ${voteAccountAddress} does not match delegation on stake receiver account ${voteAccount},
1954
+ remove this flag or provide a different stake account delegated to ${voteAccountAddress}`);
1955
+ }
1956
+ if (isValidVoter) {
1957
+ const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, voteAccount, stakePoolAddress);
1958
+ const stakeAccount = await connection.getAccountInfo(stakeAccountAddress);
1959
+ if (!stakeAccount) {
1960
+ throw new Error(`Preferred withdraw valdator's stake account is invalid`);
1961
+ }
1962
+ const availableForWithdrawal = calcLamportsWithdrawAmount(stakePool.account.data, new BN(stakeAccount.lamports
1963
+ - MINIMUM_ACTIVE_STAKE
1964
+ - stakeAccountRentExemption));
1965
+ if (availableForWithdrawal.lt(poolAmount)) {
1966
+ throw new Error(`Not enough lamports available for withdrawal from ${stakeAccountAddress},
1967
+ ${poolAmount} asked, ${availableForWithdrawal} available.`);
1968
+ }
1969
+ withdrawAccounts.push({
1970
+ stakeAddress: stakeAccountAddress,
1971
+ voteAddress: voteAccount,
1972
+ poolAmount,
1973
+ });
1974
+ }
1975
+ else {
1976
+ throw new Error(`Provided stake account is delegated to a vote account ${voteAccount} which does not exist in the stake pool`);
1977
+ }
1978
+ }
1979
+ else if (voteAccountAddress) {
1980
+ const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, voteAccountAddress, stakePoolAddress);
1981
+ const stakeAccount = await connection.getAccountInfo(stakeAccountAddress);
1982
+ if (!stakeAccount) {
1983
+ throw new Error('Invalid Stake Account');
1984
+ }
1985
+ const availableLamports = new BN(stakeAccount.lamports - MINIMUM_ACTIVE_STAKE - stakeAccountRentExemption);
1986
+ if (availableLamports.lt(new BN(0))) {
1987
+ throw new Error('Invalid Stake Account');
1988
+ }
1989
+ const availableForWithdrawal = calcLamportsWithdrawAmount(stakePool.account.data, availableLamports);
1990
+ if (availableForWithdrawal.lt(poolAmount)) {
1991
+ // noinspection ExceptionCaughtLocallyJS
1992
+ throw new Error(`Not enough lamports available for withdrawal from ${stakeAccountAddress},
1993
+ ${poolAmount} asked, ${availableForWithdrawal} available.`);
1994
+ }
1995
+ withdrawAccounts.push({
1996
+ stakeAddress: stakeAccountAddress,
1997
+ voteAddress: voteAccountAddress,
1998
+ poolAmount,
1999
+ });
2000
+ }
2001
+ else {
2002
+ // Get the list of accounts to withdraw from
2003
+ withdrawAccounts.push(...(await prepareWithdrawAccounts(connection, stakePool.account.data, stakePoolAddress, poolAmount, validatorComparator, poolTokenAccount.equals(stakePool.account.data.managerFeeAccount))));
2004
+ }
2005
+ // Construct transaction to withdraw from withdrawAccounts account list
2006
+ const instructions = [];
2007
+ const userTransferAuthority = Keypair.generate();
2008
+ const signers = [userTransferAuthority];
2009
+ instructions.push(createApproveInstruction(poolTokenAccount, userTransferAuthority.publicKey, tokenOwner, poolAmount.toNumber()));
2010
+ let totalRentFreeBalances = 0;
2011
+ // Max 5 accounts to prevent an error: "Transaction too large"
2012
+ const maxWithdrawAccounts = 5;
2013
+ let i = 0;
2014
+ // Go through prepared accounts and withdraw/claim them
2015
+ for (const withdrawAccount of withdrawAccounts) {
2016
+ if (i > maxWithdrawAccounts) {
2017
+ break;
2018
+ }
2019
+ // Convert pool tokens amount to lamports
2020
+ const solWithdrawAmount = calcLamportsWithdrawAmount(stakePool.account.data, withdrawAccount.poolAmount);
2021
+ let infoMsg = `Withdrawing ◎${solWithdrawAmount},
2022
+ from stake account ${(_e = withdrawAccount.stakeAddress) === null || _e === void 0 ? void 0 : _e.toBase58()}`;
2023
+ if (withdrawAccount.voteAddress) {
2024
+ infoMsg = `${infoMsg}, delegated to ${(_f = withdrawAccount.voteAddress) === null || _f === void 0 ? void 0 : _f.toBase58()}`;
2025
+ }
2026
+ console.info(infoMsg);
2027
+ let stakeToReceive;
2028
+ if (!stakeReceiver
2029
+ || (stakeReceiverAccount && stakeReceiverAccount.type === 'delegated')) {
2030
+ const stakeKeypair = newStakeAccount(tokenOwner, instructions, stakeAccountRentExemption);
2031
+ signers.push(stakeKeypair);
2032
+ totalRentFreeBalances += stakeAccountRentExemption;
2033
+ stakeToReceive = stakeKeypair.publicKey;
2034
+ }
2035
+ else {
2036
+ stakeToReceive = stakeReceiver;
2037
+ }
2038
+ instructions.push(StakePoolInstruction.withdrawStake({
2039
+ programId: stakePoolProgramId,
2040
+ stakePool: stakePoolAddress,
2041
+ validatorList: stakePool.account.data.validatorList,
2042
+ validatorStake: withdrawAccount.stakeAddress,
2043
+ destinationStake: stakeToReceive,
2044
+ destinationStakeAuthority: tokenOwner,
2045
+ sourceTransferAuthority: userTransferAuthority.publicKey,
2046
+ sourcePoolAccount: poolTokenAccount,
2047
+ managerFeeAccount: stakePool.account.data.managerFeeAccount,
2048
+ poolMint: stakePool.account.data.poolMint,
2049
+ poolTokens: withdrawAccount.poolAmount.toNumber(),
2050
+ withdrawAuthority,
2051
+ }));
2052
+ i++;
2053
+ }
2054
+ if (stakeReceiver
2055
+ && stakeReceiverAccount
2056
+ && stakeReceiverAccount.type === 'delegated') {
2057
+ signers.forEach((newStakeKeypair) => {
2058
+ instructions.concat(StakeProgram.merge({
2059
+ stakePubkey: stakeReceiver,
2060
+ sourceStakePubKey: newStakeKeypair.publicKey,
2061
+ authorizedPubkey: tokenOwner,
2062
+ }).instructions);
2063
+ });
2064
+ }
2065
+ return {
2066
+ instructions,
2067
+ signers,
2068
+ stakeReceiver,
2069
+ totalRentFreeBalances,
2070
+ };
2071
+ }
2072
+ /**
2073
+ * Creates instructions required to withdraw SOL directly from a stake pool.
2074
+ */
2075
+ async function withdrawSol(connection, stakePoolAddress, tokenOwner, solReceiver, amount, solWithdrawAuthority) {
2076
+ const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
2077
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2078
+ const poolAmount = solToLamports(amount);
2079
+ const poolTokenAccount = getAssociatedTokenAddressSync(stakePool.account.data.poolMint, tokenOwner);
2080
+ const tokenAccount = await getAccount(connection, poolTokenAccount);
2081
+ // Check withdrawFrom balance
2082
+ if (tokenAccount.amount < poolAmount) {
2083
+ throw new Error(`Not enough token balance to withdraw ${lamportsToSol(poolAmount)} pool tokens.
2084
+ Maximum withdraw amount is ${lamportsToSol(tokenAccount.amount)} pool tokens.`);
2085
+ }
2086
+ // Construct transaction to withdraw from withdrawAccounts account list
2087
+ const instructions = [];
2088
+ const userTransferAuthority = Keypair.generate();
2089
+ const signers = [userTransferAuthority];
2090
+ instructions.push(createApproveInstruction(poolTokenAccount, userTransferAuthority.publicKey, tokenOwner, poolAmount));
2091
+ const poolWithdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2092
+ if (solWithdrawAuthority) {
2093
+ const expectedSolWithdrawAuthority = stakePool.account.data.solWithdrawAuthority;
2094
+ if (!expectedSolWithdrawAuthority) {
2095
+ throw new Error('SOL withdraw authority specified in arguments but stake pool has none');
2096
+ }
2097
+ if (solWithdrawAuthority.toBase58() !== expectedSolWithdrawAuthority.toBase58()) {
2098
+ throw new Error(`Invalid deposit withdraw specified, expected ${expectedSolWithdrawAuthority.toBase58()}, received ${solWithdrawAuthority.toBase58()}`);
2099
+ }
2100
+ }
2101
+ const withdrawTransaction = StakePoolInstruction.withdrawSol({
2102
+ programId: stakePoolProgramId,
2103
+ stakePool: stakePoolAddress,
2104
+ withdrawAuthority: poolWithdrawAuthority,
2105
+ reserveStake: stakePool.account.data.reserveStake,
2106
+ sourcePoolAccount: poolTokenAccount,
2107
+ sourceTransferAuthority: userTransferAuthority.publicKey,
2108
+ destinationSystemAccount: solReceiver,
2109
+ managerFeeAccount: stakePool.account.data.managerFeeAccount,
2110
+ poolMint: stakePool.account.data.poolMint,
2111
+ poolTokens: poolAmount,
2112
+ solWithdrawAuthority,
2113
+ });
2114
+ instructions.push(withdrawTransaction);
2115
+ return {
2116
+ instructions,
2117
+ signers,
2118
+ };
2119
+ }
2120
+ /**
2121
+ * Creates instructions required to withdraw wSOL from a stake pool.
2122
+ */
2123
+ async function withdrawWsolWithSession(connection, stakePoolAddress, signerOrSession, userPubkey, amount, solWithdrawAuthority) {
2124
+ const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
2125
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2126
+ const stakePool = stakePoolAccount.account.data;
2127
+ const poolTokens = solToLamports(amount);
2128
+ const poolTokenAccount = getAssociatedTokenAddressSync(stakePool.poolMint, userPubkey);
2129
+ const tokenAccount = await getAccount(connection, poolTokenAccount);
2130
+ if (tokenAccount.amount < poolTokens) {
2131
+ throw new Error(`Not enough token balance to withdraw ${amount} pool tokens.
2132
+ Maximum withdraw amount is ${lamportsToSol(tokenAccount.amount)} pool tokens.`);
2133
+ }
2134
+ const userWsolAccount = getAssociatedTokenAddressSync(NATIVE_MINT, userPubkey);
2135
+ const instructions = [];
2136
+ const signers = [];
2137
+ instructions.push(createAssociatedTokenAccountIdempotentInstruction(signerOrSession, userWsolAccount, userPubkey, NATIVE_MINT));
2138
+ const [programSigner] = PublicKey.findProgramAddressSync([Buffer.from('fogo_session_program_signer')], stakePoolProgramId);
2139
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2140
+ instructions.push(StakePoolInstruction.withdrawWsolWithSession({
2141
+ programId: stakePoolProgramId,
2142
+ stakePool: stakePoolAddress,
2143
+ withdrawAuthority,
2144
+ userTransferAuthority: signerOrSession,
2145
+ poolTokensFrom: poolTokenAccount,
2146
+ reserveStake: stakePool.reserveStake,
2147
+ userWsolAccount,
2148
+ managerFeeAccount: stakePool.managerFeeAccount,
2149
+ poolMint: stakePool.poolMint,
2150
+ tokenProgramId: stakePool.tokenProgramId,
2151
+ solWithdrawAuthority,
2152
+ wsolMint: NATIVE_MINT,
2153
+ programSigner,
2154
+ poolTokens,
2155
+ }));
2156
+ return {
2157
+ instructions,
2158
+ signers,
2159
+ };
2160
+ }
2161
+ async function addValidatorToPool(connection, stakePoolAddress, validatorVote, seed) {
2162
+ const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
2163
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2164
+ const stakePool = stakePoolAccount.account.data;
2165
+ const { reserveStake, staker, validatorList } = stakePool;
2166
+ const validatorListAccount = await getValidatorListAccount(connection, validatorList);
2167
+ const validatorInfo = validatorListAccount.account.data.validators.find(v => v.voteAccountAddress.toBase58() === validatorVote.toBase58());
2168
+ if (validatorInfo) {
2169
+ throw new Error('Vote account is already in validator list');
2170
+ }
2171
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2172
+ const validatorStake = await findStakeProgramAddress(stakePoolProgramId, validatorVote, stakePoolAddress, seed);
2173
+ const instructions = [
2174
+ StakePoolInstruction.addValidatorToPool({
2175
+ programId: stakePoolProgramId,
2176
+ stakePool: stakePoolAddress,
2177
+ staker,
2178
+ reserveStake,
2179
+ withdrawAuthority,
2180
+ validatorList,
2181
+ validatorStake,
2182
+ validatorVote,
2183
+ }),
2184
+ ];
2185
+ return {
2186
+ instructions,
2187
+ };
2188
+ }
2189
+ async function removeValidatorFromPool(connection, stakePoolAddress, validatorVote, seed) {
2190
+ const stakePoolAccount = await getStakePoolAccount(connection, stakePoolAddress);
2191
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2192
+ const stakePool = stakePoolAccount.account.data;
2193
+ const { staker, validatorList } = stakePool;
2194
+ const validatorListAccount = await getValidatorListAccount(connection, validatorList);
2195
+ const validatorInfo = validatorListAccount.account.data.validators.find(v => v.voteAccountAddress.toBase58() === validatorVote.toBase58());
2196
+ if (!validatorInfo) {
2197
+ throw new Error('Vote account is not already in validator list');
2198
+ }
2199
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2200
+ const validatorStake = await findStakeProgramAddress(stakePoolProgramId, validatorVote, stakePoolAddress, seed);
2201
+ const transientStakeSeed = validatorInfo.transientSeedSuffixStart;
2202
+ const transientStake = await findTransientStakeProgramAddress(stakePoolProgramId, validatorInfo.voteAccountAddress, stakePoolAddress, transientStakeSeed);
2203
+ const instructions = [
2204
+ StakePoolInstruction.removeValidatorFromPool({
2205
+ programId: stakePoolProgramId,
2206
+ stakePool: stakePoolAddress,
2207
+ staker,
2208
+ withdrawAuthority,
2209
+ validatorList,
2210
+ validatorStake,
2211
+ transientStake,
2212
+ }),
2213
+ ];
2214
+ return {
2215
+ instructions,
2216
+ };
2217
+ }
2218
+ /**
2219
+ * Creates instructions required to increase validator stake.
2220
+ */
2221
+ async function increaseValidatorStake(connection, stakePoolAddress, validatorVote, lamports, ephemeralStakeSeed) {
2222
+ const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
2223
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2224
+ const validatorList = await getValidatorListAccount(connection, stakePool.account.data.validatorList);
2225
+ const validatorInfo = validatorList.account.data.validators.find(v => v.voteAccountAddress.toBase58() === validatorVote.toBase58());
2226
+ if (!validatorInfo) {
2227
+ throw new Error('Vote account not found in validator list');
2228
+ }
2229
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2230
+ // Bump transient seed suffix by one to avoid reuse when not using the increaseAdditionalStake instruction
2231
+ const transientStakeSeed = ephemeralStakeSeed === undefined
2232
+ ? validatorInfo.transientSeedSuffixStart.addn(1)
2233
+ : validatorInfo.transientSeedSuffixStart;
2234
+ const transientStake = await findTransientStakeProgramAddress(stakePoolProgramId, validatorInfo.voteAccountAddress, stakePoolAddress, transientStakeSeed);
2235
+ const validatorStake = await findStakeProgramAddress(stakePoolProgramId, validatorInfo.voteAccountAddress, stakePoolAddress);
2236
+ const instructions = [];
2237
+ if (ephemeralStakeSeed !== undefined) {
2238
+ const ephemeralStake = await findEphemeralStakeProgramAddress(stakePoolProgramId, stakePoolAddress, new BN(ephemeralStakeSeed));
2239
+ instructions.push(StakePoolInstruction.increaseAdditionalValidatorStake({
2240
+ programId: stakePoolProgramId,
2241
+ stakePool: stakePoolAddress,
2242
+ staker: stakePool.account.data.staker,
2243
+ validatorList: stakePool.account.data.validatorList,
2244
+ reserveStake: stakePool.account.data.reserveStake,
2245
+ transientStakeSeed: transientStakeSeed.toNumber(),
2246
+ withdrawAuthority,
2247
+ transientStake,
2248
+ validatorStake,
2249
+ validatorVote,
2250
+ lamports,
2251
+ ephemeralStake,
2252
+ ephemeralStakeSeed,
2253
+ }));
2254
+ }
2255
+ else {
2256
+ instructions.push(StakePoolInstruction.increaseValidatorStake({
2257
+ programId: stakePoolProgramId,
2258
+ stakePool: stakePoolAddress,
2259
+ staker: stakePool.account.data.staker,
2260
+ validatorList: stakePool.account.data.validatorList,
2261
+ reserveStake: stakePool.account.data.reserveStake,
2262
+ transientStakeSeed: transientStakeSeed.toNumber(),
2263
+ withdrawAuthority,
2264
+ transientStake,
2265
+ validatorStake,
2266
+ validatorVote,
2267
+ lamports,
2268
+ }));
2269
+ }
2270
+ return {
2271
+ instructions,
2272
+ };
2273
+ }
2274
+ /**
2275
+ * Creates instructions required to decrease validator stake.
2276
+ */
2277
+ async function decreaseValidatorStake(connection, stakePoolAddress, validatorVote, lamports, ephemeralStakeSeed) {
2278
+ const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
2279
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2280
+ const validatorList = await getValidatorListAccount(connection, stakePool.account.data.validatorList);
2281
+ const validatorInfo = validatorList.account.data.validators.find(v => v.voteAccountAddress.toBase58() === validatorVote.toBase58());
2282
+ if (!validatorInfo) {
2283
+ throw new Error('Vote account not found in validator list');
2284
+ }
2285
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2286
+ const validatorStake = await findStakeProgramAddress(stakePoolProgramId, validatorInfo.voteAccountAddress, stakePoolAddress);
2287
+ // Bump transient seed suffix by one to avoid reuse when not using the decreaseAdditionalStake instruction
2288
+ const transientStakeSeed = ephemeralStakeSeed === undefined
2289
+ ? validatorInfo.transientSeedSuffixStart.addn(1)
2290
+ : validatorInfo.transientSeedSuffixStart;
2291
+ const transientStake = await findTransientStakeProgramAddress(stakePoolProgramId, validatorInfo.voteAccountAddress, stakePoolAddress, transientStakeSeed);
2292
+ const instructions = [];
2293
+ if (ephemeralStakeSeed !== undefined) {
2294
+ const ephemeralStake = await findEphemeralStakeProgramAddress(stakePoolProgramId, stakePoolAddress, new BN(ephemeralStakeSeed));
2295
+ instructions.push(StakePoolInstruction.decreaseAdditionalValidatorStake({
2296
+ programId: stakePoolProgramId,
2297
+ stakePool: stakePoolAddress,
2298
+ staker: stakePool.account.data.staker,
2299
+ validatorList: stakePool.account.data.validatorList,
2300
+ reserveStake: stakePool.account.data.reserveStake,
2301
+ transientStakeSeed: transientStakeSeed.toNumber(),
2302
+ withdrawAuthority,
2303
+ validatorStake,
2304
+ transientStake,
2305
+ lamports,
2306
+ ephemeralStake,
2307
+ ephemeralStakeSeed,
2308
+ }));
2309
+ }
2310
+ else {
2311
+ instructions.push(StakePoolInstruction.decreaseValidatorStakeWithReserve({
2312
+ programId: stakePoolProgramId,
2313
+ stakePool: stakePoolAddress,
2314
+ staker: stakePool.account.data.staker,
2315
+ validatorList: stakePool.account.data.validatorList,
2316
+ reserveStake: stakePool.account.data.reserveStake,
2317
+ transientStakeSeed: transientStakeSeed.toNumber(),
2318
+ withdrawAuthority,
2319
+ validatorStake,
2320
+ transientStake,
2321
+ lamports,
2322
+ }));
2323
+ }
2324
+ return {
2325
+ instructions,
2326
+ };
2327
+ }
2328
+ /**
2329
+ * Creates instructions required to completely update a stake pool after epoch change.
2330
+ */
2331
+ async function updateStakePool(connection, stakePool, noMerge = false) {
2332
+ const stakePoolAddress = stakePool.pubkey;
2333
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2334
+ const validatorList = await getValidatorListAccount(connection, stakePool.account.data.validatorList);
2335
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2336
+ const updateListInstructions = [];
2337
+ const instructions = [];
2338
+ let startIndex = 0;
2339
+ const validatorChunks = arrayChunk(validatorList.account.data.validators, MAX_VALIDATORS_TO_UPDATE);
2340
+ for (const validatorChunk of validatorChunks) {
2341
+ const validatorAndTransientStakePairs = [];
2342
+ for (const validator of validatorChunk) {
2343
+ const validatorStake = await findStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress);
2344
+ validatorAndTransientStakePairs.push(validatorStake);
2345
+ const transientStake = await findTransientStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress, validator.transientSeedSuffixStart);
2346
+ validatorAndTransientStakePairs.push(transientStake);
2347
+ }
2348
+ updateListInstructions.push(StakePoolInstruction.updateValidatorListBalance({
2349
+ programId: stakePoolProgramId,
2350
+ stakePool: stakePoolAddress,
2351
+ validatorList: stakePool.account.data.validatorList,
2352
+ reserveStake: stakePool.account.data.reserveStake,
2353
+ validatorAndTransientStakePairs,
2354
+ withdrawAuthority,
2355
+ startIndex,
2356
+ noMerge,
2357
+ }));
2358
+ startIndex += MAX_VALIDATORS_TO_UPDATE;
2359
+ }
2360
+ instructions.push(StakePoolInstruction.updateStakePoolBalance({
2361
+ programId: stakePoolProgramId,
2362
+ stakePool: stakePoolAddress,
2363
+ validatorList: stakePool.account.data.validatorList,
2364
+ reserveStake: stakePool.account.data.reserveStake,
2365
+ managerFeeAccount: stakePool.account.data.managerFeeAccount,
2366
+ poolMint: stakePool.account.data.poolMint,
2367
+ withdrawAuthority,
2368
+ }));
2369
+ instructions.push(StakePoolInstruction.cleanupRemovedValidatorEntries({
2370
+ programId: stakePoolProgramId,
2371
+ stakePool: stakePoolAddress,
2372
+ validatorList: stakePool.account.data.validatorList,
2373
+ }));
2374
+ return {
2375
+ updateListInstructions,
2376
+ finalInstructions: instructions,
2377
+ };
2378
+ }
2379
+ /**
2380
+ * Retrieves detailed information about the StakePool.
2381
+ */
2382
+ async function stakePoolInfo(connection, stakePoolAddress) {
2383
+ var _c, _d;
2384
+ const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
2385
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2386
+ const reserveAccountStakeAddress = stakePool.account.data.reserveStake;
2387
+ const totalLamports = stakePool.account.data.totalLamports;
2388
+ const lastUpdateEpoch = stakePool.account.data.lastUpdateEpoch;
2389
+ const validatorList = await getValidatorListAccount(connection, stakePool.account.data.validatorList);
2390
+ const maxNumberOfValidators = validatorList.account.data.maxValidators;
2391
+ const currentNumberOfValidators = validatorList.account.data.validators.length;
2392
+ const epochInfo = await connection.getEpochInfo();
2393
+ const reserveStake = await connection.getAccountInfo(reserveAccountStakeAddress);
2394
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2395
+ const minimumReserveStakeBalance = await connection.getMinimumBalanceForRentExemption(StakeProgram.space);
2396
+ const stakeAccounts = await Promise.all(validatorList.account.data.validators.map(async (validator) => {
2397
+ const stakeAccountAddress = await findStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress);
2398
+ const transientStakeAccountAddress = await findTransientStakeProgramAddress(stakePoolProgramId, validator.voteAccountAddress, stakePoolAddress, validator.transientSeedSuffixStart);
2399
+ const updateRequired = !validator.lastUpdateEpoch.eqn(epochInfo.epoch);
2400
+ return {
2401
+ voteAccountAddress: validator.voteAccountAddress.toBase58(),
2402
+ stakeAccountAddress: stakeAccountAddress.toBase58(),
2403
+ validatorActiveStakeLamports: validator.activeStakeLamports.toString(),
2404
+ validatorLastUpdateEpoch: validator.lastUpdateEpoch.toString(),
2405
+ validatorLamports: validator.activeStakeLamports
2406
+ .add(validator.transientStakeLamports)
2407
+ .toString(),
2408
+ validatorTransientStakeAccountAddress: transientStakeAccountAddress.toBase58(),
2409
+ validatorTransientStakeLamports: validator.transientStakeLamports.toString(),
2410
+ updateRequired,
2411
+ };
2412
+ }));
2413
+ const totalPoolTokens = lamportsToSol(stakePool.account.data.poolTokenSupply);
2414
+ const updateRequired = !lastUpdateEpoch.eqn(epochInfo.epoch);
2415
+ return {
2416
+ address: stakePoolAddress.toBase58(),
2417
+ poolWithdrawAuthority: withdrawAuthority.toBase58(),
2418
+ manager: stakePool.account.data.manager.toBase58(),
2419
+ staker: stakePool.account.data.staker.toBase58(),
2420
+ stakeDepositAuthority: stakePool.account.data.stakeDepositAuthority.toBase58(),
2421
+ stakeWithdrawBumpSeed: stakePool.account.data.stakeWithdrawBumpSeed,
2422
+ maxValidators: maxNumberOfValidators,
2423
+ validatorList: validatorList.account.data.validators.map((validator) => {
2424
+ return {
2425
+ activeStakeLamports: validator.activeStakeLamports.toString(),
2426
+ transientStakeLamports: validator.transientStakeLamports.toString(),
2427
+ lastUpdateEpoch: validator.lastUpdateEpoch.toString(),
2428
+ transientSeedSuffixStart: validator.transientSeedSuffixStart.toString(),
2429
+ transientSeedSuffixEnd: validator.transientSeedSuffixEnd.toString(),
2430
+ status: validator.status.toString(),
2431
+ voteAccountAddress: validator.voteAccountAddress.toString(),
2432
+ };
2433
+ }), // CliStakePoolValidator
2434
+ validatorListStorageAccount: stakePool.account.data.validatorList.toBase58(),
2435
+ reserveStake: stakePool.account.data.reserveStake.toBase58(),
2436
+ poolMint: stakePool.account.data.poolMint.toBase58(),
2437
+ managerFeeAccount: stakePool.account.data.managerFeeAccount.toBase58(),
2438
+ tokenProgramId: stakePool.account.data.tokenProgramId.toBase58(),
2439
+ totalLamports: stakePool.account.data.totalLamports.toString(),
2440
+ poolTokenSupply: stakePool.account.data.poolTokenSupply.toString(),
2441
+ lastUpdateEpoch: stakePool.account.data.lastUpdateEpoch.toString(),
2442
+ lockup: stakePool.account.data.lockup, // pub lockup: CliStakePoolLockup
2443
+ epochFee: stakePool.account.data.epochFee,
2444
+ nextEpochFee: stakePool.account.data.nextEpochFee,
2445
+ preferredDepositValidatorVoteAddress: stakePool.account.data.preferredDepositValidatorVoteAddress,
2446
+ preferredWithdrawValidatorVoteAddress: stakePool.account.data.preferredWithdrawValidatorVoteAddress,
2447
+ stakeDepositFee: stakePool.account.data.stakeDepositFee,
2448
+ stakeWithdrawalFee: stakePool.account.data.stakeWithdrawalFee,
2449
+ // CliStakePool the same
2450
+ nextStakeWithdrawalFee: stakePool.account.data.nextStakeWithdrawalFee,
2451
+ stakeReferralFee: stakePool.account.data.stakeReferralFee,
2452
+ solDepositAuthority: (_c = stakePool.account.data.solDepositAuthority) === null || _c === void 0 ? void 0 : _c.toBase58(),
2453
+ solDepositFee: stakePool.account.data.solDepositFee,
2454
+ solReferralFee: stakePool.account.data.solReferralFee,
2455
+ solWithdrawAuthority: (_d = stakePool.account.data.solWithdrawAuthority) === null || _d === void 0 ? void 0 : _d.toBase58(),
2456
+ solWithdrawalFee: stakePool.account.data.solWithdrawalFee,
2457
+ nextSolWithdrawalFee: stakePool.account.data.nextSolWithdrawalFee,
2458
+ lastEpochPoolTokenSupply: stakePool.account.data.lastEpochPoolTokenSupply.toString(),
2459
+ lastEpochTotalLamports: stakePool.account.data.lastEpochTotalLamports.toString(),
2460
+ details: {
2461
+ reserveStakeLamports: reserveStake === null || reserveStake === void 0 ? void 0 : reserveStake.lamports,
2462
+ reserveAccountStakeAddress: reserveAccountStakeAddress.toBase58(),
2463
+ minimumReserveStakeBalance,
2464
+ stakeAccounts,
2465
+ totalLamports,
2466
+ totalPoolTokens,
2467
+ currentNumberOfValidators,
2468
+ maxNumberOfValidators,
2469
+ updateRequired,
2470
+ }, // CliStakePoolDetails
2471
+ };
2472
+ }
2473
+ /**
2474
+ * Creates instructions required to create pool token metadata.
2475
+ */
2476
+ async function createPoolTokenMetadata(connection, stakePoolAddress, payer, name, symbol, uri) {
2477
+ const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
2478
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2479
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2480
+ const tokenMetadata = findMetadataAddress(stakePool.account.data.poolMint);
2481
+ const manager = stakePool.account.data.manager;
2482
+ const instructions = [];
2483
+ instructions.push(StakePoolInstruction.createTokenMetadata({
2484
+ programId: stakePoolProgramId,
2485
+ stakePool: stakePoolAddress,
2486
+ poolMint: stakePool.account.data.poolMint,
2487
+ payer,
2488
+ manager,
2489
+ tokenMetadata,
2490
+ withdrawAuthority,
2491
+ name,
2492
+ symbol,
2493
+ uri,
2494
+ }));
2495
+ return {
2496
+ instructions,
2497
+ };
2498
+ }
2499
+ /**
2500
+ * Creates instructions required to update pool token metadata.
2501
+ */
2502
+ async function updatePoolTokenMetadata(connection, stakePoolAddress, name, symbol, uri) {
2503
+ const stakePool = await getStakePoolAccount(connection, stakePoolAddress);
2504
+ const stakePoolProgramId = getStakePoolProgramId(connection.rpcEndpoint);
2505
+ const withdrawAuthority = await findWithdrawAuthorityProgramAddress(stakePoolProgramId, stakePoolAddress);
2506
+ const tokenMetadata = findMetadataAddress(stakePool.account.data.poolMint);
2507
+ const instructions = [];
2508
+ instructions.push(StakePoolInstruction.updateTokenMetadata({
2509
+ programId: stakePoolProgramId,
2510
+ stakePool: stakePoolAddress,
2511
+ manager: stakePool.account.data.manager,
2512
+ tokenMetadata,
2513
+ withdrawAuthority,
2514
+ name,
2515
+ symbol,
2516
+ uri,
2517
+ }));
2518
+ return {
2519
+ instructions,
2520
+ };
2521
+ }
2522
+
2523
+ export { DEVNET_STAKE_POOL_PROGRAM_ID, STAKE_POOL_INSTRUCTION_LAYOUTS, STAKE_POOL_PROGRAM_ID, StakePoolInstruction, StakePoolLayout, ValidatorListLayout, ValidatorStakeInfoLayout, addValidatorToPool, createPoolTokenMetadata, decreaseValidatorStake, depositSol, depositStake, depositWsolWithSession, getStakeAccount, getStakePoolAccount, getStakePoolAccounts, getStakePoolProgramId, increaseValidatorStake, removeValidatorFromPool, stakePoolInfo, tokenMetadataLayout, updatePoolTokenMetadata, updateStakePool, withdrawSol, withdrawStake, withdrawWsolWithSession };
2524
+ //# sourceMappingURL=index.browser.esm.js.map