@wireio/stake 1.0.0 → 1.1.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/lib/stake.browser.js +106 -96
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.js +106 -96
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +106 -96
- package/lib/stake.m.js.map +1 -1
- package/package.json +1 -1
- package/src/networks/ethereum/clients/opp.client.ts +20 -21
- package/src/networks/ethereum/clients/receipt.client.ts +8 -1
- package/src/networks/ethereum/ethereum.ts +95 -86
- package/src/networks/solana/solana.ts +29 -23
- package/src/staker.ts +1 -0
package/package.json
CHANGED
|
@@ -84,34 +84,33 @@ export class OPPClient {
|
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
87
|
/**
|
|
91
88
|
* Fetches all OPPMessage events and flattens all assertions into a single OPPAssertion[] array.
|
|
92
89
|
*/
|
|
93
90
|
async getMessages(address: string): Promise<OPPAssertion[]> {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
91
|
+
try {
|
|
92
|
+
const oppMessageFilter = this.contract.OPP.filters.OPPMessage();
|
|
93
|
+
const events = await this.contract.OPP.queryFilter(oppMessageFilter, 0, "latest");
|
|
94
|
+
const allAssertions: OPPAssertion[] = [];
|
|
95
|
+
for (const event of events) {
|
|
96
|
+
const assertions = await this.extractAssertionsFromEvent(event);
|
|
97
|
+
allAssertions.push(...assertions);
|
|
98
|
+
}
|
|
101
99
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
// ! Current implementation is not ideal - no current way to filter OPP Messages by a single user
|
|
101
|
+
const normalized = address ? address.toLowerCase() : null;
|
|
102
|
+
const filtered = allAssertions.filter(a =>
|
|
103
|
+
(a.from && a.from.toLowerCase() === normalized) ||
|
|
104
|
+
(a.to && a.to.toLowerCase() === normalized)
|
|
105
|
+
);
|
|
106
|
+
return filtered.reverse();
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
// console.log('Error fetching OPP messages:', error);
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
114
|
/**
|
|
116
115
|
* Extracts all OPPAssertions from a single OPPMessage event, attaching event metadata to each.
|
|
117
116
|
*/
|
|
@@ -20,7 +20,14 @@ export class ReceiptClient {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
async stakeReceipts(address: string): Promise<preLaunchReceipt[]> {
|
|
23
|
-
|
|
23
|
+
try {
|
|
24
|
+
const receipts = await this.fetchPreLaunchReceipts(address, ReceiptNFTKind.STAKE);
|
|
25
|
+
return receipts;
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
// console.log('Error fetching stake receipts:', err);
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
async pretokenReceipts(address: string): Promise<preLaunchReceipt[]> {
|
|
@@ -160,100 +160,109 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
160
160
|
* tracked = liqETH tracked balance (protocol/accounting view)
|
|
161
161
|
*/
|
|
162
162
|
async getPortfolio(): Promise<Portfolio | null> {
|
|
163
|
-
if (!this.signer) return Promise.resolve(null);
|
|
164
163
|
|
|
165
|
-
|
|
164
|
+
try {
|
|
165
|
+
if (!this.signer) return Promise.resolve(null);
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
const nativeBalance = await this.provider.getBalance(walletAddress);
|
|
169
|
-
const nativeDecimals = this.network?.nativeCurrency?.decimals ?? 18;
|
|
170
|
-
const nativeSymbol = this.network?.nativeCurrency?.symbol ?? 'ETH';
|
|
167
|
+
const walletAddress = await this.signer!.getAddress();
|
|
171
168
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
169
|
+
// 1) Native ETH balance
|
|
170
|
+
const nativeBalance = await this.provider.getBalance(walletAddress);
|
|
171
|
+
const nativeDecimals = this.network?.nativeCurrency?.decimals ?? 18;
|
|
172
|
+
const nativeSymbol = this.network?.nativeCurrency?.symbol ?? 'ETH';
|
|
175
173
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
for (let r of stakeReceipts) {
|
|
180
|
-
stakeBalanceBN = stakeBalanceBN.add(BigNumber.from(r.receipt.principal.amount));
|
|
181
|
-
}
|
|
182
|
-
let stakeSharesBN = BigNumber.from(0);
|
|
183
|
-
for (let r of stakeReceipts) {
|
|
184
|
-
stakeSharesBN = stakeSharesBN.add(BigNumber.from(r.receipt.shares.amount));
|
|
185
|
-
}
|
|
174
|
+
// 2) liqETH ERC-20 balance (actual)
|
|
175
|
+
const liqBalance: ethers.BigNumber = await this.contract.LiqEthToken.balanceOf(walletAddress);
|
|
176
|
+
const liqSymbol = 'Liq' + (this.network?.nativeCurrency?.symbol ?? 'ETH');
|
|
186
177
|
|
|
187
|
-
|
|
188
|
-
|
|
178
|
+
// 3) staked liqEth ERC-20 balance (calculate from receipts)
|
|
179
|
+
let stakeReceipts = await this.receiptClient.stakeReceipts(walletAddress);
|
|
189
180
|
|
|
181
|
+
let stakeBalanceBN = BigNumber.from(0);
|
|
182
|
+
for (let r of stakeReceipts) {
|
|
183
|
+
stakeBalanceBN = stakeBalanceBN.add(BigNumber.from(r.receipt.principal.amount));
|
|
184
|
+
}
|
|
185
|
+
let stakeSharesBN = BigNumber.from(0);
|
|
186
|
+
for (let r of stakeReceipts) {
|
|
187
|
+
stakeSharesBN = stakeSharesBN.add(BigNumber.from(r.receipt.shares.amount));
|
|
188
|
+
}
|
|
190
189
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
190
|
+
// 4) WIRE pretoken balance
|
|
191
|
+
const wireBalance: ethers.BigNumber = await this.contract.Pretoken.balanceOf(walletAddress);
|
|
192
|
+
|
|
193
|
+
// 5) Calculate staking yield
|
|
194
|
+
let currentIndex = BigInt(0);
|
|
195
|
+
let totalShares = BigInt(0);
|
|
196
|
+
let userShares = BigInt(0);
|
|
197
|
+
const indexScale = BigInt(1e27);
|
|
198
|
+
try {
|
|
199
|
+
// These may throw if not implemented on contract
|
|
200
|
+
const [indexBn, totalSharesBn] = await Promise.all([
|
|
201
|
+
this.contract.Depositor.index().catch(() => BigNumber.from(0)),
|
|
202
|
+
this.contract.Depositor.totalShares().catch(() => BigNumber.from(0)),
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
const userSharesBn = stakeSharesBN;
|
|
206
|
+
currentIndex = BigInt(indexBn.toString());
|
|
207
|
+
totalShares = BigInt(totalSharesBn.toString());
|
|
208
|
+
userShares = BigInt(userSharesBn.toString());
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.log('Error fetching staking index/shares:', error);
|
|
211
|
+
}
|
|
202
212
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
213
|
+
// sharesToTokens(userShares, currentIndex) = userShares * currentIndex / indexScale
|
|
214
|
+
let estimatedClaim = BigInt(0);
|
|
215
|
+
let estimatedYield = BigInt(0);
|
|
216
|
+
|
|
217
|
+
// started work on estimating the user's personal APY - not necessary at the moment
|
|
218
|
+
// let estimatedAPY: number | null = null;
|
|
219
|
+
// if (userShares > BigInt(0) && currentIndex > BigInt(0)) {
|
|
220
|
+
// estimatedClaim = (userShares * currentIndex) / indexScale;
|
|
221
|
+
// if (estimatedClaim > stakeBalanceBN.toBigInt()) {
|
|
222
|
+
// estimatedYield = estimatedClaim - stakeBalanceBN.toBigInt();
|
|
223
|
+
// }
|
|
224
|
+
|
|
225
|
+
// estimatedAPY = null;
|
|
226
|
+
// }
|
|
227
|
+
|
|
228
|
+
const portfolio: Portfolio = {
|
|
229
|
+
native: {
|
|
230
|
+
amount: nativeBalance.toBigInt(),
|
|
231
|
+
decimals: nativeDecimals,
|
|
232
|
+
symbol: nativeSymbol,
|
|
233
|
+
},
|
|
234
|
+
liq: {
|
|
235
|
+
amount: liqBalance.toBigInt(),
|
|
236
|
+
decimals: nativeDecimals,
|
|
237
|
+
symbol: liqSymbol,
|
|
238
|
+
},
|
|
239
|
+
staked: {
|
|
240
|
+
amount: stakeBalanceBN.toBigInt(),
|
|
241
|
+
decimals: nativeDecimals,
|
|
242
|
+
symbol: liqSymbol,
|
|
243
|
+
},
|
|
244
|
+
wire: {
|
|
245
|
+
amount: wireBalance.toBigInt(),
|
|
246
|
+
decimals: 18,
|
|
247
|
+
symbol: '$WIRE',
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
yield: {
|
|
251
|
+
currentIndex,
|
|
252
|
+
indexScale,
|
|
253
|
+
totalShares,
|
|
254
|
+
userShares,
|
|
255
|
+
estimatedClaim,
|
|
256
|
+
estimatedYield,
|
|
257
|
+
},
|
|
258
|
+
chainID: this.network.chainId
|
|
259
|
+
}
|
|
260
|
+
return portfolio;
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
// console.log('Error fetching Ethereum portfolio:', error);
|
|
264
|
+
throw error;
|
|
255
265
|
}
|
|
256
|
-
return portfolio;
|
|
257
266
|
}
|
|
258
267
|
|
|
259
268
|
/**
|
|
@@ -422,7 +431,7 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
422
431
|
txCount?: number;
|
|
423
432
|
safetyMultiplier?: number;
|
|
424
433
|
minBufferWei?: bigint;
|
|
425
|
-
balanceOverrideLamports?: bigint;
|
|
434
|
+
balanceOverrideLamports?: bigint;
|
|
426
435
|
}): Promise<bigint> {
|
|
427
436
|
this.ensureUser();
|
|
428
437
|
|
|
@@ -208,14 +208,18 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
try {
|
|
211
|
-
|
|
212
|
-
const {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
211
|
+
// Build compute budget increase instruction
|
|
212
|
+
const cuIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 });
|
|
213
|
+
|
|
214
|
+
// Build the Outpost synd instruction
|
|
215
|
+
const ix = await this.depositClient.buildDepositTx(amountLamports);
|
|
216
|
+
|
|
217
|
+
// Wrap in a transaction and send
|
|
218
|
+
const tx = new Transaction().add(cuIx, ix);
|
|
219
|
+
const prepared = await this.prepareTx(tx);
|
|
220
|
+
const signed = await this.signTransaction(prepared.tx);
|
|
221
|
+
|
|
222
|
+
return this.sendAndConfirmHttp(signed, prepared);
|
|
219
223
|
} catch (err) {
|
|
220
224
|
throw new Error(`Failed to deposit Solana: ${err}`);
|
|
221
225
|
}
|
|
@@ -238,14 +242,18 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
238
242
|
}
|
|
239
243
|
|
|
240
244
|
try {
|
|
241
|
-
|
|
242
|
-
const {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
// Build compute budget increase instruction
|
|
246
|
+
const cuIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 });
|
|
247
|
+
|
|
248
|
+
// Build the Outpost synd instruction
|
|
249
|
+
const ix = await this.depositClient.buildWithdrawTx(amountLamports);
|
|
250
|
+
|
|
251
|
+
// Wrap in a transaction and send
|
|
252
|
+
const tx = new Transaction().add(cuIx, ix);
|
|
253
|
+
const prepared = await this.prepareTx(tx);
|
|
254
|
+
const signed = await this.signTransaction(prepared.tx);
|
|
255
|
+
|
|
256
|
+
return this.sendAndConfirmHttp(signed, prepared);
|
|
249
257
|
} catch (err) {
|
|
250
258
|
throw new Error(`Failed to withdraw Solana: ${err}`);
|
|
251
259
|
}
|
|
@@ -328,14 +336,12 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
328
336
|
const user = this.solPubKey;
|
|
329
337
|
const cuIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 400_000 });
|
|
330
338
|
const ix = await this.tokenClient.buildPurchaseIx(amountLamports, user);
|
|
339
|
+
|
|
331
340
|
const tx = new Transaction().add(cuIx, ix);
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
return
|
|
336
|
-
blockhash,
|
|
337
|
-
lastValidBlockHeight,
|
|
338
|
-
});
|
|
341
|
+
const prepared = await this.prepareTx(tx);
|
|
342
|
+
const signed = await this.signTransaction(prepared.tx);
|
|
343
|
+
|
|
344
|
+
return this.sendAndConfirmHttp(signed, prepared);
|
|
339
345
|
}
|
|
340
346
|
catch (err) {
|
|
341
347
|
throw new Error(`Failed to buy liqSOL pretokens: ${err}`);
|