@wireio/stake 2.2.2 → 2.3.1

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.
@@ -1,175 +1,11 @@
1
1
  import { SolChainID, PublicKey as PublicKey$1, KeyType, EvmChainID } from '@wireio/core';
2
- import { SystemProgram, StakeProgram, SYSVAR_INSTRUCTIONS_PUBKEY, SYSVAR_CLOCK_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY, SYSVAR_RENT_PUBKEY, PublicKey, Keypair, Connection, ComputeBudgetProgram, TransactionMessage, Transaction, SendTransactionError } from '@solana/web3.js';
2
+ import { PublicKey, StakeProgram, Keypair, SystemProgram, SYSVAR_INSTRUCTIONS_PUBKEY, SYSVAR_CLOCK_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY, SYSVAR_RENT_PUBKEY, Connection, ComputeBudgetProgram, TransactionMessage, Transaction, SendTransactionError } from '@solana/web3.js';
3
3
  import { BN, Program, AnchorProvider } from '@coral-xyz/anchor';
4
- import { getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, getAssociatedTokenAddress } from '@solana/spl-token';
4
+ import { getAssociatedTokenAddress, TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, ASSOCIATED_TOKEN_PROGRAM_ID } from '@solana/spl-token';
5
5
  import * as multisig from '@sqds/multisig';
6
6
  import bs58 from 'bs58';
7
7
  import { ethers, Contract, BigNumber } from 'ethers';
8
8
 
9
- class DepositClient {
10
- constructor(provider, pgs) {
11
- this.provider = provider;
12
- this.pgs = pgs;
13
- this.program = pgs.getProgram("liqsolCore");
14
- }
15
- get connection() {
16
- return this.provider.connection;
17
- }
18
- get wallet() {
19
- return this.provider.wallet;
20
- }
21
- async buildDepositTx(amount, user = this.wallet.publicKey) {
22
- if (!user) {
23
- throw new Error(
24
- "DepositClient.buildDepositTx: wallet not connected"
25
- );
26
- }
27
- if (!amount || amount <= BigInt(0)) {
28
- throw new Error(
29
- "DepositClient.buildDepositTx: amount must be greater than zero."
30
- );
31
- }
32
- const depositAuthority = this.pgs.deriveDepositAuthorityPda();
33
- const liqsolMint = this.pgs.deriveLiqsolMintPda();
34
- const liqsolMintAuthority = this.pgs.deriveLiqsolMintAuthorityPda();
35
- const reservePool = this.pgs.deriveReservePoolPda();
36
- const vault = this.pgs.deriveVaultPda();
37
- const controllerState = this.pgs.deriveStakeControllerStatePda();
38
- const payoutState = this.pgs.derivePayoutStatePda();
39
- const bucketAuthority = this.pgs.deriveBucketAuthorityPda();
40
- const payRateHistory = this.pgs.derivePayRateHistoryPda();
41
- const globalConfig = this.pgs.deriveGlobalConfigPda();
42
- const userAta = getAssociatedTokenAddressSync(
43
- liqsolMint,
44
- user,
45
- true,
46
- TOKEN_2022_PROGRAM_ID
47
- );
48
- const distributionState = this.pgs.deriveDistributionStatePda();
49
- const userRecord = this.pgs.deriveUserRecordPda(userAta);
50
- const bucketTokenAccount = getAssociatedTokenAddressSync(
51
- liqsolMint,
52
- bucketAuthority,
53
- true,
54
- TOKEN_2022_PROGRAM_ID
55
- );
56
- const seed = Math.floor(Math.random() * 2 ** 32);
57
- const ephemeralStake = await this.pgs.deriveEphemeralStakeAddress(user, seed);
58
- return await this.program.methods.deposit(new BN(amount.toString()), seed).accounts({
59
- user,
60
- depositAuthority,
61
- systemProgram: SystemProgram.programId,
62
- tokenProgram: TOKEN_2022_PROGRAM_ID,
63
- associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
64
- liqsolProgram: this.pgs.PROGRAM_IDS.LIQSOL_TOKEN,
65
- stakeProgram: StakeProgram.programId,
66
- liqsolMint,
67
- userAta,
68
- liqsolMintAuthority,
69
- reservePool,
70
- vault,
71
- ephemeralStake,
72
- controllerState,
73
- payoutState,
74
- bucketAuthority,
75
- bucketTokenAccount,
76
- userRecord,
77
- distributionState,
78
- payRateHistory,
79
- instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,
80
- clock: SYSVAR_CLOCK_PUBKEY,
81
- stakeHistory: SYSVAR_STAKE_HISTORY_PUBKEY,
82
- rent: SYSVAR_RENT_PUBKEY,
83
- globalConfig
84
- }).instruction();
85
- }
86
- async buildWithdrawTx(amount, user = this.wallet.publicKey) {
87
- if (!user) {
88
- throw new Error(
89
- "DepositClient.buildWithdrawTx: wallet not connected"
90
- );
91
- }
92
- if (!amount || amount <= BigInt(0)) {
93
- throw new Error(
94
- "DepositClient.buildWithdrawTx: amount must be greater than zero."
95
- );
96
- }
97
- const liqsolMint = this.pgs.deriveLiqsolMintPda();
98
- const userAta = getAssociatedTokenAddressSync(
99
- liqsolMint,
100
- user,
101
- true,
102
- TOKEN_2022_PROGRAM_ID
103
- );
104
- const userRecord = this.pgs.deriveUserRecordPda(userAta);
105
- const distributionState = this.pgs.deriveDistributionStatePda();
106
- const global = this.pgs.deriveWithdrawGlobalPda();
107
- const reservePool = this.pgs.deriveReservePoolPda();
108
- const stakeAllocationState = this.pgs.deriveStakeAllocationStatePda();
109
- const stakeMetrics = this.pgs.deriveStakeMetricsPda();
110
- const maintenanceLedger = this.pgs.deriveMaintenanceLedgerPda();
111
- const globalConfig = this.pgs.deriveGlobalConfigPda();
112
- const globalAcct = await this.program.account.global.fetch(global);
113
- const rawId = globalAcct.nextReceiptId;
114
- let receiptId;
115
- if (typeof rawId === "bigint") {
116
- receiptId = rawId;
117
- } else if (rawId != null && typeof rawId === "object" && "toString" in rawId) {
118
- receiptId = BigInt(rawId.toString());
119
- } else if (typeof rawId === "number") {
120
- receiptId = BigInt(rawId);
121
- } else {
122
- throw new Error(
123
- `DepositClient.buildWithdrawTx: unexpected nextReceiptId type (${typeof rawId})`
124
- );
125
- }
126
- const mintAuthority = this.pgs.deriveWithdrawMintAuthorityPda();
127
- const metadata = this.pgs.deriveWithdrawMintMetadataPda();
128
- const nftMint = this.pgs.deriveWithdrawNftMintPda(receiptId);
129
- const receiptData = this.pgs.deriveLiqReceiptDataPda(nftMint);
130
- const owner = user;
131
- const nftAta = getAssociatedTokenAddressSync(
132
- nftMint,
133
- owner,
134
- true,
135
- TOKEN_2022_PROGRAM_ID
136
- );
137
- const bucketAuthority = this.pgs.deriveBucketAuthorityPda();
138
- const bucketTokenAccount = getAssociatedTokenAddressSync(
139
- liqsolMint,
140
- bucketAuthority,
141
- true,
142
- TOKEN_2022_PROGRAM_ID
143
- );
144
- return await this.program.methods.requestWithdraw(new BN(amount.toString())).accounts({
145
- user,
146
- owner,
147
- global,
148
- liqsolMint,
149
- userAta,
150
- userRecord,
151
- reservePool,
152
- stakeAllocationState,
153
- stakeMetrics,
154
- maintenanceLedger,
155
- clock: SYSVAR_CLOCK_PUBKEY,
156
- mintAuthority,
157
- receiptData,
158
- metadata,
159
- nftMint,
160
- nftAta,
161
- distributionState,
162
- bucketTokenAccount,
163
- tokenProgram: TOKEN_2022_PROGRAM_ID,
164
- tokenInterface: TOKEN_2022_PROGRAM_ID,
165
- associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
166
- systemProgram: SystemProgram.programId,
167
- rent: SYSVAR_RENT_PUBKEY,
168
- globalConfig
169
- }).instruction();
170
- }
171
- }
172
-
173
9
  var address$7 = "5nBtmutQLrRKBUxNfHJPDjiW5u8id6QM9Hhjg1D1g1XH";
174
10
  var metadata$7 = {
175
11
  name: "liqsol_core",
@@ -14958,7 +14794,253 @@ function ceilDiv(n, d) {
14958
14794
  }
14959
14795
  return n.add(d.subn(1)).div(d);
14960
14796
  }
14797
+ function normalizeToBigInt(x) {
14798
+ if (typeof x === "bigint") return x;
14799
+ if (x != null && typeof x === "object" && "toString" in x) return BigInt(x.toString());
14800
+ if (typeof x === "number") return BigInt(x);
14801
+ throw new Error(`normalizeToBigInt: unsupported type ${typeof x}`);
14802
+ }
14961
14803
 
14804
+ let ConvertClient$1 = class ConvertClient {
14805
+ constructor(provider, pgs) {
14806
+ this.provider = provider;
14807
+ this.pgs = pgs;
14808
+ this.program = pgs.getProgram("liqsolCore");
14809
+ }
14810
+ get connection() {
14811
+ return this.provider.connection;
14812
+ }
14813
+ get wallet() {
14814
+ return this.provider.wallet;
14815
+ }
14816
+ async buildDepositTx(amount, user = this.wallet.publicKey) {
14817
+ if (!user) throw new Error("ConvertClient.buildDepositTx: wallet not connected");
14818
+ if (!amount || amount <= BigInt(0))
14819
+ throw new Error("ConvertClient.buildDepositTx: amount must be greater than zero.");
14820
+ const depositAuthority = this.pgs.deriveDepositAuthorityPda();
14821
+ const liqsolMint = this.pgs.deriveLiqsolMintPda();
14822
+ const liqsolMintAuthority = this.pgs.deriveLiqsolMintAuthorityPda();
14823
+ const reservePool = this.pgs.deriveReservePoolPda();
14824
+ const vault = this.pgs.deriveVaultPda();
14825
+ const controllerState = this.pgs.deriveStakeControllerStatePda();
14826
+ const payoutState = this.pgs.derivePayoutStatePda();
14827
+ const bucketAuthority = this.pgs.deriveBucketAuthorityPda();
14828
+ const payRateHistory = this.pgs.derivePayRateHistoryPda();
14829
+ const globalConfig = this.pgs.deriveGlobalConfigPda();
14830
+ const userAta = getAssociatedTokenAddressSync(liqsolMint, user, true, TOKEN_2022_PROGRAM_ID);
14831
+ const distributionState = this.pgs.deriveDistributionStatePda();
14832
+ const userRecord = this.pgs.deriveUserRecordPda(userAta);
14833
+ const bucketTokenAccount = getAssociatedTokenAddressSync(
14834
+ liqsolMint,
14835
+ bucketAuthority,
14836
+ true,
14837
+ TOKEN_2022_PROGRAM_ID
14838
+ );
14839
+ const seed = Math.floor(Math.random() * 2 ** 32);
14840
+ const ephemeralStake = await this.pgs.deriveEphemeralStakeAddress(user, seed);
14841
+ return await this.program.methods.deposit(new BN(amount.toString()), seed).accounts({
14842
+ user,
14843
+ depositAuthority,
14844
+ systemProgram: SystemProgram.programId,
14845
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
14846
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
14847
+ liqsolProgram: this.pgs.PROGRAM_IDS.LIQSOL_TOKEN,
14848
+ stakeProgram: StakeProgram.programId,
14849
+ liqsolMint,
14850
+ userAta,
14851
+ liqsolMintAuthority,
14852
+ reservePool,
14853
+ vault,
14854
+ ephemeralStake,
14855
+ controllerState,
14856
+ payoutState,
14857
+ bucketAuthority,
14858
+ bucketTokenAccount,
14859
+ userRecord,
14860
+ distributionState,
14861
+ payRateHistory,
14862
+ instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,
14863
+ clock: SYSVAR_CLOCK_PUBKEY,
14864
+ stakeHistory: SYSVAR_STAKE_HISTORY_PUBKEY,
14865
+ rent: SYSVAR_RENT_PUBKEY,
14866
+ globalConfig
14867
+ }).instruction();
14868
+ }
14869
+ async buildWithdrawTx(amount, user = this.wallet.publicKey) {
14870
+ if (!user) throw new Error("ConvertClient.buildWithdrawTx: wallet not connected");
14871
+ if (!amount || amount <= BigInt(0))
14872
+ throw new Error("ConvertClient.buildWithdrawTx: amount must be greater than zero.");
14873
+ const liqsolMint = this.pgs.deriveLiqsolMintPda();
14874
+ const userAta = getAssociatedTokenAddressSync(liqsolMint, user, true, TOKEN_2022_PROGRAM_ID);
14875
+ const userRecord = this.pgs.deriveUserRecordPda(userAta);
14876
+ const distributionState = this.pgs.deriveDistributionStatePda();
14877
+ const global = this.pgs.deriveWithdrawGlobalPda();
14878
+ const reservePool = this.pgs.deriveReservePoolPda();
14879
+ const stakeAllocationState = this.pgs.deriveStakeAllocationStatePda();
14880
+ const stakeMetrics = this.pgs.deriveStakeMetricsPda();
14881
+ const maintenanceLedger = this.pgs.deriveMaintenanceLedgerPda();
14882
+ const globalConfig = this.pgs.deriveGlobalConfigPda();
14883
+ const globalAcct = await this.program.account.global.fetch(global);
14884
+ const rawId = globalAcct.nextReceiptId;
14885
+ const receiptId = normalizeToBigInt(rawId);
14886
+ const mintAuthority = this.pgs.deriveWithdrawMintAuthorityPda();
14887
+ const metadata = this.pgs.deriveWithdrawMintMetadataPda();
14888
+ const nftMint = this.pgs.deriveWithdrawNftMintPda(receiptId);
14889
+ const receiptData = this.pgs.deriveLiqReceiptDataPda(nftMint);
14890
+ const owner = user;
14891
+ const nftAta = getAssociatedTokenAddressSync(nftMint, owner, true, TOKEN_2022_PROGRAM_ID);
14892
+ const bucketAuthority = this.pgs.deriveBucketAuthorityPda();
14893
+ const bucketTokenAccount = getAssociatedTokenAddressSync(
14894
+ liqsolMint,
14895
+ bucketAuthority,
14896
+ true,
14897
+ TOKEN_2022_PROGRAM_ID
14898
+ );
14899
+ return await this.program.methods.requestWithdraw(new BN(amount.toString())).accounts({
14900
+ user,
14901
+ owner,
14902
+ global,
14903
+ liqsolMint,
14904
+ userAta,
14905
+ userRecord,
14906
+ reservePool,
14907
+ stakeAllocationState,
14908
+ stakeMetrics,
14909
+ maintenanceLedger,
14910
+ clock: SYSVAR_CLOCK_PUBKEY,
14911
+ mintAuthority,
14912
+ receiptData,
14913
+ metadata,
14914
+ nftMint,
14915
+ nftAta,
14916
+ distributionState,
14917
+ bucketTokenAccount,
14918
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
14919
+ tokenInterface: TOKEN_2022_PROGRAM_ID,
14920
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
14921
+ systemProgram: SystemProgram.programId,
14922
+ rent: SYSVAR_RENT_PUBKEY,
14923
+ globalConfig
14924
+ }).instruction();
14925
+ }
14926
+ async fetchWithdrawReceipts(owner) {
14927
+ const globalPda = this.pgs.deriveWithdrawGlobalPda();
14928
+ const globalAcct = await this.program.account.global.fetch(globalPda);
14929
+ const nextId = normalizeToBigInt(globalAcct.nextReceiptId);
14930
+ const mintToId = new Map();
14931
+ for (let i = BigInt(0); i < nextId; i++) {
14932
+ const mint = this.pgs.deriveWithdrawNftMintPda(i);
14933
+ mintToId.set(mint.toBase58(), i);
14934
+ }
14935
+ const tokenAccounts = await this.connection.getParsedTokenAccountsByOwner(owner, {
14936
+ programId: TOKEN_2022_PROGRAM_ID
14937
+ });
14938
+ const receipts = [];
14939
+ for (const { pubkey, account } of tokenAccounts.value) {
14940
+ const info = account.data?.["parsed"]?.info;
14941
+ if (!info) continue;
14942
+ const amount = info.tokenAmount;
14943
+ const decimals = Number(amount?.decimals ?? 0);
14944
+ const uiAmount = Number(amount?.uiAmount ?? 0);
14945
+ if (decimals !== 0 || uiAmount !== 1) continue;
14946
+ const mintStr = info.mint;
14947
+ if (!mintStr) continue;
14948
+ const receiptId = mintToId.get(mintStr);
14949
+ if (receiptId === void 0) continue;
14950
+ const mintKey = new PublicKey(mintStr);
14951
+ const receiptDataPda = this.pgs.deriveLiqReceiptDataPda(mintKey);
14952
+ let receiptData;
14953
+ try {
14954
+ const raw = await this.program.account.liqReceiptData.fetch(receiptDataPda);
14955
+ receiptData = {
14956
+ receiptId: normalizeToBigInt(raw.receiptId),
14957
+ liqports: normalizeToBigInt(raw.liqports),
14958
+ epoch: normalizeToBigInt(raw.epoch),
14959
+ fulfilled: Boolean(raw.fulfilled)
14960
+ };
14961
+ } catch (err) {
14962
+ console.warn(`ConvertClient: failed to fetch receipt data for mint ${mintStr}`, err);
14963
+ continue;
14964
+ }
14965
+ const { etaMs, readyAtMs } = await this.estimateEpochEta(receiptData.epoch);
14966
+ const status = receiptData.fulfilled ? "claimed" : etaMs <= 0 ? "ready" : "queued";
14967
+ const amountView = {
14968
+ amount: receiptData.liqports,
14969
+ decimals: 9,
14970
+ symbol: "SOL"
14971
+ };
14972
+ receipts.push({
14973
+ tokenId: receiptData.receiptId,
14974
+ receipt: {
14975
+ amount: amountView,
14976
+ readyAt: readyAtMs,
14977
+ chain: "SOL",
14978
+ epoch: receiptData.epoch,
14979
+ status,
14980
+ mint: mintKey.toBase58(),
14981
+ ownerAta: pubkey.toBase58()
14982
+ }
14983
+ });
14984
+ }
14985
+ return receipts;
14986
+ }
14987
+ async buildClaimWithdrawTx(receiptId, user) {
14988
+ const mintAccount = this.pgs.deriveWithdrawNftMintPda(receiptId);
14989
+ const receiptData = this.pgs.deriveLiqReceiptDataPda(mintAccount);
14990
+ const ownerAta = getAssociatedTokenAddressSync(
14991
+ mintAccount,
14992
+ user,
14993
+ true,
14994
+ TOKEN_2022_PROGRAM_ID
14995
+ );
14996
+ const accounts = {
14997
+ user,
14998
+ global: this.pgs.deriveWithdrawGlobalPda(),
14999
+ mintAuthority: this.pgs.deriveWithdrawMintAuthorityPda(),
15000
+ receiptData,
15001
+ mintAccount,
15002
+ ownerAta,
15003
+ reservePool: this.pgs.deriveReservePoolPda(),
15004
+ vault: this.pgs.deriveVaultPda(),
15005
+ clock: SYSVAR_CLOCK_PUBKEY,
15006
+ stakeHistory: SYSVAR_STAKE_HISTORY_PUBKEY,
15007
+ globalConfig: this.pgs.deriveGlobalConfigPda(),
15008
+ tokenProgram: TOKEN_2022_PROGRAM_ID,
15009
+ stakeProgram: StakeProgram.programId,
15010
+ systemProgram: SystemProgram.programId,
15011
+ associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID
15012
+ };
15013
+ return this.program.methods.claimWithdraw().accounts(accounts).instruction();
15014
+ }
15015
+ async estimateEpochEta(targetEpoch) {
15016
+ const conn = this.connection;
15017
+ const epochInfo = await conn.getEpochInfo();
15018
+ const schedule = await conn.getEpochSchedule();
15019
+ const currentEpoch = BigInt(epochInfo.epoch);
15020
+ if (targetEpoch <= currentEpoch) {
15021
+ const now = Date.now();
15022
+ return { etaMs: 0, readyAtMs: now };
15023
+ }
15024
+ let slotTimeSec = 0.4;
15025
+ try {
15026
+ const samples = await conn.getRecentPerformanceSamples(1);
15027
+ if (samples?.length) {
15028
+ const s = samples[0];
15029
+ slotTimeSec = s.numSlots > 0 ? s.samplePeriodSecs / s.numSlots : slotTimeSec;
15030
+ }
15031
+ } catch (_) {
15032
+ }
15033
+ const slotsPerEpoch = BigInt(schedule.slotsPerEpoch);
15034
+ const slotsRemainingInCurrent = slotsPerEpoch - BigInt(epochInfo.slotIndex);
15035
+ const epochsRemaining = targetEpoch - currentEpoch - BigInt(1);
15036
+ const slotsRemaining = (epochsRemaining > 0 ? epochsRemaining * slotsPerEpoch : BigInt(0)) + slotsRemainingInCurrent;
15037
+ const etaSeconds = Number(slotsRemaining) * slotTimeSec;
15038
+ const etaMs = Math.max(0, Math.round(etaSeconds * 1e3));
15039
+ return { etaMs, readyAtMs: Date.now() + etaMs };
15040
+ }
15041
+ };
15042
+
15043
+ const INDEX_SCALE_BN = new BN("1000000000000");
14962
15044
  class DistributionClient {
14963
15045
  constructor(provider, pgs) {
14964
15046
  this.provider = provider;
@@ -14968,6 +15050,14 @@ class DistributionClient {
14968
15050
  get connection() {
14969
15051
  return this.provider.connection;
14970
15052
  }
15053
+ async getTokenBalance(ata) {
15054
+ try {
15055
+ const bal = await this.connection.getTokenAccountBalance(ata);
15056
+ return new BN(bal.value.amount);
15057
+ } catch {
15058
+ return new BN(0);
15059
+ }
15060
+ }
14971
15061
  async getDistributionState() {
14972
15062
  const pda = this.pgs.deriveDistributionStatePda();
14973
15063
  try {
@@ -15035,6 +15125,81 @@ class DistributionClient {
15035
15125
  }
15036
15126
  return { shares: userShares, totalShares, ratio };
15037
15127
  }
15128
+ async getClaimableLiqsol(user) {
15129
+ const liqsolMint = this.pgs.deriveLiqsolMintPda();
15130
+ const bucketAuthority = this.pgs.deriveBucketAuthorityPda();
15131
+ const userAta = getAssociatedTokenAddressSync(
15132
+ liqsolMint,
15133
+ user,
15134
+ true,
15135
+ TOKEN_2022_PROGRAM_ID
15136
+ );
15137
+ const bucketTokenAccount = getAssociatedTokenAddressSync(
15138
+ liqsolMint,
15139
+ bucketAuthority,
15140
+ true,
15141
+ TOKEN_2022_PROGRAM_ID
15142
+ );
15143
+ const [distributionState, userRecord, actualBalance, bucketBalance] = await Promise.all([
15144
+ this.getDistributionState(),
15145
+ this.getUserRecord(user),
15146
+ this.getTokenBalance(userAta),
15147
+ this.getTokenBalance(bucketTokenAccount)
15148
+ ]);
15149
+ if (!distributionState || !userRecord) {
15150
+ return new BN(0);
15151
+ }
15152
+ let syncedIndex = new BN(distributionState.currentIndex.toString());
15153
+ const totalShares = new BN(distributionState.totalShares.toString());
15154
+ const lastBucketBalance = new BN(distributionState.lastBucketBalance.toString());
15155
+ if (totalShares.gt(new BN(0)) && bucketBalance.gt(lastBucketBalance)) {
15156
+ const delta = bucketBalance.sub(lastBucketBalance);
15157
+ const indexDelta = delta.mul(INDEX_SCALE_BN).div(totalShares);
15158
+ if (indexDelta.gt(new BN(0))) {
15159
+ syncedIndex = syncedIndex.add(indexDelta);
15160
+ }
15161
+ }
15162
+ const shares = new BN(userRecord.shares.toString());
15163
+ const entitled = shares.mul(syncedIndex).div(INDEX_SCALE_BN);
15164
+ if (entitled.lte(actualBalance)) {
15165
+ return new BN(0);
15166
+ }
15167
+ return entitled.sub(actualBalance);
15168
+ }
15169
+ async buildClaimRewardsIx(user) {
15170
+ const liqsolMint = this.pgs.deriveLiqsolMintPda();
15171
+ const distributionState = this.pgs.deriveDistributionStatePda();
15172
+ const bucketAuthority = this.pgs.deriveBucketAuthorityPda();
15173
+ const userAta = getAssociatedTokenAddressSync(
15174
+ liqsolMint,
15175
+ user,
15176
+ true,
15177
+ TOKEN_2022_PROGRAM_ID
15178
+ );
15179
+ const bucketTokenAccount = getAssociatedTokenAddressSync(
15180
+ liqsolMint,
15181
+ bucketAuthority,
15182
+ true,
15183
+ TOKEN_2022_PROGRAM_ID
15184
+ );
15185
+ const userRecord = this.pgs.deriveUserRecordPda(userAta);
15186
+ const bucketUserRecord = this.pgs.deriveUserRecordPda(bucketTokenAccount);
15187
+ const extraAccountMetaList = this.pgs.deriveExtraAccountMetaListPda(liqsolMint);
15188
+ return this.program.methods.claimRewards().accounts({
15189
+ user,
15190
+ userAta,
15191
+ userRecord,
15192
+ bucketUserRecord,
15193
+ distributionState,
15194
+ extraAccountMetaList,
15195
+ liqsolCoreProgram: this.pgs.PROGRAM_IDS.LIQSOL_CORE,
15196
+ transferHookProgram: this.pgs.PROGRAM_IDS.TRANSFER_HOOK,
15197
+ liqsolMint,
15198
+ bucketAuthority,
15199
+ bucketTokenAccount,
15200
+ tokenProgram: TOKEN_2022_PROGRAM_ID
15201
+ }).instruction();
15202
+ }
15038
15203
  async getAverageScaledPayRate(windowSize = 5) {
15039
15204
  const history = await this.getPayRateHistory();
15040
15205
  if (!history) {
@@ -15729,7 +15894,7 @@ const _SolanaStakingClient = class _SolanaStakingClient {
15729
15894
  commitment
15730
15895
  });
15731
15896
  this.program = new SolanaProgramService(this.anchor, config.network.chainId);
15732
- this.depositClient = new DepositClient(this.anchor, this.program);
15897
+ this.convertClient = new ConvertClient$1(this.anchor, this.program);
15733
15898
  this.distributionClient = new DistributionClient(this.anchor, this.program);
15734
15899
  this.leaderboardClient = new LeaderboardClient(this.anchor, this.program);
15735
15900
  this.outpostClient = new OutpostClient(this.anchor, this.program);
@@ -15756,7 +15921,7 @@ const _SolanaStakingClient = class _SolanaStakingClient {
15756
15921
  if (amountLamports <= BigInt(0))
15757
15922
  throw new Error("Deposit amount must be greater than zero.");
15758
15923
  try {
15759
- const ix = await this.depositClient.buildDepositTx(amountLamports, this.squadsVaultPDA);
15924
+ const ix = await this.convertClient.buildDepositTx(amountLamports, this.squadsVaultPDA);
15760
15925
  return !!this.squadsX ? await this.sendSquadsIxs(ix) : await this.buildAndSendIx(ix);
15761
15926
  } catch (err) {
15762
15927
  console.log(`Failed to deposit Solana: ${err}`);
@@ -15768,13 +15933,40 @@ const _SolanaStakingClient = class _SolanaStakingClient {
15768
15933
  if (amountLamports <= BigInt(0))
15769
15934
  throw new Error("Withdraw amount must be greater than zero.");
15770
15935
  try {
15771
- const ix = await this.depositClient.buildWithdrawTx(amountLamports, this.squadsVaultPDA);
15936
+ const ix = await this.convertClient.buildWithdrawTx(amountLamports, this.squadsVaultPDA);
15772
15937
  return !!this.squadsX ? await this.sendSquadsIxs(ix) : await this.buildAndSendIx(ix);
15773
15938
  } catch (err) {
15774
15939
  console.log(`Failed to withdraw Solana: ${err}`);
15775
15940
  throw err;
15776
15941
  }
15777
15942
  }
15943
+ async getPendingWithdraws() {
15944
+ this.ensureUser();
15945
+ const owner = this.squadsVaultPDA ?? this.anchor.wallet.publicKey;
15946
+ return await this.convertClient.fetchWithdrawReceipts(owner);
15947
+ }
15948
+ async claimWithdraw(tokenId) {
15949
+ this.ensureUser();
15950
+ const owner = this.squadsVaultPDA ?? this.anchor.wallet.publicKey;
15951
+ try {
15952
+ const ix = await this.convertClient.buildClaimWithdrawTx(tokenId, owner);
15953
+ return !!this.squadsX ? await this.sendSquadsIxs(ix) : await this.buildAndSendIx(ix);
15954
+ } catch (err) {
15955
+ console.log(`Failed to claim withdraw on Solana: ${err}`);
15956
+ throw err;
15957
+ }
15958
+ }
15959
+ async claimLiqsolRewards() {
15960
+ this.ensureUser();
15961
+ const owner = this.squadsVaultPDA ?? this.anchor.wallet.publicKey;
15962
+ try {
15963
+ const ix = await this.distributionClient.buildClaimRewardsIx(owner);
15964
+ return !!this.squadsX ? await this.sendSquadsIxs(ix) : await this.buildAndSendIx(ix);
15965
+ } catch (err) {
15966
+ console.log(`Failed to claim liqSOL rewards on Solana: ${err}`);
15967
+ throw err;
15968
+ }
15969
+ }
15778
15970
  async stake(amountLamports) {
15779
15971
  this.ensureUser();
15780
15972
  if (!amountLamports || amountLamports <= BigInt(0))
@@ -15824,10 +16016,11 @@ const _SolanaStakingClient = class _SolanaStakingClient {
15824
16016
  TOKEN_2022_PROGRAM_ID,
15825
16017
  ASSOCIATED_TOKEN_PROGRAM_ID
15826
16018
  );
15827
- const [nativeLamports, actualBalResp, snapshot] = await Promise.all([
16019
+ const [nativeLamports, actualBalResp, snapshot, claimableLamports] = await Promise.all([
15828
16020
  this.connection.getBalance(user, "confirmed"),
15829
16021
  this.connection.getTokenAccountBalance(userLiqsolAta, "confirmed").catch(() => null),
15830
- this.outpostClient.fetchWireState(user).catch(() => null)
16022
+ this.outpostClient.fetchWireState(user).catch(() => null),
16023
+ this.distributionClient.getClaimableLiqsol(user).catch(() => new BN(0))
15831
16024
  ]);
15832
16025
  const LIQSOL_DECIMALS = 9;
15833
16026
  const actualAmountStr = actualBalResp?.value?.amount ?? "0";
@@ -15864,6 +16057,12 @@ const _SolanaStakingClient = class _SolanaStakingClient {
15864
16057
  decimals: LIQSOL_DECIMALS,
15865
16058
  ata: userLiqsolAta
15866
16059
  },
16060
+ claimable: {
16061
+ amount: BigInt(claimableLamports.toString()),
16062
+ symbol: "LiqSOL",
16063
+ decimals: LIQSOL_DECIMALS,
16064
+ ata: userLiqsolAta
16065
+ },
15867
16066
  staked: {
15868
16067
  amount: stakedLiqsol,
15869
16068
  symbol: "LiqSOL",
@@ -41289,47 +41488,25 @@ class ReceiptClient {
41289
41488
  }
41290
41489
  return results;
41291
41490
  }
41292
- async getOwnedReceiptNFTsFor(owner, fromBlock = 0, toBlock = "latest") {
41293
- const receiptContract = this.contract.ReceiptNFT;
41294
- const toLogs = await receiptContract.queryFilter(
41295
- receiptContract.filters.Transfer(null, owner),
41296
- fromBlock,
41297
- toBlock
41298
- );
41299
- const fromLogs = await receiptContract.queryFilter(
41300
- receiptContract.filters.Transfer(owner, null),
41301
- fromBlock,
41302
- toBlock
41303
- );
41304
- const owned = new Set();
41305
- for (const e of toLogs) {
41306
- const tokenId = e.args?.tokenId;
41307
- if (!tokenId) continue;
41308
- owned.add(tokenId.toString());
41309
- }
41310
- for (const e of fromLogs) {
41311
- const tokenId = e.args?.tokenId;
41312
- if (!tokenId) continue;
41313
- owned.delete(tokenId.toString());
41314
- }
41315
- return Array.from(owned).map((id) => BigNumber.from(id));
41316
- }
41317
41491
  async fetchWithdrawReceipts(address) {
41318
41492
  const tokenIds = await this.getOwnedWithdrawReceiptsFor(address);
41319
41493
  const results = [];
41320
41494
  for (const idBN of tokenIds) {
41321
41495
  try {
41322
41496
  const receiptData = await this.contract.WithdrawalQueue.info(idBN);
41497
+ const readyAtMs = Number(receiptData.readyAt) * 1e3;
41498
+ const status = readyAtMs <= Date.now() ? "ready" : "queued";
41323
41499
  results.push({
41324
41500
  tokenId: idBN.toBigInt(),
41325
41501
  receipt: {
41326
- ethAmount: receiptData.ethAmount,
41327
- ethBalance: {
41502
+ amount: {
41328
41503
  amount: receiptData.ethAmount.toBigInt(),
41329
41504
  decimals: 18,
41330
41505
  symbol: "ETH"
41331
41506
  },
41332
- readyAt: new Date(Number(receiptData.readyAt.toString()) * 1e3).valueOf()
41507
+ readyAt: readyAtMs,
41508
+ chain: "ETH",
41509
+ status
41333
41510
  }
41334
41511
  });
41335
41512
  } catch (err) {
@@ -41364,6 +41541,31 @@ class ReceiptClient {
41364
41541
  }
41365
41542
  return Array.from(owned).map((id) => BigNumber.from(id));
41366
41543
  }
41544
+ async getOwnedReceiptNFTsFor(owner, fromBlock = 0, toBlock = "latest") {
41545
+ const receiptContract = this.contract.ReceiptNFT;
41546
+ const toLogs = await receiptContract.queryFilter(
41547
+ receiptContract.filters.Transfer(null, owner),
41548
+ fromBlock,
41549
+ toBlock
41550
+ );
41551
+ const fromLogs = await receiptContract.queryFilter(
41552
+ receiptContract.filters.Transfer(owner, null),
41553
+ fromBlock,
41554
+ toBlock
41555
+ );
41556
+ const owned = new Set();
41557
+ for (const e of toLogs) {
41558
+ const tokenId = e.args?.tokenId;
41559
+ if (!tokenId) continue;
41560
+ owned.add(tokenId.toString());
41561
+ }
41562
+ for (const e of fromLogs) {
41563
+ const tokenId = e.args?.tokenId;
41564
+ if (!tokenId) continue;
41565
+ owned.delete(tokenId.toString());
41566
+ }
41567
+ return Array.from(owned).map((id) => BigNumber.from(id));
41568
+ }
41367
41569
  }
41368
41570
 
41369
41571
  class ValidatorClient {
@@ -41434,6 +41636,9 @@ class EthereumStakingClient {
41434
41636
  get network() {
41435
41637
  return this.config.network;
41436
41638
  }
41639
+ get address() {
41640
+ return this.signer?.getAddress();
41641
+ }
41437
41642
  async deposit(amount) {
41438
41643
  this.ensureUser();
41439
41644
  const amountWei = BigNumber.isBigNumber(amount) ? amount : BigNumber.from(amount);
@@ -41442,14 +41647,14 @@ class EthereumStakingClient {
41442
41647
  }
41443
41648
  async withdraw(amount) {
41444
41649
  this.ensureUser();
41445
- const address = await this.signer.getAddress();
41650
+ const address = await this.address;
41446
41651
  const amountWei = BigNumber.from(amount);
41447
41652
  const result = await this.convertClient.performWithdraw(address, amountWei);
41448
41653
  return result.txHash;
41449
41654
  }
41450
- async loadPendingWithdraws() {
41655
+ async getPendingWithdraws() {
41451
41656
  this.ensureUser();
41452
- const address = await this.signer.getAddress();
41657
+ const address = await this.address;
41453
41658
  return await this.receiptClient.fetchWithdrawReceipts(address);
41454
41659
  }
41455
41660
  async claimWithdraw(tokenId) {
@@ -41460,7 +41665,7 @@ class EthereumStakingClient {
41460
41665
  }
41461
41666
  async stake(amount) {
41462
41667
  this.ensureUser();
41463
- const walletAddress = await this.signer.getAddress();
41668
+ const walletAddress = await this.address;
41464
41669
  const amountWei = BigNumber.from(amount);
41465
41670
  const result = await this.stakeClient.performStake(amountWei, walletAddress);
41466
41671
  return result.txHash;
@@ -41476,7 +41681,7 @@ class EthereumStakingClient {
41476
41681
  }
41477
41682
  async buy(amount) {
41478
41683
  this.ensureUser();
41479
- const buyer = await this.signer.getAddress();
41684
+ const buyer = await this.address;
41480
41685
  let result = await this.pretokenClient.purchasePretokensWithLiqETH(amount, buyer);
41481
41686
  return result && result.txHash ? result.txHash : "Error - no resulting txHash";
41482
41687
  }
@@ -41488,7 +41693,7 @@ class EthereumStakingClient {
41488
41693
  async getPortfolio() {
41489
41694
  try {
41490
41695
  if (!this.signer) return Promise.resolve(null);
41491
- const walletAddress = await this.signer.getAddress();
41696
+ const walletAddress = await this.address;
41492
41697
  const nativeBalance = await this.provider.getBalance(walletAddress);
41493
41698
  const nativeDecimals = this.network?.nativeCurrency?.decimals ?? 18;
41494
41699
  const nativeSymbol = this.network?.nativeCurrency?.symbol ?? "ETH";
@@ -41566,12 +41771,12 @@ class EthereumStakingClient {
41566
41771
  }
41567
41772
  async fetchPrelaunchReceipts(address) {
41568
41773
  this.ensureUser();
41569
- if (address === void 0) address = await this.signer.getAddress();
41774
+ if (address === void 0) address = await this.address;
41570
41775
  return await this.receiptClient.stakeReceipts(address);
41571
41776
  }
41572
41777
  async getOPPMessages(address) {
41573
41778
  this.ensureUser();
41574
- if (!address) address = await this.signer.getAddress();
41779
+ if (!address) address = await this.address;
41575
41780
  return await this.oppClient.getMessages(address);
41576
41781
  }
41577
41782
  ensureUser() {
@@ -41646,7 +41851,7 @@ class EthereumStakingClient {
41646
41851
  }
41647
41852
  async getDepositBuffer(options) {
41648
41853
  this.ensureUser();
41649
- const walletAddress = await this.signer.getAddress();
41854
+ const walletAddress = await this.address;
41650
41855
  const baseGas = await this.provider.estimateGas({
41651
41856
  from: walletAddress,
41652
41857
  to: walletAddress,
@@ -41741,13 +41946,13 @@ const CONTRACT_NAMES = [
41741
41946
  ];
41742
41947
 
41743
41948
  var types$1 = /*#__PURE__*/Object.freeze({
41744
- __proto__: null,
41745
- CONTRACT_NAMES: CONTRACT_NAMES
41949
+ __proto__: null,
41950
+ CONTRACT_NAMES: CONTRACT_NAMES
41746
41951
  });
41747
41952
 
41748
41953
  var types = /*#__PURE__*/Object.freeze({
41749
- __proto__: null
41954
+ __proto__: null
41750
41955
  });
41751
41956
 
41752
- export { ADDRESSES, ADDRESS_BOOK_BY_CHAIN, CHAINLINK_FEED, CHAINLINK_PROGRAM, CONTRACTS_BY_CHAIN, DEFAULT_AVERAGE_PAY_RATE, DEFAULT_PAY_RATE_LOOKBACK, DepositClient, DistributionClient, EPHEMERAL_RENT_EXEMPTION, ERC1155Abi, ERC20Abi, ERC721Abi, types$1 as ETH, EthereumContractService, EthereumStakingClient, HOODI_ADDRESSES, INDEX_SCALE$1 as INDEX_SCALE, INITIAL_TRANCHE_SUPPLY, LAMPORTS_PER_SOL, LeaderboardClient, MAINNET_ADDRESSES, OutpostClient, PAY_RATE_SCALE_FACTOR, PDA_SEEDS, PROGRAM_IDS_BY_CHAIN, PurchaseAsset, ReceiptNFTKind, SCALE, types as SOL, SolanaStakingClient, Staker, SupportedEvmChainID, SupportedSolChainID, TokenClient, airdropSol, buildOutpostAccounts, buildSolanaTrancheLadder, buildSolanaTrancheSnapshot, ceilDiv, deriveEphemeralStakeAddress, generateRandomDepositAmount, generateTestKeypair, getEpochSnapshot, getErrorMessage, getProgramIds, lamportsToSol, msToEpochEnd, scheduledInstruction, sleep, solToLamports, toBigint, tokensToShares, waitForConfirmation, waitUntilSafeToExecuteFunction };
41957
+ export { ADDRESSES, ADDRESS_BOOK_BY_CHAIN, CHAINLINK_FEED, CHAINLINK_PROGRAM, CONTRACTS_BY_CHAIN, ConvertClient$1 as ConvertClient, DEFAULT_AVERAGE_PAY_RATE, DEFAULT_PAY_RATE_LOOKBACK, DistributionClient, EPHEMERAL_RENT_EXEMPTION, ERC1155Abi, ERC20Abi, ERC721Abi, types$1 as ETH, EthereumContractService, EthereumStakingClient, HOODI_ADDRESSES, INDEX_SCALE$1 as INDEX_SCALE, INITIAL_TRANCHE_SUPPLY, LAMPORTS_PER_SOL, LeaderboardClient, MAINNET_ADDRESSES, OutpostClient, PAY_RATE_SCALE_FACTOR, PDA_SEEDS, PROGRAM_IDS_BY_CHAIN, PurchaseAsset, ReceiptNFTKind, SCALE, types as SOL, SolanaStakingClient, Staker, SupportedEvmChainID, SupportedSolChainID, TokenClient, airdropSol, buildOutpostAccounts, buildSolanaTrancheLadder, buildSolanaTrancheSnapshot, ceilDiv, deriveEphemeralStakeAddress, generateRandomDepositAmount, generateTestKeypair, getEpochSnapshot, getErrorMessage, getProgramIds, lamportsToSol, msToEpochEnd, normalizeToBigInt, scheduledInstruction, sleep, solToLamports, toBigint, tokensToShares, waitForConfirmation, waitUntilSafeToExecuteFunction };
41753
41958
  //# sourceMappingURL=stake.browser.js.map