@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.
- package/lib/stake.browser.js +833 -172
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.d.ts +777 -163
- package/lib/stake.js +831 -165
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +833 -172
- package/lib/stake.m.js.map +1 -1
- package/package.json +2 -2
- package/src/assets/solana/idl/liqsol_core.json +760 -150
- package/src/assets/solana/idl/liqsol_token.json +1 -1
- package/src/assets/solana/idl/transfer_hook.json +6 -1
- package/src/assets/solana/idl/validator_leaderboard.json +4 -1
- package/src/assets/solana/types/liqsol_core.ts +760 -150
- package/src/assets/solana/types/liqsol_token.ts +1 -1
- package/src/assets/solana/types/transfer_hook.ts +6 -1
- package/src/assets/solana/types/validator_leaderboard.ts +4 -1
- package/src/networks/ethereum/ethereum.ts +53 -6
- package/src/networks/solana/clients/deposit.client.ts +5 -4
- package/src/networks/solana/constants.ts +14 -0
- package/src/networks/solana/solana.ts +20 -13
- package/src/types.ts +15 -9
|
@@ -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": "
|
|
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": "
|
|
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": "
|
|
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
|
-
|
|
246
|
-
return
|
|
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(
|
|
251
|
-
|
|
252
|
-
return
|
|
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
|
-
// -
|
|
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
|
|
396
|
-
let
|
|
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
|
-
|
|
406
|
+
estimatedClaim = (userShares * currentIndex) / INDEX_SCALE;
|
|
401
407
|
|
|
402
|
-
if (
|
|
403
|
-
|
|
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
|
-
|
|
439
|
-
|
|
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
|
-
//
|
|
479
|
-
|
|
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
|
-
*
|
|
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
|
|
150
|
+
* Total liq (wei/lamports) the user could claim right now if they fully
|
|
145
151
|
* unwound their stake:
|
|
146
|
-
*
|
|
152
|
+
* estimatedClaim = userShares * currentIndex / indexScale
|
|
147
153
|
*/
|
|
148
|
-
|
|
154
|
+
estimatedClaim?: bigint;
|
|
149
155
|
|
|
150
156
|
/**
|
|
151
|
-
* Portion of
|
|
152
|
-
*
|
|
157
|
+
* Portion of estimatedClaim that is “yield” above principal:
|
|
158
|
+
* estimatedYield = max(0, estimatedClaim - staked)
|
|
153
159
|
*
|
|
154
|
-
* NOTE:
|
|
160
|
+
* NOTE: staked principal itself is surfaced separately as
|
|
155
161
|
* Portfolio.staked.amount.
|
|
156
162
|
*/
|
|
157
|
-
|
|
163
|
+
estimatedYield?: bigint;
|
|
158
164
|
}
|
|
159
165
|
|
|
160
166
|
export interface TrancheLadderItem {
|