@wireio/stake 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wireio/stake",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "description": "LIQ Staking Module for Wire Network",
5
5
  "homepage": "https://gitea.gitgo.app/Wire/sdk-stake",
6
6
  "license": "FSL-1.1-Apache-2.0",
@@ -64,7 +64,7 @@
64
64
  "@types/node": "^18.19.0",
65
65
  "@typescript-eslint/eslint-plugin": "^5.60.0",
66
66
  "@typescript-eslint/parser": "^5.60.0",
67
- "@wireio/core": "^0.3.0",
67
+ "@wireio/core": "^0.3.1",
68
68
  "assert": "^2.0.0",
69
69
  "chai": "^4.3.6",
70
70
  "esbuild": "^0.25.8",
package/src/index.ts CHANGED
@@ -13,8 +13,8 @@ export * as SOL from './networks/solana/types';
13
13
  export * from './networks/solana/utils';
14
14
 
15
15
  // CLIENTS
16
- export * from './networks/solana/clients/deposit.client';
16
+ export * from './networks/solana/clients/convert.client';
17
17
  export * from './networks/solana/clients/distribution.client';
18
18
  export * from './networks/solana/clients/leaderboard.client';
19
19
  export * from './networks/solana/clients/outpost.client';
20
- export * from './networks/solana/clients/token.client';
20
+ export * from './networks/solana/clients/token.client';
@@ -1,7 +1,7 @@
1
1
  import { BigNumber } from "ethers";
2
- import { preLaunchReceipt, WithdrawReceipt } from "../types";
2
+ import { preLaunchReceipt } from "../types";
3
+ import { WithdrawReceipt, ReceiptNFTKind } from "../../../types";
3
4
  import { EthereumContractService } from "../contract";
4
- import { ReceiptNFTKind } from "../../../types";
5
5
 
6
6
  export class ReceiptClient {
7
7
 
@@ -13,8 +13,7 @@ export class ReceiptClient {
13
13
  this.contractService = contract;
14
14
  }
15
15
 
16
-
17
-
16
+ // NOTE: Stake/pretoken receipts intentionally ignored for withdraw view.
18
17
  async allReceipts(address: string): Promise<preLaunchReceipt[]> {
19
18
  return this.fetchPreLaunchReceipts(address);
20
19
  }
@@ -23,9 +22,7 @@ export class ReceiptClient {
23
22
  try {
24
23
  const receipts = await this.fetchPreLaunchReceipts(address, ReceiptNFTKind.STAKE);
25
24
  return receipts;
26
- }
27
- catch (err) {
28
- // console.log('Error fetching stake receipts:', err);
25
+ } catch (err) {
29
26
  return [];
30
27
  }
31
28
  }
@@ -34,28 +31,20 @@ export class ReceiptClient {
34
31
  return this.fetchPreLaunchReceipts(address, ReceiptNFTKind.PRETOKEN_PURCHASE);
35
32
  }
36
33
 
37
-
38
-
39
34
  /**
40
- *
41
- * @param address (string) to fetch receipts for
42
- * @returns preLaunchReceipt[]
35
+ * Fetch ReceiptNFT data (stake/pretoken) for an address, optionally filtered by kind.
43
36
  */
44
37
  async fetchPreLaunchReceipts(address: string, type?: ReceiptNFTKind): Promise<preLaunchReceipt[]> {
45
38
  const receiptContract = this.contract.ReceiptNFT;
46
39
 
47
- // first figure out which tokenIds this address owns, from events
48
40
  const tokenIds = await this.getOwnedReceiptNFTsFor(address);
49
-
50
41
  const results: preLaunchReceipt[] = [];
51
42
 
52
- // next fetch on-chain receipt data just for those ids
53
43
  for (const idBN of tokenIds) {
54
44
  try {
55
45
  const receiptData = await receiptContract.getReceipt(idBN);
56
46
 
57
- //skip any receipt not of the requested type
58
- if(type !== undefined && receiptData.kind !== type) continue;
47
+ if (type !== undefined && receiptData.kind !== type) continue;
59
48
 
60
49
  results.push({
61
50
  tokenId: idBN.toBigInt(),
@@ -78,7 +67,6 @@ export class ReceiptClient {
78
67
  }
79
68
  });
80
69
  } catch (err) {
81
- // in case of any mismatch or race, just skip this id
82
70
  console.warn(`Failed to load receipt for tokenId=${idBN.toString()}`, err);
83
71
  continue;
84
72
  }
@@ -88,50 +76,6 @@ export class ReceiptClient {
88
76
  }
89
77
 
90
78
 
91
-
92
-
93
- private async getOwnedReceiptNFTsFor(
94
- owner: string,
95
- fromBlock = 0,
96
- toBlock: number | string = "latest"
97
- ): Promise<BigNumber[]> {
98
- const receiptContract = this.contract.ReceiptNFT;
99
-
100
- // Logs where address received tokens
101
- const toLogs = await receiptContract.queryFilter(
102
- receiptContract.filters.Transfer(null, owner),
103
- fromBlock,
104
- toBlock
105
- );
106
-
107
- // Logs where address sent tokens (including burns from owner → 0)
108
- const fromLogs = await receiptContract.queryFilter(
109
- receiptContract.filters.Transfer(owner, null),
110
- fromBlock,
111
- toBlock
112
- );
113
-
114
- const owned = new Set<string>();
115
-
116
- // Add all received tokenIds
117
- for (const e of toLogs) {
118
- const tokenId = e.args?.tokenId;
119
- if (!tokenId) continue;
120
- owned.add(tokenId.toString());
121
- }
122
-
123
- // Remove all sent tokenIds
124
- for (const e of fromLogs) {
125
- const tokenId = e.args?.tokenId;
126
- if (!tokenId) continue;
127
- owned.delete(tokenId.toString());
128
- }
129
-
130
- // Convert to BigNumbers
131
- return Array.from(owned).map((id) => BigNumber.from(id));
132
- }
133
-
134
-
135
79
  /**
136
80
  *
137
81
  * @param address (string) to fetch receipts for
@@ -147,16 +91,21 @@ export class ReceiptClient {
147
91
  try {
148
92
  const receiptData = await this.contract.WithdrawalQueue.info(idBN);
149
93
 
150
- results.push({
151
- tokenId: idBN.toBigInt(),
94
+ // status: ready if readyAt <= now; otherwise queued
95
+ const readyAtMs = Number(receiptData.readyAt) * 1000;
96
+ const status = readyAtMs <= Date.now() ? 'ready' : 'queued';
97
+
98
+ results.push({
99
+ tokenId: idBN.toBigInt(),
152
100
  receipt: {
153
- ethAmount: receiptData.ethAmount,
154
- ethBalance: {
101
+ amount: {
155
102
  amount: receiptData.ethAmount.toBigInt(),
156
103
  decimals: 18,
157
- symbol: "ETH"
104
+ symbol: "ETH",
158
105
  },
159
- readyAt: new Date(Number(receiptData.readyAt.toString()) * 1000).valueOf(),
106
+ readyAt: readyAtMs,
107
+ chain: 'ETH',
108
+ status,
160
109
  }
161
110
  });
162
111
  } catch (err) {
@@ -211,4 +160,40 @@ export class ReceiptClient {
211
160
  // Convert to BigNumbers
212
161
  return Array.from(owned).map((id) => BigNumber.from(id));
213
162
  }
214
- }
163
+
164
+ private async getOwnedReceiptNFTsFor(
165
+ owner: string,
166
+ fromBlock = 0,
167
+ toBlock: number | string = "latest"
168
+ ): Promise<BigNumber[]> {
169
+ const receiptContract = this.contract.ReceiptNFT;
170
+
171
+ const toLogs = await receiptContract.queryFilter(
172
+ receiptContract.filters.Transfer(null, owner),
173
+ fromBlock,
174
+ toBlock
175
+ );
176
+
177
+ const fromLogs = await receiptContract.queryFilter(
178
+ receiptContract.filters.Transfer(owner, null),
179
+ fromBlock,
180
+ toBlock
181
+ );
182
+
183
+ const owned = new Set<string>();
184
+
185
+ for (const e of toLogs) {
186
+ const tokenId = e.args?.tokenId;
187
+ if (!tokenId) continue;
188
+ owned.add(tokenId.toString());
189
+ }
190
+
191
+ for (const e of fromLogs) {
192
+ const tokenId = e.args?.tokenId;
193
+ if (!tokenId) continue;
194
+ owned.delete(tokenId.toString());
195
+ }
196
+
197
+ return Array.from(owned).map((id) => BigNumber.from(id));
198
+ }
199
+ }
@@ -0,0 +1,61 @@
1
+ import { BigNumber, ethers } from "ethers";
2
+ import { ClaimedEvent, DepositEvent, DepositResult, SharesBurnedEvent, ValidatorDepositedEvent } from "../types";
3
+ import { EthereumContractService } from "../contract";
4
+ import { formatContractErrors } from "../utils";
5
+
6
+ export class ValidatorClient {
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
+ /**
18
+ *
19
+ * @param amountWei an amount of liqETH (in WEI) to stake to the Outpost
20
+ * @returns txHash (hash of the transaction), receipt, Staked event
21
+ */
22
+ async validatorDepositAndLockBond(): Promise<any> {
23
+ const amountWei: BigNumber = ethers.utils.parseEther("32");
24
+
25
+ // simulate call first
26
+ try {
27
+ await this.contract.DepositManager.callStatic.validatorDepositAndLockBond({ value: amountWei });
28
+ } catch (err: any) {
29
+ let errorObj = formatContractErrors(err);
30
+ throw new Error(errorObj.name ?? errorObj.raw)
31
+ }
32
+
33
+
34
+ // send the tx to stake liqeth
35
+ const tx = await this.contract.DepositManager.validatorDepositAndLockBond({ value: amountWei });
36
+
37
+ // Wait for 1 confirmation
38
+ const receipt = await tx.wait(1);
39
+
40
+ // Parse ValidatorDeposited event if present
41
+ let staked: ValidatorDepositedEvent | undefined;
42
+ const ev = receipt.events?.find((e) => e.event === 'Staked');
43
+
44
+ if (ev && ev.args) {
45
+ const { sender, amount, shares } = ev.args;
46
+ staked = {
47
+ sender,
48
+ amount: BigNumber.from(amount),
49
+ shares: BigNumber.from(shares),
50
+ };
51
+ }
52
+
53
+ return {
54
+ txHash: tx.hash,
55
+ receipt,
56
+ staked,
57
+ };
58
+ }
59
+
60
+
61
+ }
@@ -15,6 +15,7 @@ import { StakeClient } from './clients/stake.client';
15
15
  import { PretokenClient } from './clients/pretoken.client';
16
16
  import { OPPClient } from './clients/opp.client';
17
17
  import { ReceiptClient } from './clients/receipt.client';
18
+ import { ValidatorClient } from './clients/validator.client';
18
19
 
19
20
  export const INITIAL_TRANCHE_SUPPLY = 35000;
20
21
 
@@ -29,6 +30,7 @@ export class EthereumStakingClient implements IStakingClient {
29
30
  private stakeClient: StakeClient;
30
31
  private oppClient: OPPClient;
31
32
  private receiptClient: ReceiptClient;
33
+ private validatorClient: ValidatorClient;
32
34
 
33
35
 
34
36
  get contract() { return this.contractService.contract; }
@@ -56,6 +58,7 @@ export class EthereumStakingClient implements IStakingClient {
56
58
  this.stakeClient = new StakeClient(this.contractService);
57
59
  this.oppClient = new OPPClient(this.contractService);
58
60
  this.receiptClient = new ReceiptClient(this.contractService);
61
+ this.validatorClient = new ValidatorClient(this.contractService)
59
62
  }
60
63
  catch (error) {
61
64
  // console.error('Error initializing EthereumStakingClient:', error);
@@ -104,7 +107,7 @@ export class EthereumStakingClient implements IStakingClient {
104
107
  * @param amount Amount in wei (or something convertible to BigNumber).
105
108
  * @returns transaction hash
106
109
  */
107
- async loadPendingWithdraws(): Promise<WithdrawReceipt[]> {
110
+ async getPendingWithdraws(): Promise<WithdrawReceipt[]> {
108
111
  this.ensureUser();
109
112
  const address = await this.signer!.getAddress();
110
113
 
@@ -178,6 +181,21 @@ export class EthereumStakingClient implements IStakingClient {
178
181
  }
179
182
 
180
183
 
184
+ /**
185
+ * Validator functions
186
+ */
187
+ async validatorDeposit(): Promise<string> {
188
+ this.ensureUser();
189
+
190
+ let result = await this.validatorClient.validatorDepositAndLockBond();
191
+ return result && result.txHash ? result.txHash : "Error - no resulting txHash";
192
+ }
193
+
194
+
195
+
196
+
197
+
198
+
181
199
  /**
182
200
  * Resolve the user's ETH + liqETH balances.
183
201
  *
@@ -310,6 +328,8 @@ export class EthereumStakingClient implements IStakingClient {
310
328
  return await this.oppClient.getMessages(address);
311
329
  }
312
330
 
331
+
332
+
313
333
  // Ensure that signer wallet is available for write operations
314
334
  private ensureUser() {
315
335
  if (!this.signer) {
@@ -1,5 +1,5 @@
1
1
  import { BigNumber, ethers } from 'ethers';
2
- import { BalanceView } from '../../types';
2
+ import { BalanceView, ChainSymbol, WithdrawReceipt as UnifiedWithdrawReceipt } from '../../types';
3
3
 
4
4
  export const CONTRACT_NAMES = [
5
5
  // LiqETH contracts
@@ -99,17 +99,20 @@ export interface SharesBurnedEvent {
99
99
  tokenValue: BigNumber;
100
100
  }
101
101
 
102
+ /**
103
+ * Legacy stake/pretoken receipt (kept for compatibility; not used in withdraw UI).
104
+ */
102
105
  export interface preLaunchReceipt {
103
106
  tokenId: bigint;
104
107
  receipt: {
105
- account: string,
106
- currency: number,
107
- kind: number,
108
- indexAtMint: BalanceView,
109
- principal: BalanceView,
110
- shares: BalanceView,
111
- timestamp: string,
112
- }
108
+ account: string;
109
+ currency: number;
110
+ kind: number;
111
+ indexAtMint: BalanceView;
112
+ principal: BalanceView;
113
+ shares: BalanceView;
114
+ timestamp: string;
115
+ };
113
116
  }
114
117
 
115
118
  export interface ClaimedEvent {
@@ -117,12 +120,13 @@ export interface ClaimedEvent {
117
120
  amount: BigNumber;
118
121
  }
119
122
 
123
+ // Unified withdraw receipt type is defined centrally in src/types.ts
124
+ export type WithdrawReceipt = UnifiedWithdrawReceipt;
120
125
 
121
- export interface WithdrawReceipt {
122
- tokenId: bigint;
123
- receipt: {
124
- ethAmount: BigNumber;
125
- ethBalance: BalanceView;
126
- readyAt: number;
127
- }
128
- }
126
+
127
+
128
+ export interface ValidatorDepositedEvent {
129
+ sender: string;
130
+ amount: BigNumber;
131
+ shares: BigNumber
132
+ }