@wireio/stake 0.4.0 → 0.4.2

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,27 +1,32 @@
1
1
  import { BigNumber, ethers } from 'ethers';
2
- import { IStakingClient, Portfolio, StakerConfig, TrancheSnapshot } from '../../types';
3
2
  import { ChainID, EvmChainID, PublicKey as WirePubKey } from '@wireio/core';
3
+ import {
4
+ IStakingClient,
5
+ OPPAssertion,
6
+ Portfolio,
7
+ StakerConfig,
8
+ TrancheSnapshot
9
+ } from '../../types';
4
10
  import { EthereumContractService } from './contract';
5
11
  import { preLaunchReceipt } from './types';
6
- import { DepositClient } from './clients/deposit.client';
12
+ import { buildEthereumTrancheSnapshot } from './utils';
13
+ import { ConvertClient } from './clients/convert.client';
7
14
  import { StakeClient } from './clients/stake.client';
8
15
  import { PretokenClient } from './clients/pretoken.client';
9
- import { buildEthereumTrancheSnapshot } from './utils';
10
- import { LiqClient } from './clients/liq.client';
11
-
12
-
13
-
16
+ import { OPPClient } from './clients/opp.client';
17
+ import { ReceiptClient } from './clients/receipt.client';
14
18
 
15
19
  export class EthereumStakingClient implements IStakingClient {
20
+ private readonly provider: ethers.providers.Web3Provider | ethers.providers.JsonRpcProvider;
16
21
  public readonly pubKey?: WirePubKey;
17
- private readonly provider: ethers.providers.Web3Provider;
18
- private readonly signer: ethers.Signer;
22
+ private readonly signer?: ethers.Signer;
19
23
  private readonly contractService: EthereumContractService;
20
24
 
21
- private depositClient: DepositClient;
22
- private liqClient: LiqClient;
25
+ private convertClient: ConvertClient;
23
26
  private pretokenClient: PretokenClient;
24
27
  private stakeClient: StakeClient;
28
+ private oppClient: OPPClient;
29
+ private receiptClient: ReceiptClient;
25
30
 
26
31
 
27
32
  get contract() { return this.contractService.contract; }
@@ -29,28 +34,32 @@ export class EthereumStakingClient implements IStakingClient {
29
34
 
30
35
  constructor(private config: StakerConfig) {
31
36
  try {
32
- this.provider = config.provider as ethers.providers.Web3Provider;
33
- this.signer = this.provider.getSigner();
37
+ if (config.provider) {
38
+ this.provider = config.provider as ethers.providers.Web3Provider;
39
+ this.signer = this.provider.getSigner();
40
+ }
41
+ else {
42
+ this.provider = new ethers.providers.JsonRpcProvider(config.network.rpcUrls[0]);
43
+ }
34
44
  this.pubKey = config.pubKey;
35
-
45
+
36
46
  this.contractService = new EthereumContractService({
37
47
  provider: this.provider,
38
48
  signer: this.signer,
39
49
  });
40
-
41
- this.depositClient = new DepositClient(this.contractService);
42
- this.liqClient = new LiqClient(this.contractService);
50
+
51
+ this.convertClient = new ConvertClient(this.contractService);
43
52
  this.pretokenClient = new PretokenClient(this.contractService);
44
53
  this.stakeClient = new StakeClient(this.contractService);
45
- }
54
+ this.oppClient = new OPPClient(this.contractService);
55
+ this.receiptClient = new ReceiptClient(this.contractService);
56
+ }
46
57
  catch (error) {
47
58
  // console.error('Error initializing EthereumStakingClient:', error);
48
59
  throw error;
49
- }
60
+ }
50
61
  }
51
62
 
52
-
53
-
54
63
  // ---------------------------------------------------------------------
55
64
  // Public IStakingClient Interface Methods
56
65
  // ---------------------------------------------------------------------
@@ -62,40 +71,41 @@ export class EthereumStakingClient implements IStakingClient {
62
71
  * @returns transaction hash
63
72
  */
64
73
  async deposit(amount: number | string | bigint | BigNumber): Promise<string> {
74
+ this.ensureUser();
75
+
65
76
  const amountWei = BigNumber.isBigNumber(amount)
66
77
  ? amount
67
78
  : BigNumber.from(amount);
68
79
 
69
- const result = await this.depositClient.performDeposit(amountWei);
80
+ const result = await this.convertClient.performDeposit(amountWei);
70
81
  return result.txHash;
71
82
  }
72
83
 
73
-
74
-
75
84
  /**
76
85
  * Withdraw native ETH from the liqETH protocol via the liqeth safeBurn function, which burns the LiqETH and adds the user to the withdrawal queue.
77
86
  * @param amount Amount in wei (or something convertible to BigNumber).
78
87
  * @returns transaction hash
79
88
  */
80
89
  async withdraw(amount: bigint): Promise<string> {
81
- const address = await this.signer.getAddress();
90
+ this.ensureUser();
91
+
92
+ const address = await this.signer!.getAddress();
82
93
  const amountWei = BigNumber.from(amount);
83
- // const chainId = this.network?.chainId ?? (await this.provider.getNetwork()).chainId;
84
- // const result = await this.depositClient.requestWithdraw(amountWei, this.signer, chainId);
85
94
 
86
- const result = await this.liqClient.safeBurn(address, amountWei)
95
+ const result = await this.convertClient.performWithdraw(address, amountWei)
87
96
  return result.txHash;
88
97
  }
89
98
 
90
99
 
91
100
  /**
92
101
  * Stake liqETH via DepositManager.
93
- * @param amount Amount in wei
94
- * Keep this as a bigint / string in the caller; avoid JS floats.
102
+ * @param amount Amount in wei - Keep this as a bigint / string in the caller; avoid JS floats.
95
103
  * @returns transaction hash
96
104
  */
97
105
  async stake(amount: bigint): Promise<string> {
98
- const walletAddress = await this.signer.getAddress();
106
+ this.ensureUser();
107
+
108
+ const walletAddress = await this.signer!.getAddress();
99
109
  const amountWei = BigNumber.from(amount);
100
110
 
101
111
  const result = await this.stakeClient.performStake(amountWei, walletAddress);
@@ -116,96 +126,27 @@ export class EthereumStakingClient implements IStakingClient {
116
126
  * @returns the transaction hash
117
127
  */
118
128
  async unstakePrelaunch(tokenId: bigint, recipient: string): Promise<string> {
129
+ this.ensureUser();
130
+
119
131
  const tokenIdBigNum = BigNumber.from(tokenId)
120
132
  const result = await this.stakeClient.performWithdrawStake(tokenIdBigNum, recipient);
121
133
  return result.txHash;
122
134
  }
123
135
 
124
136
 
125
-
126
137
  async buy(amount: bigint): Promise<string> {
127
- const buyer = await this.signer.getAddress();
128
- const amountBigNum = BigNumber.from(amount)
138
+ this.ensureUser();
139
+
140
+ const buyer = await this.signer!.getAddress();
129
141
 
130
142
  // ! Hoodi only - check if the mock aggregator price is stale, and if so, update it before submitting the buy request
131
143
  await this.updateMockAggregatorPrice();
132
-
133
-
134
- const bal = await this.contract.LiqEth.balanceOf(buyer);
135
- const paused = await this.contract.Depositor.paused();
136
- if(paused) {
137
- throw new Error("Error - Depositor is in a paused state");
138
- }
139
-
140
- // if current liq balance is less than the requested buy amount, throw an error
141
- if (bal.lt(amount)) {
142
- throw new Error(`Balance insufficient for pre-token purchase`);
143
- }
144
-
145
- //check that the contract has allowance for the token
146
- const depositorAddr = this.contract.Depositor.address;
147
- const allowance = await this.contract.LiqEth.allowance(buyer, depositorAddr);
148
-
149
- // if allowance is less than the requested stake amount, request permission to spend LiqEth
150
- if (allowance.lt(amount)) {
151
- const liqWrite = this.contractService.getWrite('LiqEth');
152
-
153
- // currently requested unlimited amount - potentially change to only request up to the current amount?
154
- const approveAmount = ethers.constants.MaxUint256;
155
-
156
- console.warn(`allowance insufficient (${allowance.toString()} < ${amount.toString()}); sending approve(${depositorAddr}, ${approveAmount.toString()})`);
157
-
158
- const approveTx = await liqWrite.approve(depositorAddr, approveAmount);
159
- await approveTx.wait(1);
160
-
161
- // re-read allowance to ensure approval succeeded
162
- const newAllowance = await this.contract.LiqEth.allowance(buyer, depositorAddr);
163
- if (newAllowance.lt(amount)) {
164
- throw new Error('Approval failed or allowance still insufficient after approve');
165
- }
166
- }
167
-
168
-
169
- let result = await this.pretokenClient.purchasePretokensWithLiqETH(amountBigNum, buyer);
170
144
 
145
+ let result = await this.pretokenClient.purchasePretokensWithLiqETH(amount, buyer);
171
146
  return result && result.txHash ? result.txHash : "Error - no resulting txHash";
172
147
  }
173
148
 
174
149
 
175
-
176
-
177
- async getOPPStatus(): Promise<any> {
178
- return await this.stakeClient.getOppStatus();
179
- }
180
-
181
-
182
-
183
- /**
184
- * ETH Prelaunch function to list the ReceiptNFTs owned by a specific user
185
- * @param address address to query the receipts for
186
- * @returns array of receipts
187
- */
188
- async fetchPrelaunchReceipts(address?: string): Promise<preLaunchReceipt[]> {
189
- if(address === undefined) address = await this.signer.getAddress();
190
-
191
- let receipts = await this.stakeClient.fetchPreLaunchReceipts(address);
192
- return receipts
193
- }
194
-
195
-
196
-
197
- async getEthStats(): Promise<any> {
198
- let withdrawDelay = await this.contract.DepositManager.withdrawDelay();
199
- let minDeposit = await this.contract.DepositManager.minDeposit();
200
- let rewardCooldown = await this.contract.DepositManager.rewardCooldown();
201
-
202
- return {
203
- withdrawDelay,
204
- minDeposit,
205
- rewardCooldown,
206
- }
207
- }
208
-
209
150
  /**
210
151
  * Resolve the user's ETH + liqETH balances.
211
152
  *
@@ -214,9 +155,9 @@ export class EthereumStakingClient implements IStakingClient {
214
155
  * tracked = liqETH tracked balance (protocol/accounting view)
215
156
  */
216
157
  async getPortfolio(): Promise<Portfolio> {
217
- const walletAddress = await this.signer.getAddress();
218
- // console.log('getPortfolio() wallet address', walletAddress)
158
+ this.ensureUser();
219
159
 
160
+ const walletAddress = await this.signer!.getAddress();
220
161
 
221
162
  // 1) Native ETH balance
222
163
  const nativeBalance = await this.provider.getBalance(walletAddress);
@@ -227,9 +168,15 @@ export class EthereumStakingClient implements IStakingClient {
227
168
  const liqBalance: ethers.BigNumber = await this.contract.LiqEth.balanceOf(walletAddress);
228
169
  const liqSymbol = 'Liq' + (this.network?.nativeCurrency?.symbol ?? 'ETH');
229
170
 
230
- // 3) staked liqEth ERC-20 balance (actual)
231
- const stakedLiqBalance = await this.contract.Depositor.sharesOf(walletAddress);
171
+ // 3) staked liqEth ERC-20 balance (calculate from receipts)
172
+ let stakeReceipts = await this.receiptClient.stakeReceipts(walletAddress);
173
+ let stakeBalanceBN = BigNumber.from(0);
174
+ for (let r of stakeReceipts) {
175
+ stakeBalanceBN = stakeBalanceBN.add(BigNumber.from(r.receipt.principal.amount));
176
+ }
232
177
 
178
+ // 4) WIRE pretoken balance
179
+ const wireBalance: ethers.BigNumber = await this.contract.Pretoken.balanceOf(walletAddress);
233
180
 
234
181
  const portfolio: Portfolio = {
235
182
  native: {
@@ -243,13 +190,13 @@ export class EthereumStakingClient implements IStakingClient {
243
190
  symbol: liqSymbol,
244
191
  },
245
192
  staked: {
246
- amount: stakedLiqBalance.toBigInt(),
193
+ amount: stakeBalanceBN.toBigInt(),
247
194
  decimals: nativeDecimals,
248
195
  symbol: liqSymbol,
249
196
  },
250
197
  wire: {
251
- amount: BigInt(0), // TODO
252
- decimals: 0,
198
+ amount: wireBalance.toBigInt(),
199
+ decimals: 18,
253
200
  symbol: '$WIRE',
254
201
  },
255
202
  chainID: this.network.chainId
@@ -257,9 +204,74 @@ export class EthereumStakingClient implements IStakingClient {
257
204
  return portfolio;
258
205
  }
259
206
 
207
+ /**
208
+ * ETH Prelaunch function to list the Stake ReceiptNFTs owned by a specific user
209
+ * @param address address to query the receipts for
210
+ * @returns array of receipts
211
+ */
212
+ async fetchPrelaunchReceipts(address?: string): Promise<preLaunchReceipt[]> {
213
+ this.ensureUser();
214
+
215
+ if (address === undefined) address = await this.signer!.getAddress();
216
+
217
+ //default to stake receipts
218
+ return await this.receiptClient.stakeReceipts(address);
219
+ }
220
+
221
+ async getOPPMessages(address?: string): Promise<OPPAssertion[]> {
222
+ this.ensureUser();
223
+
224
+ if (!address) address = await this.signer!.getAddress();
225
+
226
+ return await this.oppClient.getMessages(address);
227
+ }
228
+
229
+ // Ensure that signer wallet is available for write operations
230
+ private ensureUser() {
231
+ if (!this.signer) {
232
+ throw new Error(
233
+ 'EthereumStakingClient: write operation requires a wallet-connected Web3 provider',
234
+ );
235
+ }
236
+ }
237
+
238
+
239
+ // ---------------------------------------------------------------------
240
+ // READ-ONLY Public Methods
241
+ // ---------------------------------------------------------------------
242
+
243
+ // Estimated total APY for staking yeild
244
+ getSystemAPY(): Promise<number> {
245
+ // TODO
246
+ return Promise.resolve(0);
247
+ }
248
+
249
+ // Protocol fee charged for deposit from Native to LIQ
250
+ getDepositFee(amount: bigint): Promise<bigint> {
251
+ // TODO
252
+ return Promise.resolve(BigInt(0));
253
+ }
254
+
255
+ async getOPPStatus(): Promise<any> {
256
+ return await this.oppClient.getStatus();
257
+ }
258
+
259
+ async getEthStats(): Promise<any> {
260
+ let withdrawDelay = await this.contract.DepositManager.withdrawDelay();
261
+ let minDeposit = await this.contract.DepositManager.minDeposit();
262
+ let rewardCooldown = await this.contract.DepositManager.rewardCooldown();
263
+
264
+ return {
265
+ withdrawDelay,
266
+ minDeposit,
267
+ rewardCooldown,
268
+ }
269
+ }
260
270
 
261
271
  /**
262
272
  * Program-level prelaunch WIRE / tranche snapshot for Ethereum
273
+ *
274
+ * SUPPORTS READ-ONLY ACcESS
263
275
  */
264
276
  async getTrancheSnapshot(options?: {
265
277
  chainID?: ChainID;
@@ -296,25 +308,25 @@ export class EthereumStakingClient implements IStakingClient {
296
308
 
297
309
 
298
310
  // fetch price and timestamp from aggregator
299
- const [ roundId, answer, startedAt, updatedAt, answeredInRound ] = await this.contract.Aggregator.latestRoundData();
311
+ const [roundId, answer, startedAt, updatedAt, answeredInRound] = await this.contract.Aggregator.latestRoundData();
300
312
  let ethPriceUsd: bigint = BigInt(answer.toString());
301
313
  let nativePriceTimestamp: number = Number(updatedAt);
302
314
 
303
315
  // ! Placeholder from hoodi deployment - don't think this can be fetched dynamically
304
- const initialTrancheSupply = BigInt(60000) * BigInt(1e8);
316
+ const initialTrancheSupply = BigInt(60000) * BigInt(1e8);
305
317
 
306
318
  return buildEthereumTrancheSnapshot({
307
319
  chainID,
308
- totalSharesBn,
309
- indexBn,
320
+ totalSharesBn,
321
+ indexBn,
310
322
  trancheNumberBn,
311
- currentTrancheSupply,
312
- tranchePriceWadBn,
323
+ currentTrancheSupply,
324
+ tranchePriceWadBn,
313
325
  totalTrancheSupply,
314
326
  initialTrancheSupply,
315
327
  supplyGrowthBps,
316
328
  priceGrowthBps,
317
- minPriceUsd,
329
+ minPriceUsd,
318
330
  maxPriceUsd,
319
331
 
320
332
  ethPriceUsd,
@@ -324,16 +336,10 @@ export class EthereumStakingClient implements IStakingClient {
324
336
  });
325
337
  }
326
338
 
327
-
328
-
329
-
330
339
  // ---------------------------------------------------------------------
331
340
  // Internal ETH Staking client helper functions
332
341
  // ---------------------------------------------------------------------
333
342
 
334
-
335
-
336
-
337
343
  // ! This is a temporary measure for Hoodi testnet because there is no aggregator deployed
338
344
  private async updateMockAggregatorPrice() {
339
345
  const aggregator = this.contract.Aggregator;
@@ -349,7 +355,7 @@ export class EthereumStakingClient implements IStakingClient {
349
355
  // safety check - only run in non-production contexts
350
356
  const network = await this.provider.getNetwork();
351
357
  const chainId = network.chainId;
352
- const allowedTestChains = new Set([560048]);
358
+ const allowedTestChains = new Set([560048]);
353
359
  if (!allowedTestChains.has(chainId)) {
354
360
  console.warn(`MockAggregator is stale (${ageSec}s) but chainId ${chainId} is not a test/local network — skipping update.`);
355
361
  return;
@@ -380,10 +386,4 @@ export class EthereumStakingClient implements IStakingClient {
380
386
  console.log(`MockAggregator updated ${ageSec}s ago — no update needed`);
381
387
  }
382
388
  }
383
-
384
-
385
-
386
-
387
-
388
- // TODO: implement claimRewards, etc.
389
389
  }
@@ -20,6 +20,7 @@ export const CONTRACT_NAMES = [
20
20
  'Pretoken',
21
21
  'Aggregator',
22
22
  'EthUsdPriceConsumer',
23
+ 'Pool',
23
24
 
24
25
  ] as const;
25
26
 
@@ -193,7 +193,7 @@ export class SolanaStakingClient implements IStakingClient {
193
193
  * Handles tx build, sign, send, and confirmation.
194
194
  */
195
195
  async deposit(amountLamports: bigint): Promise<string> {
196
- this.ensureWriteAccess();
196
+ this.ensureUser();
197
197
  if (amountLamports <= BigInt(0)) {
198
198
  throw new Error('Deposit amount must be greater than zero.');
199
199
  }
@@ -219,7 +219,7 @@ export class SolanaStakingClient implements IStakingClient {
219
219
  * Actual SOL payout happens later via the operator-side flow.
220
220
  */
221
221
  async withdraw(amountLamports: bigint): Promise<string> {
222
- this.ensureWriteAccess();
222
+ this.ensureUser();
223
223
  if (amountLamports <= BigInt(0)) {
224
224
  throw new Error('Withdraw amount must be greater than zero.');
225
225
  }
@@ -238,7 +238,7 @@ export class SolanaStakingClient implements IStakingClient {
238
238
  * Stake liqSOL into Outpost (liqSOL → pool) via liqsol_core::synd.
239
239
  */
240
240
  async stake(amountLamports: bigint): Promise<string> {
241
- this.ensureWriteAccess();
241
+ this.ensureUser();
242
242
 
243
243
  if (!amountLamports || amountLamports <= BigInt(0)) {
244
244
  throw new Error('Stake amount must be greater than zero.');
@@ -261,7 +261,7 @@ export class SolanaStakingClient implements IStakingClient {
261
261
  * Unstake liqSOL from Outpost (pool → liqSOL) via liqsol_core::desynd.
262
262
  */
263
263
  async unstake(amountLamports: bigint): Promise<string> {
264
- this.ensureWriteAccess();
264
+ this.ensureUser();
265
265
 
266
266
  if (!amountLamports || amountLamports <= BigInt(0)) {
267
267
  throw new Error('Unstake amount must be greater than zero.');
@@ -287,7 +287,7 @@ export class SolanaStakingClient implements IStakingClient {
287
287
  * instruction under the new IDL (no more native-SOL purchase).
288
288
  */
289
289
  async buy(amountLamports: bigint): Promise<string> {
290
- this.ensureWriteAccess();
290
+ this.ensureUser();
291
291
  if (!amountLamports || amountLamports <= BigInt(0)) {
292
292
  throw new Error('liqSOL pretoken purchase requires a positive amount.');
293
293
  }
@@ -453,6 +453,32 @@ export class SolanaStakingClient implements IStakingClient {
453
453
  };
454
454
  }
455
455
 
456
+ /**
457
+ * Convenience helper to fetch the distribution userRecord for the current user.
458
+ * Used by balance-correction flows and debugging.
459
+ */
460
+ async getUserRecord() {
461
+ if (!this.pubKey) throw new Error('User pubKey is undefined');
462
+ return this.distributionClient.getUserRecord(this.solPubKey);
463
+ }
464
+
465
+
466
+ // ---------------------------------------------------------------------
467
+ // READ-ONLY Public Methods
468
+ // ---------------------------------------------------------------------
469
+
470
+ // Estimated total APY for staking yeild
471
+ getSystemAPY(): Promise<number> {
472
+ // TODO
473
+ return Promise.resolve(0);
474
+ }
475
+
476
+ // Protocol fee charged for deposit from Native to LIQ
477
+ getDepositFee(amount: bigint): Promise<bigint> {
478
+ // TODO
479
+ return Promise.resolve(BigInt(0));
480
+ }
481
+
456
482
  /**
457
483
  * Unified, chain-agnostic tranche snapshot for Solana.
458
484
  *
@@ -493,15 +519,6 @@ export class SolanaStakingClient implements IStakingClient {
493
519
  });
494
520
  }
495
521
 
496
- /**
497
- * Convenience helper to fetch the distribution userRecord for the current user.
498
- * Used by balance-correction flows and debugging.
499
- */
500
- async getUserRecord() {
501
- if (!this.pubKey) throw new Error('User pubKey is undefined');
502
- return this.distributionClient.getUserRecord(this.solPubKey);
503
- }
504
-
505
522
  // ---------------------------------------------------------------------
506
523
  // Tx helpers
507
524
  // ---------------------------------------------------------------------
@@ -514,7 +531,7 @@ export class SolanaStakingClient implements IStakingClient {
514
531
  signed: SolanaTransaction,
515
532
  ctx: { blockhash: string; lastValidBlockHeight: number },
516
533
  ): Promise<string> {
517
- this.ensureWriteAccess();
534
+ this.ensureUser();
518
535
 
519
536
  const signature = await this.connection.sendRawTransaction(
520
537
  signed.serialize(),
@@ -549,7 +566,7 @@ export class SolanaStakingClient implements IStakingClient {
549
566
  async signTransaction(
550
567
  tx: SolanaTransaction,
551
568
  ): Promise<SolanaTransaction> {
552
- this.ensureWriteAccess();
569
+ this.ensureUser();
553
570
  return this.anchor.wallet.signTransaction(tx);
554
571
  }
555
572
 
@@ -560,7 +577,7 @@ export class SolanaStakingClient implements IStakingClient {
560
577
  async sendTransaction(
561
578
  signed: SolanaTransaction,
562
579
  ): Promise<TransactionSignature> {
563
- this.ensureWriteAccess();
580
+ this.ensureUser();
564
581
  return this.anchor.sendAndConfirm(signed);
565
582
  }
566
583
 
@@ -586,7 +603,7 @@ export class SolanaStakingClient implements IStakingClient {
586
603
  * Guard for all write operations (deposit/withdraw/stake/unstake/buy).
587
604
  * Ensures we have a Wire pubKey and an Anchor wallet pubKey, and that they match.
588
605
  */
589
- ensureWriteAccess() {
606
+ ensureUser() {
590
607
  if (!this.pubKey || !this.anchor.wallet.publicKey) {
591
608
  throw new Error('User Authorization required: pubKey is undefined');
592
609
  }
package/src/types.ts CHANGED
@@ -5,7 +5,7 @@ import { ethers } from 'ethers';
5
5
 
6
6
  export type StakerConfig = {
7
7
  network: ExternalNetwork;
8
- provider: BaseSignerWalletAdapter | ethers.providers.Web3Provider;
8
+ provider?: BaseSignerWalletAdapter | ethers.providers.Web3Provider;
9
9
  pubKey?: PublicKey;
10
10
  }
11
11
 
@@ -23,6 +23,12 @@ export interface IStakingClient {
23
23
  /** Fetch the complete user portfolio */
24
24
  getPortfolio(): Promise<Portfolio>;
25
25
 
26
+ // Estimated total APY for staking yeild
27
+ getSystemAPY(): Promise<number>;
28
+
29
+ // Protocol fee charged for deposit from Native to LIQ
30
+ getDepositFee(amount: bigint): Promise<bigint>;
31
+
26
32
  /**
27
33
  * Program-level prelaunch WIRE/tranche snapshot for this chain.
28
34
  *
@@ -216,4 +222,57 @@ export interface TrancheSnapshot {
216
222
  * Used directly by the frontend for ladder graphs.
217
223
  */
218
224
  ladder: TrancheLadderItem[];
225
+ }
226
+
227
+
228
+ // Enum describing which asset is being used to buy pretoken
229
+ export enum PurchaseAsset {
230
+ SOL = 'SOL',
231
+ LIQSOL = 'LIQSOL',
232
+ ETH = 'ETH',
233
+ LIQETH = 'LIQETH',
234
+ YIELD = 'YIELD',
235
+ }
236
+
237
+ export interface PurchaseQuote {
238
+ purchaseAsset: PurchaseAsset;
239
+ amountIn: bigint; // lamports / wei / token units
240
+
241
+ /** Expected pretoken “shares” (pretokens) and decimals */
242
+ wireShares: bigint; // 1e8 scale
243
+ wireDecimals: number; // always 8 for now
244
+
245
+ /** Current price + notional in USD (1e8 scale) */
246
+ wirePriceUsd: bigint;
247
+ notionalUsd: bigint;
248
+ }
249
+
250
+ // export interface OPPEvent {
251
+ // type: 'liq_pretoken_purchase' | 'yield_pretoken_purchase' | 'pretoken_purchase' | 'stake' | 'unstake' | 'unknown';
252
+ // amount: bigint | null;
253
+ // chain: 'ETH' | 'SOL';
254
+ // timestamp: number | null;
255
+ // from: string | null;
256
+ // to: string | null;
257
+ // txHash: string;
258
+ // raw: any;
259
+ // assertions: OPPAssertion[]
260
+ // }
261
+
262
+ export interface OPPAssertion {
263
+ type: 'liq_pretoken_purchase' | 'yield_pretoken_purchase' | 'pretoken_purchase' | 'stake' | 'unstake' | 'bonded_actor' | 'unbonded_actor' | 'unknown',
264
+ data: any
265
+ chain: 'ETH' | 'SOL';
266
+ timestamp: number | null;
267
+ from: string | null;
268
+ to: string | null;
269
+ txHash: string;
270
+ raw: any;
271
+ }
272
+
273
+
274
+
275
+ export enum ReceiptNFTKind {
276
+ STAKE = 0,
277
+ PRETOKEN_PURCHASE = 1,
219
278
  }
@@ -1,47 +0,0 @@
1
- import { BigNumber, ethers } from "ethers";
2
- import { preLaunchReceipt, SharesBurnedEvent, StakedEvent, WithdrawnStakeEvent, WithdrawnStakeResult } from "../types";
3
- import { EthereumContractService } from "../contract";
4
- import { formatContractErrors } from "../utils";
5
-
6
- export class LiqClient {
7
-
8
- private readonly contractService: EthereumContractService;
9
-
10
- get contract() { return this.contractService.contract; }
11
-
12
- constructor(contract: EthereumContractService) {
13
- this.contractService = contract;
14
- }
15
-
16
-
17
- public async safeBurn(signerAddress: string, amountWei: BigNumber): Promise<any> {
18
- let tx, receipt;
19
- try {
20
- tx = await this.contract.LiqEth.safeBurn(signerAddress, amountWei);
21
- receipt = await tx.wait(1);
22
- } catch (err: any) {
23
- let errorObj = formatContractErrors(err);
24
- throw new Error(errorObj.name ?? errorObj.raw)
25
- }
26
-
27
- // Parse SharesBurned event if present
28
- let event: SharesBurnedEvent | undefined;
29
- const ev = receipt.events?.find((e) => e.event === 'SharesBurned');
30
-
31
- if (ev && ev.args) {
32
- const { from, shares, tokenValue } = ev.args;
33
- event = {
34
- from,
35
- shares: BigNumber.from(shares),
36
- tokenValue: BigNumber.from(tokenValue),
37
- };
38
- }
39
-
40
- return {
41
- txHash: tx.hash,
42
- receipt,
43
- event,
44
- };
45
- }
46
-
47
- }