@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/README.md +185 -243
- package/lib/stake.browser.js +343 -202
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.d.ts +104 -23
- package/lib/stake.js +511 -331
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +343 -202
- package/lib/stake.m.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +2 -2
- package/src/networks/ethereum/clients/receipt.client.ts +54 -69
- package/src/networks/ethereum/clients/validator.client.ts +61 -0
- package/src/networks/ethereum/ethereum.ts +21 -1
- package/src/networks/ethereum/types.ts +21 -17
- package/src/networks/solana/clients/convert.client.ts +339 -0
- package/src/networks/solana/solana.ts +35 -6
- package/src/networks/solana/types.ts +22 -0
- package/src/networks/solana/utils.ts +8 -1
- package/src/types.ts +40 -2
- package/src/networks/solana/clients/deposit.client.ts +0 -291
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wireio/stake",
|
|
3
|
-
"version": "2.
|
|
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.
|
|
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/
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
|
|
154
|
-
ethBalance: {
|
|
101
|
+
amount: {
|
|
155
102
|
amount: receiptData.ethAmount.toBigInt(),
|
|
156
103
|
decimals: 18,
|
|
157
|
-
symbol: "ETH"
|
|
104
|
+
symbol: "ETH",
|
|
158
105
|
},
|
|
159
|
-
readyAt:
|
|
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
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
export interface ValidatorDepositedEvent {
|
|
129
|
+
sender: string;
|
|
130
|
+
amount: BigNumber;
|
|
131
|
+
shares: BigNumber
|
|
132
|
+
}
|