@wireio/stake 0.2.3 → 0.2.4
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 +270 -96
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.d.ts +176 -84
- package/lib/stake.js +282 -102
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +270 -96
- package/lib/stake.m.js.map +1 -1
- package/package.json +1 -1
- package/src/networks/solana/clients/token.client.ts +72 -98
- package/src/networks/solana/solana.ts +284 -184
- package/src/networks/solana/utils.ts +209 -5
- package/src/types.ts +68 -30
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// src/networks/solana/utils.ts
|
|
2
|
-
|
|
3
1
|
import { Program, BN, AnchorProvider } from '@coral-xyz/anchor';
|
|
4
2
|
|
|
5
3
|
import {
|
|
@@ -52,7 +50,213 @@ import {
|
|
|
52
50
|
|
|
53
51
|
import liqsolCoreIDL from '../../assets/solana/idl/liqsol_core.json';
|
|
54
52
|
import { LiqsolCore } from '../../assets/solana/types/liqsol_core';
|
|
55
|
-
import { TrancheState } from './types';
|
|
53
|
+
import { GlobalState, TrancheState } from './types';
|
|
54
|
+
import { TrancheLadderItem, TrancheSnapshot } from '../../types';
|
|
55
|
+
import { ChainID } from '@wireio/core';
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
// -----------------------------------------------------------------------------
|
|
59
|
+
// Tranche Support
|
|
60
|
+
// -----------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
const INDEX_SCALE = BigInt(1_000_000_000_000); // 1e12
|
|
64
|
+
const USD_SCALE = BigInt(100_000_000); // 1e8
|
|
65
|
+
const BPS = BigInt(10_000);
|
|
66
|
+
|
|
67
|
+
/** BN | bigint -> bigint helper (keeps code readable) */
|
|
68
|
+
export function toBigint(x: any): bigint {
|
|
69
|
+
if (typeof x === 'bigint') return x;
|
|
70
|
+
if (typeof x === 'number') return BigInt(x);
|
|
71
|
+
// Anchor BN
|
|
72
|
+
return BigInt(x.toString());
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Convert token amount -> shares using the same rule as on-chain tests:
|
|
77
|
+
* shares = ceil(amount * INDEX_SCALE / currentIndex)
|
|
78
|
+
*/
|
|
79
|
+
export function tokensToShares(amount: bigint, currentIndex: bigint): bigint {
|
|
80
|
+
if (amount === BigInt(0)) return BigInt(0);
|
|
81
|
+
const num = amount * INDEX_SCALE;
|
|
82
|
+
const q = num / currentIndex;
|
|
83
|
+
const r = num % currentIndex;
|
|
84
|
+
return r === BigInt(0) ? q : q + BigInt(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Apply one forward growth step: value * (BPS + growthBps) / BPS.
|
|
89
|
+
* Simple integer round-half-up.
|
|
90
|
+
*/
|
|
91
|
+
function growOnce(value: bigint, growthBps: number): bigint {
|
|
92
|
+
const g = BigInt(growthBps);
|
|
93
|
+
return (value * (BPS + g) + BPS / BigInt(2)) / BPS;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Apply one backward step: value * BPS / (BPS + growthBps).
|
|
98
|
+
* Also integer round-half-up.
|
|
99
|
+
*/
|
|
100
|
+
function shrinkOnce(value: bigint, growthBps: number): bigint {
|
|
101
|
+
const g = BigInt(growthBps);
|
|
102
|
+
return (value * BPS + (BPS + g) / BigInt(2)) / (BPS + g);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Build a local tranche ladder around the current tranche
|
|
107
|
+
* using only on-chain config + current state.
|
|
108
|
+
*
|
|
109
|
+
* Rules (from liqsol_core tests):
|
|
110
|
+
* - past tranches are fully sold
|
|
111
|
+
* - current tranche has (initial - currentSupply) sold
|
|
112
|
+
* - future tranches start with 0 sold
|
|
113
|
+
* - supply/price grow by supplyGrowthBps/priceGrowthBps per tranche
|
|
114
|
+
*/
|
|
115
|
+
export function buildSolanaTrancheLadder(options: {
|
|
116
|
+
currentTranche: number;
|
|
117
|
+
initialTrancheSupply: bigint;
|
|
118
|
+
currentTrancheSupply: bigint;
|
|
119
|
+
totalWarrantsSold: bigint; // informational only
|
|
120
|
+
currentPriceUsd: bigint;
|
|
121
|
+
supplyGrowthBps: number;
|
|
122
|
+
priceGrowthBps: number;
|
|
123
|
+
windowBefore?: number;
|
|
124
|
+
windowAfter?: number;
|
|
125
|
+
}): TrancheLadderItem[] {
|
|
126
|
+
const {
|
|
127
|
+
currentTranche,
|
|
128
|
+
initialTrancheSupply,
|
|
129
|
+
currentTrancheSupply,
|
|
130
|
+
currentPriceUsd,
|
|
131
|
+
supplyGrowthBps,
|
|
132
|
+
priceGrowthBps,
|
|
133
|
+
windowBefore = 5,
|
|
134
|
+
windowAfter = 5,
|
|
135
|
+
} = options;
|
|
136
|
+
|
|
137
|
+
const startId = Math.max(0, currentTranche - windowBefore);
|
|
138
|
+
const endId = currentTranche + windowAfter;
|
|
139
|
+
|
|
140
|
+
const capacity = new Map<number, bigint>();
|
|
141
|
+
const price = new Map<number, bigint>();
|
|
142
|
+
|
|
143
|
+
// Seed current
|
|
144
|
+
capacity.set(currentTranche, initialTrancheSupply);
|
|
145
|
+
price.set(currentTranche, currentPriceUsd);
|
|
146
|
+
|
|
147
|
+
// Forward (future tranches)
|
|
148
|
+
for (let id = currentTranche + 1; id <= endId; id++) {
|
|
149
|
+
const prevCap = capacity.get(id - 1)!;
|
|
150
|
+
const prevPrice = price.get(id - 1)!;
|
|
151
|
+
capacity.set(id, growOnce(prevCap, supplyGrowthBps));
|
|
152
|
+
price.set(id, growOnce(prevPrice, priceGrowthBps));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Backward (past tranches)
|
|
156
|
+
for (let id = currentTranche - 1; id >= startId; id--) {
|
|
157
|
+
const nextCap = capacity.get(id + 1)!;
|
|
158
|
+
const nextPrice = price.get(id + 1)!;
|
|
159
|
+
capacity.set(id, shrinkOnce(nextCap, supplyGrowthBps));
|
|
160
|
+
price.set(id, shrinkOnce(nextPrice, priceGrowthBps));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const ladder: TrancheLadderItem[] = [];
|
|
164
|
+
for (let id = startId; id <= endId; id++) {
|
|
165
|
+
const cap = capacity.get(id)!;
|
|
166
|
+
let sold: bigint;
|
|
167
|
+
if (id < currentTranche) {
|
|
168
|
+
sold = cap;
|
|
169
|
+
} else if (id === currentTranche) {
|
|
170
|
+
sold = cap - currentTrancheSupply;
|
|
171
|
+
} else {
|
|
172
|
+
sold = BigInt(0);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
ladder.push({
|
|
176
|
+
id,
|
|
177
|
+
capacity: cap,
|
|
178
|
+
sold,
|
|
179
|
+
remaining: cap - sold,
|
|
180
|
+
priceUsd: price.get(id)!,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return ladder;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Turn raw liqsol_core accounts into a chain-agnostic TrancheSnapshot for SOL.
|
|
189
|
+
* All math stays here; TokenClient just wires accounts + connection.
|
|
190
|
+
*/
|
|
191
|
+
export function buildSolanaTrancheSnapshot(options: {
|
|
192
|
+
chainID: ChainID;
|
|
193
|
+
globalState: GlobalState;
|
|
194
|
+
trancheState: TrancheState;
|
|
195
|
+
solPriceUsd?: bigint;
|
|
196
|
+
nativePriceTimestamp?: number;
|
|
197
|
+
ladderWindowBefore?: number;
|
|
198
|
+
ladderWindowAfter?: number;
|
|
199
|
+
}): TrancheSnapshot {
|
|
200
|
+
const {
|
|
201
|
+
chainID,
|
|
202
|
+
globalState,
|
|
203
|
+
trancheState,
|
|
204
|
+
solPriceUsd,
|
|
205
|
+
nativePriceTimestamp,
|
|
206
|
+
ladderWindowBefore,
|
|
207
|
+
ladderWindowAfter,
|
|
208
|
+
} = options;
|
|
209
|
+
|
|
210
|
+
const currentIndex = toBigint(globalState.currentIndex);
|
|
211
|
+
const totalShares = toBigint(globalState.totalShares);
|
|
212
|
+
|
|
213
|
+
const currentTranche = trancheState.currentTrancheNumber.toNumber();
|
|
214
|
+
const currentTrancheSupply = toBigint(trancheState.currentTrancheSupply);
|
|
215
|
+
const initialTrancheSupply = toBigint(trancheState.initialTrancheSupply);
|
|
216
|
+
const totalWarrantsSold = toBigint(trancheState.totalWarrantsSold);
|
|
217
|
+
const currentPriceUsd = toBigint(trancheState.currentTranchePriceUsd);
|
|
218
|
+
|
|
219
|
+
const supplyGrowthBps = trancheState.supplyGrowthBps;
|
|
220
|
+
const priceGrowthBps = trancheState.priceGrowthBps;
|
|
221
|
+
|
|
222
|
+
const minPriceUsd = trancheState.minPriceUsd
|
|
223
|
+
? toBigint(trancheState.minPriceUsd)
|
|
224
|
+
: undefined;
|
|
225
|
+
const maxPriceUsd = trancheState.maxPriceUsd
|
|
226
|
+
? toBigint(trancheState.maxPriceUsd)
|
|
227
|
+
: undefined;
|
|
228
|
+
|
|
229
|
+
const ladder = buildSolanaTrancheLadder({
|
|
230
|
+
currentTranche,
|
|
231
|
+
initialTrancheSupply,
|
|
232
|
+
currentTrancheSupply,
|
|
233
|
+
totalWarrantsSold,
|
|
234
|
+
currentPriceUsd,
|
|
235
|
+
supplyGrowthBps,
|
|
236
|
+
priceGrowthBps,
|
|
237
|
+
windowBefore: ladderWindowBefore,
|
|
238
|
+
windowAfter: ladderWindowAfter,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
chainID,
|
|
243
|
+
currentIndex,
|
|
244
|
+
totalShares,
|
|
245
|
+
currentTranche,
|
|
246
|
+
currentPriceUsd,
|
|
247
|
+
minPriceUsd,
|
|
248
|
+
maxPriceUsd,
|
|
249
|
+
supplyGrowthBps,
|
|
250
|
+
priceGrowthBps,
|
|
251
|
+
currentTrancheSupply,
|
|
252
|
+
initialTrancheSupply,
|
|
253
|
+
totalWarrantsSold,
|
|
254
|
+
nativePriceUsd: solPriceUsd,
|
|
255
|
+
nativePriceTimestamp,
|
|
256
|
+
ladder,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
56
260
|
|
|
57
261
|
// -----------------------------------------------------------------------------
|
|
58
262
|
// Read-only liqsol_core Program helper
|
|
@@ -367,10 +571,10 @@ export async function buildOutpostAccounts(
|
|
|
367
571
|
// Chainlink program feeds
|
|
368
572
|
let chainLinkFeed = CHAINLINK_FEED;
|
|
369
573
|
let chainLinkProgram = CHAINLINK_PROGRAM
|
|
370
|
-
|
|
574
|
+
|
|
371
575
|
try {
|
|
372
576
|
const program = getLiqsolCoreProgram(connection);
|
|
373
|
-
const ts
|
|
577
|
+
const ts: TrancheState = await program.account.trancheState.fetch(trancheState);
|
|
374
578
|
if (ts.chainlinkFeed && ts.chainlinkProgram) {
|
|
375
579
|
chainLinkFeed = ts.chainlinkFeed as PublicKey;
|
|
376
580
|
chainLinkProgram = ts.chainlinkProgram as PublicKey;
|
package/src/types.ts
CHANGED
|
@@ -30,7 +30,11 @@ export interface IStakingClient {
|
|
|
30
30
|
* - `TrancheSnapshot` when the chain supports pretoken/tranches
|
|
31
31
|
* - `null` if this chain has no WIRE/pretoken integration
|
|
32
32
|
*/
|
|
33
|
-
getTrancheSnapshot(
|
|
33
|
+
getTrancheSnapshot(options?: {
|
|
34
|
+
chainID?: ChainID;
|
|
35
|
+
windowBefore?: number;
|
|
36
|
+
windowAfter?: number;
|
|
37
|
+
}): Promise<TrancheSnapshot | null>;
|
|
34
38
|
|
|
35
39
|
/** */
|
|
36
40
|
getBuyQuote(amount: bigint, asset: PurchaseAsset): Promise<PurchaseQuote>;
|
|
@@ -51,7 +55,7 @@ export interface Portfolio {
|
|
|
51
55
|
/** Extra PDAs and account addresses */
|
|
52
56
|
extras?: Record<string, any>;
|
|
53
57
|
/** Chain ID of the network for which this portfolio is from */
|
|
54
|
-
chainID: ChainID;
|
|
58
|
+
chainID: ChainID;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
export type BalanceView = {
|
|
@@ -61,45 +65,79 @@ export type BalanceView = {
|
|
|
61
65
|
ata?: SolPubKey; // associated token account address
|
|
62
66
|
};
|
|
63
67
|
|
|
68
|
+
export interface TrancheLadderItem {
|
|
69
|
+
/** On-chain tranche id, 0-based (0,1,2,...) */
|
|
70
|
+
id: number;
|
|
71
|
+
/** Total capacity for this tranche (pretokens, 1e8 scale) */
|
|
72
|
+
capacity: bigint;
|
|
73
|
+
/** Sold amount in this tranche (1e8 scale) */
|
|
74
|
+
sold: bigint;
|
|
75
|
+
/** Remaining = capacity - sold (1e8 scale) */
|
|
76
|
+
remaining: bigint;
|
|
77
|
+
/** Price for this tranche in USD (1e8 scale) */
|
|
78
|
+
priceUsd: bigint;
|
|
79
|
+
}
|
|
80
|
+
|
|
64
81
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* All integer values are raw on-chain integers:
|
|
68
|
-
* - `currentTranchePriceUsd`: 1e8 USD
|
|
69
|
-
* - supplies / warrants / shares: 1e8 WIRE units (per liqsol_core/ETH analog)
|
|
70
|
-
* - index: same scale the program uses (INDEX_SCALE = 1e12 on Solana today)
|
|
82
|
+
* Unified pretoken/tranche snapshot for any chain.
|
|
83
|
+
* ETH / other chains just fill the same shape from their own contracts.
|
|
71
84
|
*/
|
|
72
85
|
export interface TrancheSnapshot {
|
|
73
86
|
chainID: ChainID;
|
|
74
87
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
/** Global share index (1e12 on Sol today; other chains can use their own scale) */
|
|
89
|
+
currentIndex: bigint;
|
|
90
|
+
/** Total accounting shares (wire pretoken “shares”) */
|
|
91
|
+
totalShares: bigint;
|
|
92
|
+
|
|
93
|
+
/** Current tranche id as stored on chain (0-based) */
|
|
94
|
+
currentTranche: number;
|
|
95
|
+
|
|
96
|
+
/** Current tranche price in USD (1e8 scale) */
|
|
97
|
+
currentPriceUsd: bigint;
|
|
98
|
+
/** Optional min/max bounds for price validation (1e8 scale) */
|
|
99
|
+
minPriceUsd?: bigint;
|
|
100
|
+
maxPriceUsd?: bigint;
|
|
101
|
+
|
|
102
|
+
/** Tranche curve config (per-chain) */
|
|
103
|
+
supplyGrowthBps: number; // e.g. 100 = +1% per tranche
|
|
104
|
+
priceGrowthBps: number; // e.g. 200 = +2% per tranche
|
|
78
105
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
totalWarrantsSold: bigint;
|
|
83
|
-
|
|
106
|
+
/** Current tranche supply state (1e8 scale) */
|
|
107
|
+
currentTrancheSupply: bigint; // remaining in current tranche
|
|
108
|
+
initialTrancheSupply: bigint; // capacity for current tranche
|
|
109
|
+
totalWarrantsSold: bigint; // global cumulative sold (all tranches), 1e8
|
|
110
|
+
|
|
111
|
+
/** Native token → USD price if available (SOL/USD, ETH/USD, etc, 1e8 scale) */
|
|
112
|
+
nativePriceUsd?: bigint;
|
|
113
|
+
/** Optional timestamp (sec) for the last recorded native price */
|
|
114
|
+
nativePriceTimestamp?: number;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Local window of tranche “rows” centered around current.
|
|
118
|
+
* Used directly by the frontend for ladder graphs.
|
|
119
|
+
*/
|
|
120
|
+
ladder: TrancheLadderItem[];
|
|
84
121
|
}
|
|
85
122
|
|
|
86
|
-
|
|
123
|
+
/** Purchase asset selection used by staking client(s) */
|
|
87
124
|
export enum PurchaseAsset {
|
|
88
|
-
SOL =
|
|
89
|
-
LIQSOL =
|
|
90
|
-
ETH =
|
|
91
|
-
LIQETH =
|
|
92
|
-
YIELD =
|
|
125
|
+
SOL = 'SOL',
|
|
126
|
+
LIQSOL = 'LIQSOL',
|
|
127
|
+
ETH = 'ETH',
|
|
128
|
+
LIQETH = 'LIQETH',
|
|
129
|
+
YIELD = 'YIELD',
|
|
93
130
|
}
|
|
94
131
|
|
|
95
132
|
export interface PurchaseQuote {
|
|
96
133
|
purchaseAsset: PurchaseAsset;
|
|
97
|
-
amountIn: bigint;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
wirePriceUsd: bigint; // 1e8 precision
|
|
103
|
-
notionalUsd: bigint; // 1e8 precision
|
|
104
|
-
}
|
|
134
|
+
amountIn: bigint; // lamports / wei / token units
|
|
135
|
+
|
|
136
|
+
/** Expected pretoken “shares” (pretokens) and decimals */
|
|
137
|
+
wireShares: bigint; // 1e8 scale
|
|
138
|
+
wireDecimals: number; // always 8 for now
|
|
105
139
|
|
|
140
|
+
/** Current price + notional in USD (1e8 scale) */
|
|
141
|
+
wirePriceUsd: bigint;
|
|
142
|
+
notionalUsd: bigint;
|
|
143
|
+
}
|