@wireio/stake 0.4.2 → 0.4.3

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.
@@ -5,7 +5,7 @@
5
5
  * IDL can be found at `target/idl/liqsol_token.json`.
6
6
  */
7
7
  export type LiqsolToken = {
8
- "address": "6hiJ8PrSyYLr7H9MA9VYh9fvGoHxZ2TXdDAMzjeUVSXZ",
8
+ "address": "5MRFSLCkXPEzfR6gkcZCVttq9g83mMUHyTZ85Z3TSpvU",
9
9
  "metadata": {
10
10
  "name": "liqsolToken",
11
11
  "version": "0.1.0",
@@ -5,7 +5,7 @@
5
5
  * IDL can be found at `target/idl/transfer_hook.json`.
6
6
  */
7
7
  export type TransferHook = {
8
- "address": "EtqCLddkPNGjkgiH9rVUmK3M5X2FKFprQvgscBJ8g6hX",
8
+ "address": "HbBpH9opFW9gcYVanHLweKuHhWQ8P3Kcc1mbpAx1vojz",
9
9
  "metadata": {
10
10
  "name": "transferHook",
11
11
  "version": "0.1.0",
@@ -129,6 +129,11 @@ export type TransferHook = {
129
129
  {
130
130
  "code": 6002,
131
131
  "name": "tlvAccountResolutionError"
132
+ },
133
+ {
134
+ "code": 6003,
135
+ "name": "cannotTransferToBucket",
136
+ "msg": "Cannot transfer liqSOL directly to bucket - only protocol minting is allowed"
132
137
  }
133
138
  ],
134
139
  "types": [
@@ -5,7 +5,7 @@
5
5
  * IDL can be found at `target/idl/validator_leaderboard.json`.
6
6
  */
7
7
  export type ValidatorLeaderboard = {
8
- "address": "H6CWj2PgxCE9Z5dPi9nMrR2VxT1C4DQcqR1QjmLeon47",
8
+ "address": "5v7mWL1735qp2Th9B5WNf7spGynR5ZaxwyCYoQw13DP2",
9
9
  "metadata": {
10
10
  "name": "validatorLeaderboard",
11
11
  "version": "0.1.0",
@@ -124,6 +124,9 @@ export type ValidatorLeaderboard = {
124
124
  },
125
125
  {
126
126
  "name": "systemProgram"
127
+ },
128
+ {
129
+ "name": "clock"
127
130
  }
128
131
  ],
129
132
  "args": [
@@ -174,10 +174,48 @@ export class EthereumStakingClient implements IStakingClient {
174
174
  for (let r of stakeReceipts) {
175
175
  stakeBalanceBN = stakeBalanceBN.add(BigNumber.from(r.receipt.principal.amount));
176
176
  }
177
+ let stakeSharesBN = BigNumber.from(0);
178
+ for (let r of stakeReceipts) {
179
+ stakeSharesBN = stakeSharesBN.add(BigNumber.from(r.receipt.shares.amount));
180
+ }
177
181
 
178
182
  // 4) WIRE pretoken balance
179
183
  const wireBalance: ethers.BigNumber = await this.contract.Pretoken.balanceOf(walletAddress);
180
184
 
185
+
186
+ // 5) Calculate staking yield
187
+ let currentIndex = BigInt(0);
188
+ let totalShares = BigInt(0);
189
+ let userShares = BigInt(0);
190
+ const indexScale = BigInt(1e27);
191
+ try {
192
+ // These may throw if not implemented on contract
193
+ const [indexBn, totalSharesBn] = await Promise.all([
194
+ this.contract.Depositor.index().catch(() => BigNumber.from(0)),
195
+ this.contract.Depositor.totalShares().catch(() => BigNumber.from(0)),
196
+ ]);
197
+
198
+ const userSharesBn = stakeSharesBN;
199
+ currentIndex = BigInt(indexBn.toString());
200
+ totalShares = BigInt(totalSharesBn.toString());
201
+ userShares = BigInt(userSharesBn.toString());
202
+ } catch {}
203
+
204
+ // sharesToTokens(userShares, currentIndex) = userShares * currentIndex / indexScale
205
+ let estimatedClaim = BigInt(0);
206
+ let estimatedYield = BigInt(0);
207
+
208
+ // started work on estimating the user's personal APY - not necessary at the moment
209
+ // let estimatedAPY: number | null = null;
210
+ // if (userShares > BigInt(0) && currentIndex > BigInt(0)) {
211
+ // estimatedClaim = (userShares * currentIndex) / indexScale;
212
+ // if (estimatedClaim > stakeBalanceBN.toBigInt()) {
213
+ // estimatedYield = estimatedClaim - stakeBalanceBN.toBigInt();
214
+ // }
215
+
216
+ // estimatedAPY = null;
217
+ // }
218
+
181
219
  const portfolio: Portfolio = {
182
220
  native: {
183
221
  amount: nativeBalance.toBigInt(),
@@ -199,6 +237,15 @@ export class EthereumStakingClient implements IStakingClient {
199
237
  decimals: 18,
200
238
  symbol: '$WIRE',
201
239
  },
240
+
241
+ yield: {
242
+ currentIndex,
243
+ indexScale,
244
+ totalShares,
245
+ userShares,
246
+ estimatedClaim,
247
+ estimatedYield,
248
+ },
202
249
  chainID: this.network.chainId
203
250
  }
204
251
  return portfolio;
@@ -241,15 +288,15 @@ export class EthereumStakingClient implements IStakingClient {
241
288
  // ---------------------------------------------------------------------
242
289
 
243
290
  // Estimated total APY for staking yeild
244
- getSystemAPY(): Promise<number> {
245
- // TODO
246
- return Promise.resolve(0);
291
+ async getSystemAPY(): Promise<number> {
292
+ const annualBpsBn = await this.contract.DepositManager.dailyRateBPS();
293
+ return annualBpsBn.toNumber() / 10000; // 0.04 for 4%
247
294
  }
248
295
 
249
296
  // Protocol fee charged for deposit from Native to LIQ
250
- getDepositFee(amount: bigint): Promise<bigint> {
251
- // TODO
252
- return Promise.resolve(BigInt(0));
297
+ async getDepositFee(amountWei: bigint): Promise<bigint> {
298
+ const feeBn: BigNumber = await this.contract.DepositManager.procFee(amountWei);
299
+ return BigInt(feeBn.toString());
253
300
  }
254
301
 
255
302
  async getOPPStatus(): Promise<any> {
@@ -40,6 +40,7 @@ import {
40
40
  deriveWithdrawMintMetadataPda,
41
41
  deriveWithdrawNftMintPda,
42
42
  deriveLiqReceiptDataPda,
43
+ deriveGlobalConfigPda,
43
44
  } from '../constants';
44
45
  import { WalletLike } from '../types';
45
46
 
@@ -86,6 +87,7 @@ export class DepositClient {
86
87
  const payoutState = derivePayoutStatePda();
87
88
  const bucketAuthority = deriveBucketAuthorityPda();
88
89
  const payRateHistory = derivePayRateHistoryPda();
90
+ const globalConfig = deriveGlobalConfigPda();
89
91
 
90
92
  // -------------------------------------------------------------
91
93
  // Token-2022 ATAs
@@ -129,27 +131,24 @@ export class DepositClient {
129
131
  associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
130
132
  liqsolProgram: PROGRAM_IDS.LIQSOL_TOKEN,
131
133
  stakeProgram: StakeProgram.programId,
132
-
133
134
  liqsolMint,
134
135
  userAta,
135
136
  liqsolMintAuthority,
136
137
  reservePool,
137
138
  vault,
138
139
  ephemeralStake,
139
-
140
140
  controllerState,
141
141
  payoutState,
142
142
  bucketAuthority,
143
143
  bucketTokenAccount,
144
-
145
144
  userRecord,
146
145
  distributionState,
147
146
  payRateHistory,
148
-
149
147
  instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,
150
148
  clock: SYSVAR_CLOCK_PUBKEY,
151
149
  stakeHistory: SYSVAR_STAKE_HISTORY_PUBKEY,
152
150
  rent: SYSVAR_RENT_PUBKEY,
151
+ globalConfig
153
152
  })
154
153
  .instruction();
155
154
 
@@ -203,6 +202,7 @@ export class DepositClient {
203
202
  const stakeAllocationState = deriveStakeAllocationStatePda();
204
203
  const stakeMetrics = deriveStakeMetricsPda();
205
204
  const maintenanceLedger = deriveMaintenanceLedgerPda();
205
+ const globalConfig = deriveGlobalConfigPda();
206
206
 
207
207
  // -------------------------------------------------------------
208
208
  // Need nextReceiptId from withdraw global state
@@ -265,6 +265,7 @@ export class DepositClient {
265
265
  associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
266
266
  systemProgram: SystemProgram.programId,
267
267
  rent: SYSVAR_RENT_PUBKEY,
268
+ globalConfig
268
269
  })
269
270
  .instruction();
270
271
 
@@ -36,6 +36,9 @@ export const {
36
36
  */
37
37
 
38
38
  export const PDA_SEEDS = {
39
+ // GLOBAL CONFIG
40
+ GLOBAL_CONFIG: 'global_config',
41
+
39
42
  // liqsol_core: deposit / stake controller
40
43
  DEPOSIT_AUTHORITY: 'deposit_authority',
41
44
  VAULT: 'vault',
@@ -86,8 +89,19 @@ export const PDA_SEEDS = {
86
89
  MINT_METADATA: 'mint_metadata',
87
90
  LIQ_RECEIPT_DATA: 'liq_receipt_data',
88
91
  WITHDRAW_MINT: 'mint',
92
+
93
+
94
+
89
95
  } as const;
90
96
 
97
+ // Global Config PDA
98
+ export const deriveGlobalConfigPda = () =>
99
+ PublicKey.findProgramAddressSync(
100
+ [Buffer.from(PDA_SEEDS.GLOBAL_CONFIG)],
101
+ LIQSOL_CORE,
102
+ )[0];
103
+
104
+
91
105
  /**
92
106
  * ---------------------------------------------------------------------------
93
107
  * CORE / DISTRIBUTION / DEPOSIT PDAS
@@ -246,11 +246,14 @@ export class SolanaStakingClient implements IStakingClient {
246
246
 
247
247
  const user = this.solPubKey;
248
248
 
249
+ // Build compute budget increase instruction
250
+ const cuIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 });
251
+
249
252
  // Build the Outpost synd instruction
250
253
  const ix = await this.outpostClient.buildStakeIx(amountLamports, user);
251
254
 
252
255
  // Wrap in a transaction and send
253
- const tx = new Transaction().add(ix);
256
+ const tx = new Transaction().add(cuIx, ix);
254
257
  const prepared = await this.prepareTx(tx);
255
258
  const signed = await this.signTransaction(prepared.tx);
256
259
 
@@ -269,11 +272,14 @@ export class SolanaStakingClient implements IStakingClient {
269
272
 
270
273
  const user = this.solPubKey;
271
274
 
275
+ // Build compute budget increase instruction
276
+ const cuIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 });
277
+
272
278
  // Build the Outpost desynd instruction
273
279
  const ix = await this.outpostClient.buildUnstakeIx(amountLamports, user);
274
280
 
275
281
  // Wrap in a transaction and send
276
- const tx = new Transaction().add(ix);
282
+ const tx = new Transaction().add(cuIx, ix);
277
283
  const prepared = await this.prepareTx(tx);
278
284
  const signed = await this.signTransaction(prepared.tx);
279
285
 
@@ -376,7 +382,7 @@ export class SolanaStakingClient implements IStakingClient {
376
382
  // - totalShares: globalState.totalShares
377
383
  // - userShares: outpostAccount.stakedShares
378
384
  // - estimatedClaimLiqsol: floor(userShares * index / INDEX_SCALE)
379
- // - estimatedYieldLiqsol: max(0, estimatedClaim - stakedLiqsol)
385
+ // - estimatedYield: max(0, estimatedClaim - stakedLiqsol)
380
386
  //
381
387
  // This matches the capital-staking math:
382
388
  // sharesToTokens(shares, index) = shares * index / INDEX_SCALE
@@ -392,15 +398,15 @@ export class SolanaStakingClient implements IStakingClient {
392
398
  const totalShares = BigInt(totalSharesStr);
393
399
  const userShares = BigInt(userSharesStr);
394
400
 
395
- let estimatedClaimLiqsol = BigInt(0);
396
- let estimatedYieldLiqsol = BigInt(0);
401
+ let estimatedClaim = BigInt(0);
402
+ let estimatedYield = BigInt(0);
397
403
 
398
404
  if (userShares > BigInt(0) && currentIndex > BigInt(0)) {
399
405
  // sharesToTokens(userShares, currentIndex)
400
- estimatedClaimLiqsol = (userShares * currentIndex) / INDEX_SCALE;
406
+ estimatedClaim = (userShares * currentIndex) / INDEX_SCALE;
401
407
 
402
- if (estimatedClaimLiqsol > stakedLiqsol) {
403
- estimatedYieldLiqsol = estimatedClaimLiqsol - stakedLiqsol;
408
+ if (estimatedClaim > stakedLiqsol) {
409
+ estimatedYield = estimatedClaim - stakedLiqsol;
404
410
  }
405
411
  }
406
412
 
@@ -435,8 +441,8 @@ export class SolanaStakingClient implements IStakingClient {
435
441
  totalShares,
436
442
  userShares,
437
443
  // liqSOL amounts (lamports) implied by index/shares
438
- estimatedClaimLiqsol,
439
- estimatedYieldLiqsol,
444
+ estimatedClaim,
445
+ estimatedYield,
440
446
  },
441
447
  extras: {
442
448
  userLiqsolAta: userLiqsolAta.toBase58(),
@@ -462,7 +468,7 @@ export class SolanaStakingClient implements IStakingClient {
462
468
  return this.distributionClient.getUserRecord(this.solPubKey);
463
469
  }
464
470
 
465
-
471
+
466
472
  // ---------------------------------------------------------------------
467
473
  // READ-ONLY Public Methods
468
474
  // ---------------------------------------------------------------------
@@ -475,8 +481,9 @@ export class SolanaStakingClient implements IStakingClient {
475
481
 
476
482
  // Protocol fee charged for deposit from Native to LIQ
477
483
  getDepositFee(amount: bigint): Promise<bigint> {
478
- // TODO
479
- return Promise.resolve(BigInt(0));
484
+ // Returning 1% for now,
485
+ // TODO: fetch real fee from on-chain config
486
+ return Promise.resolve((amount * BigInt(1)) / BigInt(100));
480
487
  }
481
488
 
482
489
  /**
package/src/types.ts CHANGED
@@ -41,6 +41,12 @@ export interface IStakingClient {
41
41
  windowBefore?: number;
42
42
  windowAfter?: number;
43
43
  }): Promise<TrancheSnapshot | null>;
44
+
45
+ // Estimated total APY for staking yeild
46
+ getSystemAPY(): Promise<number>;
47
+
48
+ // Protocol fee charged for deposit from Native to LIQ
49
+ getDepositFee(amount: bigint): Promise<bigint>;
44
50
  }
45
51
 
46
52
  /**
@@ -112,9 +118,9 @@ export interface BalanceView {
112
118
  }
113
119
 
114
120
  /**
115
- * SOL / Outpost yield view.
121
+ * Outpost yield view.
116
122
  *
117
- * All amounts are integers in base units (lamports for liqSOL).
123
+ * All amounts are integers in base units (lamports for liqSOL, wei for liqETH).
118
124
  *
119
125
  * Math matches capital-staking:
120
126
  * INDEX_SCALE = 1e12
@@ -141,20 +147,20 @@ export interface YieldView {
141
147
  userShares: bigint;
142
148
 
143
149
  /**
144
- * Total liqSOL (lamports) the user could claim right now if they fully
150
+ * Total liq (wei/lamports) the user could claim right now if they fully
145
151
  * unwound their stake:
146
- * estimatedClaimLiqsol = userShares * currentIndex / indexScale
152
+ * estimatedClaim = userShares * currentIndex / indexScale
147
153
  */
148
- estimatedClaimLiqsol: bigint;
154
+ estimatedClaim?: bigint;
149
155
 
150
156
  /**
151
- * Portion of estimatedClaimLiqsol that is “yield” above principal:
152
- * estimatedYieldLiqsol = max(0, estimatedClaimLiqsol - stakedLiqsol)
157
+ * Portion of estimatedClaim that is “yield” above principal:
158
+ * estimatedYield = max(0, estimatedClaim - staked)
153
159
  *
154
- * NOTE: stakedLiqsol principal itself is surfaced separately as
160
+ * NOTE: staked principal itself is surfaced separately as
155
161
  * Portfolio.staked.amount.
156
162
  */
157
- estimatedYieldLiqsol: bigint;
163
+ estimatedYield?: bigint;
158
164
  }
159
165
 
160
166
  export interface TrancheLadderItem {