@wireio/stake 0.5.2 → 0.7.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 +284 -283
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.d.ts +37 -36
- package/lib/stake.js +287 -286
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +284 -283
- package/lib/stake.m.js.map +1 -1
- package/package.json +1 -1
- package/src/assets/ethereum/ABI/liqEth/liqEth.sol/LiqEthToken.dbg.json +1 -1
- package/src/assets/ethereum/ABI/liqEth/liqEth.sol/LiqEthToken.json +33 -2
- package/src/assets/ethereum/ABI/outpost/BAR.sol/BAR.dbg.json +1 -1
- package/src/assets/ethereum/ABI/outpost/BAR.sol/BAR.json +2 -18
- package/src/assets/ethereum/ABI/outpost/Depositor.sol/Depositor.dbg.json +1 -1
- package/src/assets/ethereum/ABI/outpost/Depositor.sol/Depositor.json +26 -42
- package/src/assets/ethereum/ABI/outpost/EthUsdPriceConsumer.sol/AggregatorV3Interface.dbg.json +1 -1
- package/src/assets/ethereum/ABI/outpost/EthUsdPriceConsumer.sol/EthUsdPriceConsumer.dbg.json +1 -1
- package/src/assets/ethereum/ABI/outpost/EthUsdPriceConsumer.sol/EthUsdPriceConsumer.json +2 -31
- package/src/assets/ethereum/ABI/outpost/OutpostErrors.sol/OutpostErrors.dbg.json +1 -1
- package/src/assets/ethereum/ABI/outpost/OutpostErrors.sol/OutpostErrors.json +2 -18
- package/src/assets/ethereum/ABI/outpost/Pool.sol/Pool.dbg.json +1 -1
- package/src/assets/ethereum/ABI/outpost/Pool.sol/Pool.json +2 -18
- package/src/assets/ethereum/ABI/outpost/Pretoken.sol/Pretoken.dbg.json +1 -1
- package/src/assets/ethereum/ABI/outpost/Pretoken.sol/Pretoken.json +2 -18
- package/src/assets/ethereum/ABI/outpost/ReceiptNFT.sol/ReceiptNFT.dbg.json +1 -1
- package/src/assets/ethereum/ABI/outpost/ReceiptNFT.sol/ReceiptNFT.json +2 -18
- package/src/assets/ethereum/ABI/token/ERC1155Token.sol/ERC1155Token.dbg.json +1 -1
- package/src/assets/ethereum/ABI/token/ERC1155Token.sol/ERC1155Token.json +2 -2
- package/src/assets/ethereum/ABI/token/ERC20Token.sol/ERC20Token.dbg.json +1 -1
- package/src/assets/ethereum/ABI/token/ERC20Token.sol/ERC20Token.json +2 -2
- package/src/assets/ethereum/ABI/token/ERC721Token.sol/ERC721Token.dbg.json +1 -1
- package/src/assets/ethereum/ABI/token/ERC721Token.sol/ERC721Token.json +2 -2
- package/src/networks/ethereum/contract.ts +24 -24
- package/src/networks/ethereum/ethereum.ts +14 -8
- package/src/networks/ethereum/utils.ts +103 -71
- package/src/networks/solana/solana.ts +160 -97
- package/src/networks/solana/utils.ts +58 -30
- package/src/staker.ts +2 -0
- package/src/types.ts +12 -11
|
@@ -482,6 +482,46 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
482
482
|
// READ-ONLY Public Methods
|
|
483
483
|
// ---------------------------------------------------------------------
|
|
484
484
|
|
|
485
|
+
/**
|
|
486
|
+
* Unified, chain-agnostic tranche snapshot for Solana.
|
|
487
|
+
*
|
|
488
|
+
* Uses:
|
|
489
|
+
* - liqsol_core.globalState (currentIndex, totalShares, etc.)
|
|
490
|
+
* - liqsol_core.trancheState (price, supply, total sold, etc.)
|
|
491
|
+
* - PriceHistory/Chainlink SOL/USD via TokenClient.getSolPriceUsdSafe()
|
|
492
|
+
*
|
|
493
|
+
* This is READ-ONLY and works even with no connected wallet.
|
|
494
|
+
*/
|
|
495
|
+
async getTrancheSnapshot(options?: {
|
|
496
|
+
chainID?: ChainID;
|
|
497
|
+
windowBefore?: number;
|
|
498
|
+
windowAfter?: number;
|
|
499
|
+
}): Promise<TrancheSnapshot> {
|
|
500
|
+
const {
|
|
501
|
+
chainID = SolChainID.WireTestnet,
|
|
502
|
+
windowBefore,
|
|
503
|
+
windowAfter,
|
|
504
|
+
} = options ?? {};
|
|
505
|
+
|
|
506
|
+
const [globalState, trancheState] = await Promise.all([
|
|
507
|
+
this.tokenClient.fetchGlobalState(),
|
|
508
|
+
this.tokenClient.fetchTrancheState(),
|
|
509
|
+
]);
|
|
510
|
+
|
|
511
|
+
const { price: solPriceUsd, timestamp } =
|
|
512
|
+
await this.tokenClient.getSolPriceUsdSafe();
|
|
513
|
+
|
|
514
|
+
return buildSolanaTrancheSnapshot({
|
|
515
|
+
chainID,
|
|
516
|
+
globalState,
|
|
517
|
+
trancheState,
|
|
518
|
+
solPriceUsd,
|
|
519
|
+
nativePriceTimestamp: timestamp,
|
|
520
|
+
ladderWindowBefore: windowBefore,
|
|
521
|
+
ladderWindowAfter: windowAfter,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
485
525
|
/**
|
|
486
526
|
* Returns the system APY (percent) for Solana,
|
|
487
527
|
* using compound interest per epoch and a
|
|
@@ -490,19 +530,12 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
490
530
|
async getSystemAPY(): Promise<number> {
|
|
491
531
|
// 1) Per-epoch rate (decimal) from on-chain stakeMetrics
|
|
492
532
|
const ratePerEpoch = await this.getEpochRateDecimalFromProgram();
|
|
493
|
-
console.log('epochRateDecimal', ratePerEpoch);
|
|
494
|
-
|
|
495
533
|
// 2) Live epochs-per-year estimate from cluster
|
|
496
534
|
const epochsPerYear = await this.getEpochsPerYearFromCluster();
|
|
497
|
-
console.log('epochsPerYear', epochsPerYear);
|
|
498
|
-
|
|
499
535
|
// 3) Compound: (1 + r)^N - 1
|
|
500
536
|
const apyDecimal = Math.pow(1 + ratePerEpoch, epochsPerYear) - 1;
|
|
501
|
-
console.log('apyDecimal', apyDecimal);
|
|
502
|
-
|
|
503
537
|
// 4) Convert to percent
|
|
504
538
|
const apyPercent = apyDecimal * 100;
|
|
505
|
-
console.log('apyPercent', apyPercent);
|
|
506
539
|
|
|
507
540
|
return apyPercent;
|
|
508
541
|
}
|
|
@@ -524,9 +557,6 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
524
557
|
// Convert to JS number in **decimal per epoch** units
|
|
525
558
|
const rateDecimal = Number(raw) / Number(PAY_RATE_SCALE_FACTOR);
|
|
526
559
|
|
|
527
|
-
console.log('solSystemPayRate(raw)', raw.toString());
|
|
528
|
-
console.log('epochRateDecimal(computed)', rateDecimal);
|
|
529
|
-
|
|
530
560
|
return rateDecimal;
|
|
531
561
|
}
|
|
532
562
|
|
|
@@ -643,112 +673,145 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
643
673
|
}
|
|
644
674
|
|
|
645
675
|
/**
|
|
646
|
-
*
|
|
676
|
+
* Compute a conservative "deposit buffer" in lamports that should be left
|
|
677
|
+
* in the wallet so that a MAX deposit (balance - buffer) will succeed.
|
|
647
678
|
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
* - PriceHistory/Chainlink SOL/USD via TokenClient.getSolPriceUsdSafe()
|
|
679
|
+
* It accounts for:
|
|
680
|
+
* - Runtime tx fees (via a dummy self-transfer)
|
|
681
|
+
* - Protocol deposit fee (via getDepositFee(amount))
|
|
652
682
|
*
|
|
653
|
-
*
|
|
683
|
+
* Intended UI usage:
|
|
684
|
+
* const buffer = await client.getDepositBuffer();
|
|
685
|
+
* const balance = portfolio.native.amount;
|
|
686
|
+
* const maxDeposit = balance > buffer ? balance - buffer : BigInt(0);
|
|
654
687
|
*/
|
|
655
|
-
async
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
windowBefore,
|
|
663
|
-
windowAfter,
|
|
664
|
-
} = options ?? {};
|
|
688
|
+
async getDepositBuffer(options?: {
|
|
689
|
+
txCount?: number; // how many txs to cover in gas buffer (default 2)
|
|
690
|
+
safetyMultiplier?: number; // safety multiplier on per-tx fee (default 3x)
|
|
691
|
+
minBufferLamports?: bigint; // minimum gas buffer (default ~0.01 SOL)
|
|
692
|
+
balanceOverrideLamports?: bigint; // for tests/custom callers
|
|
693
|
+
}): Promise<bigint> {
|
|
694
|
+
this.ensureUser();
|
|
665
695
|
|
|
666
|
-
const
|
|
667
|
-
this.tokenClient.fetchGlobalState(),
|
|
668
|
-
this.tokenClient.fetchTrancheState(),
|
|
669
|
-
]);
|
|
696
|
+
const payer = this.solPubKey;
|
|
670
697
|
|
|
671
|
-
|
|
672
|
-
|
|
698
|
+
// -------------------------------------------------------------
|
|
699
|
+
// 1) Current wallet balance
|
|
700
|
+
// -------------------------------------------------------------
|
|
701
|
+
const balanceLamports: bigint =
|
|
702
|
+
options?.balanceOverrideLamports ??
|
|
703
|
+
BigInt(await this.connection.getBalance(payer, commitment));
|
|
673
704
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
trancheState,
|
|
678
|
-
solPriceUsd,
|
|
679
|
-
nativePriceTimestamp: timestamp,
|
|
680
|
-
ladderWindowBefore: windowBefore,
|
|
681
|
-
ladderWindowAfter: windowAfter,
|
|
682
|
-
});
|
|
683
|
-
}
|
|
705
|
+
if (balanceLamports <= BigInt(0)) {
|
|
706
|
+
return BigInt(0);
|
|
707
|
+
}
|
|
684
708
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
minBufferLamports?: bigint;
|
|
704
|
-
}): Promise<bigint> {
|
|
705
|
-
this.ensureUser();
|
|
709
|
+
// -------------------------------------------------------------
|
|
710
|
+
// 2) Estimate gas buffer via dummy self-transfer
|
|
711
|
+
// -------------------------------------------------------------
|
|
712
|
+
let gasBuffer = BigInt(0);
|
|
713
|
+
|
|
714
|
+
try {
|
|
715
|
+
const dummyIx = SystemProgram.transfer({
|
|
716
|
+
fromPubkey: payer,
|
|
717
|
+
toPubkey: payer,
|
|
718
|
+
lamports: 0,
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
const tx = new Transaction().add(dummyIx);
|
|
722
|
+
const { blockhash } = await this.connection.getLatestBlockhash(
|
|
723
|
+
commitment,
|
|
724
|
+
);
|
|
725
|
+
tx.recentBlockhash = blockhash;
|
|
726
|
+
tx.feePayer = payer;
|
|
706
727
|
|
|
707
|
-
|
|
728
|
+
const message = tx.compileMessage();
|
|
729
|
+
const feeInfo = await this.connection.getFeeForMessage(
|
|
730
|
+
message,
|
|
731
|
+
commitment,
|
|
732
|
+
);
|
|
708
733
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
fromPubkey: payer,
|
|
712
|
-
toPubkey: payer,
|
|
713
|
-
lamports: 0,
|
|
714
|
-
});
|
|
734
|
+
// Fallback to a conservative default if RPC doesn't give a value.
|
|
735
|
+
const singleTxFeeLamports = BigInt(feeInfo.value ?? 5000);
|
|
715
736
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
737
|
+
const txCount = BigInt(options?.txCount ?? 2);
|
|
738
|
+
const safetyMultiplier = options?.safetyMultiplier ?? 3;
|
|
739
|
+
const safetyScaled = BigInt(Math.round(safetyMultiplier * 100)); // e.g. 300
|
|
740
|
+
|
|
741
|
+
let buf =
|
|
742
|
+
(singleTxFeeLamports * txCount * safetyScaled) /
|
|
743
|
+
BigInt(100);
|
|
744
|
+
|
|
745
|
+
const defaultMinBufferLamports = BigInt(10_000_000); // ~0.01 SOL
|
|
746
|
+
const minBufferLamports =
|
|
747
|
+
options?.minBufferLamports ?? defaultMinBufferLamports;
|
|
720
748
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
749
|
+
if (buf < minBufferLamports) {
|
|
750
|
+
buf = minBufferLamports;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
gasBuffer = buf;
|
|
754
|
+
} catch {
|
|
755
|
+
// If fee estimation fails, fall back to zero gas buffer
|
|
756
|
+
// (we will still leave room for protocol fee below).
|
|
757
|
+
gasBuffer = BigInt(0);
|
|
758
|
+
}
|
|
724
759
|
|
|
725
|
-
//
|
|
726
|
-
|
|
760
|
+
// If fees alone eat the whole balance, just keep everything as buffer.
|
|
761
|
+
if (balanceLamports <= gasBuffer) {
|
|
762
|
+
return balanceLamports;
|
|
763
|
+
}
|
|
727
764
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
765
|
+
const spendable = balanceLamports - gasBuffer;
|
|
766
|
+
|
|
767
|
+
// -------------------------------------------------------------
|
|
768
|
+
// 3) If we can't compute deposit fee, buffer == gasBuffer
|
|
769
|
+
// -------------------------------------------------------------
|
|
770
|
+
if (typeof this.getDepositFee !== 'function') {
|
|
771
|
+
return gasBuffer;
|
|
772
|
+
}
|
|
731
773
|
|
|
732
|
-
//
|
|
733
|
-
|
|
734
|
-
|
|
774
|
+
// -------------------------------------------------------------
|
|
775
|
+
// 4) Binary search for max principal p such that:
|
|
776
|
+
// p + fee(p) <= spendable
|
|
777
|
+
// Then buffer = balance - pEffective.
|
|
778
|
+
// -------------------------------------------------------------
|
|
779
|
+
let lo = BigInt(0);
|
|
780
|
+
let hi = spendable;
|
|
781
|
+
|
|
782
|
+
for (let i = 0; i < 20 && hi - lo > BigInt(1); i++) {
|
|
783
|
+
const mid = (lo + hi) / BigInt(2);
|
|
784
|
+
|
|
785
|
+
let fee: bigint;
|
|
786
|
+
try {
|
|
787
|
+
fee = await this.getDepositFee(mid);
|
|
788
|
+
} catch {
|
|
789
|
+
// If fee lookup fails mid-search, fall back to gas-only buffer.
|
|
790
|
+
return gasBuffer;
|
|
791
|
+
}
|
|
735
792
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
793
|
+
if (mid + fee <= spendable) {
|
|
794
|
+
lo = mid; // mid is affordable → try bigger
|
|
795
|
+
} else {
|
|
796
|
+
hi = mid; // mid too big → go smaller
|
|
797
|
+
}
|
|
798
|
+
}
|
|
741
799
|
|
|
742
|
-
//
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
800
|
+
// Tiny safety haircut to avoid off-by-one lamport issues.
|
|
801
|
+
const fudge = BigInt(1_000); // ≈ 0.000001 SOL
|
|
802
|
+
let effectivePrincipal =
|
|
803
|
+
lo > fudge ? lo - fudge : lo;
|
|
746
804
|
|
|
747
|
-
if (
|
|
748
|
-
|
|
805
|
+
if (effectivePrincipal < BigInt(0)) {
|
|
806
|
+
effectivePrincipal = BigInt(0);
|
|
749
807
|
}
|
|
750
808
|
|
|
751
|
-
|
|
809
|
+
const buffer = balanceLamports > effectivePrincipal
|
|
810
|
+
? balanceLamports - effectivePrincipal
|
|
811
|
+
: balanceLamports;
|
|
812
|
+
|
|
813
|
+
// Ensure we never *under*-reserve gas
|
|
814
|
+
return buffer < gasBuffer ? gasBuffer : buffer;
|
|
752
815
|
}
|
|
753
816
|
|
|
754
817
|
// ---------------------------------------------------------------------
|
|
@@ -55,11 +55,51 @@ import { ChainID } from '@wireio/core';
|
|
|
55
55
|
// -----------------------------------------------------------------------------
|
|
56
56
|
// Tranche Support
|
|
57
57
|
// -----------------------------------------------------------------------------
|
|
58
|
-
|
|
59
58
|
const INDEX_SCALE = BigInt(1_000_000_000_000); // 1e12
|
|
60
|
-
const USD_SCALE = BigInt(100_000_000);
|
|
59
|
+
const USD_SCALE = BigInt(100_000_000); // 1e8
|
|
61
60
|
const BPS = BigInt(10_000);
|
|
62
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Apply one forward growth step: value * (BPS + growthBps) / BPS.
|
|
64
|
+
* Simple integer round-half-up.
|
|
65
|
+
*/
|
|
66
|
+
function growSupplyOnce(value: bigint, growthBps: number): bigint {
|
|
67
|
+
const g = BigInt(growthBps);
|
|
68
|
+
return (value * (BPS + g) + BPS / BigInt(2)) / BPS;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Apply one backward step: value * BPS / (BPS + growthBps).
|
|
73
|
+
* Also integer round-half-up.
|
|
74
|
+
*/
|
|
75
|
+
function shrinkSupplyOnce(value: bigint, growthBps: number): bigint {
|
|
76
|
+
const g = BigInt(growthBps);
|
|
77
|
+
return (value * BPS + (BPS + g) / BigInt(2)) / (BPS + g);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Price step is expressed in *cents*, while prices are 1e8 USD.
|
|
82
|
+
* 1 cent = 0.01 * 1e8 = 1e6, so:
|
|
83
|
+
* step = priceGrowthCents * 1e6
|
|
84
|
+
*/
|
|
85
|
+
function priceStepUsd1e8(priceGrowthCents: number): bigint {
|
|
86
|
+
if (!priceGrowthCents) return BigInt(0);
|
|
87
|
+
const CENT_SCALE = USD_SCALE / BigInt(100); // 1e6
|
|
88
|
+
return BigInt(priceGrowthCents) * CENT_SCALE;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function growPriceOnceUsd1e8(value: bigint, priceGrowthCents: number): bigint {
|
|
92
|
+
const step = priceStepUsd1e8(priceGrowthCents);
|
|
93
|
+
return value + step;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function shrinkPriceOnceUsd1e8(value: bigint, priceGrowthCents: number): bigint {
|
|
97
|
+
const step = priceStepUsd1e8(priceGrowthCents);
|
|
98
|
+
if (step === BigInt(0)) return value;
|
|
99
|
+
if (value <= step) return BigInt(0);
|
|
100
|
+
return value - step;
|
|
101
|
+
}
|
|
102
|
+
|
|
63
103
|
/** BN | bigint -> bigint helper (keeps code readable) */
|
|
64
104
|
export function toBigint(x: any): bigint {
|
|
65
105
|
if (typeof x === 'bigint') return x;
|
|
@@ -80,24 +120,6 @@ export function tokensToShares(amount: bigint, currentIndex: bigint): bigint {
|
|
|
80
120
|
return r === BigInt(0) ? q : q + BigInt(1);
|
|
81
121
|
}
|
|
82
122
|
|
|
83
|
-
/**
|
|
84
|
-
* Apply one forward growth step: value * (BPS + growthBps) / BPS.
|
|
85
|
-
* Simple integer round-half-up.
|
|
86
|
-
*/
|
|
87
|
-
function growOnce(value: bigint, growthBps: number): bigint {
|
|
88
|
-
const g = BigInt(growthBps);
|
|
89
|
-
return (value * (BPS + g) + BPS / BigInt(2)) / BPS;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Apply one backward step: value * BPS / (BPS + growthBps).
|
|
94
|
-
* Also integer round-half-up.
|
|
95
|
-
*/
|
|
96
|
-
function shrinkOnce(value: bigint, growthBps: number): bigint {
|
|
97
|
-
const g = BigInt(growthBps);
|
|
98
|
-
return (value * BPS + (BPS + g) / BigInt(2)) / (BPS + g);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
123
|
/**
|
|
102
124
|
* Build a local tranche ladder around the current tranche
|
|
103
125
|
* using only on-chain config + current state.
|
|
@@ -112,9 +134,9 @@ export function buildSolanaTrancheLadder(options: {
|
|
|
112
134
|
currentTranche: number;
|
|
113
135
|
initialTrancheSupply: bigint;
|
|
114
136
|
currentTrancheSupply: bigint;
|
|
115
|
-
currentPriceUsd: bigint;
|
|
137
|
+
currentPriceUsd: bigint; // 1e8 scale
|
|
116
138
|
supplyGrowthBps: number;
|
|
117
|
-
priceGrowthCents: number;
|
|
139
|
+
priceGrowthCents: number; // e.g. 2 -> $0.02 per tranche
|
|
118
140
|
windowBefore?: number;
|
|
119
141
|
windowAfter?: number;
|
|
120
142
|
}): TrancheLadderItem[] {
|
|
@@ -135,35 +157,41 @@ export function buildSolanaTrancheLadder(options: {
|
|
|
135
157
|
const capacity = new Map<number, bigint>();
|
|
136
158
|
const price = new Map<number, bigint>();
|
|
137
159
|
|
|
138
|
-
// Seed current
|
|
160
|
+
// Seed current tranche
|
|
139
161
|
capacity.set(currentTranche, initialTrancheSupply);
|
|
140
162
|
price.set(currentTranche, currentPriceUsd);
|
|
141
163
|
|
|
142
|
-
// Forward (future tranches)
|
|
164
|
+
// Forward (future tranches): grow supply by BPS, price by +cents (linear)
|
|
143
165
|
for (let id = currentTranche + 1; id <= endId; id++) {
|
|
144
166
|
const prevCap = capacity.get(id - 1)!;
|
|
145
167
|
const prevPrice = price.get(id - 1)!;
|
|
146
|
-
|
|
147
|
-
|
|
168
|
+
|
|
169
|
+
capacity.set(id, growSupplyOnce(prevCap, supplyGrowthBps));
|
|
170
|
+
price.set(id, growPriceOnceUsd1e8(prevPrice, priceGrowthCents));
|
|
148
171
|
}
|
|
149
172
|
|
|
150
|
-
// Backward (past tranches)
|
|
173
|
+
// Backward (past tranches): shrink supply by inverse BPS, price by -cents
|
|
151
174
|
for (let id = currentTranche - 1; id >= startId; id--) {
|
|
152
175
|
const nextCap = capacity.get(id + 1)!;
|
|
153
176
|
const nextPrice = price.get(id + 1)!;
|
|
154
|
-
|
|
155
|
-
|
|
177
|
+
|
|
178
|
+
capacity.set(id, shrinkSupplyOnce(nextCap, supplyGrowthBps));
|
|
179
|
+
price.set(id, shrinkPriceOnceUsd1e8(nextPrice, priceGrowthCents));
|
|
156
180
|
}
|
|
157
181
|
|
|
158
182
|
const ladder: TrancheLadderItem[] = [];
|
|
159
183
|
for (let id = startId; id <= endId; id++) {
|
|
160
184
|
const cap = capacity.get(id)!;
|
|
185
|
+
|
|
161
186
|
let sold: bigint;
|
|
162
187
|
if (id < currentTranche) {
|
|
188
|
+
// Past tranches fully sold
|
|
163
189
|
sold = cap;
|
|
164
190
|
} else if (id === currentTranche) {
|
|
191
|
+
// Current tranche: cap - remaining
|
|
165
192
|
sold = cap - currentTrancheSupply;
|
|
166
193
|
} else {
|
|
194
|
+
// Future tranches not yet opened
|
|
167
195
|
sold = BigInt(0);
|
|
168
196
|
}
|
|
169
197
|
|
|
@@ -172,7 +200,7 @@ export function buildSolanaTrancheLadder(options: {
|
|
|
172
200
|
capacity: cap,
|
|
173
201
|
sold,
|
|
174
202
|
remaining: cap - sold,
|
|
175
|
-
priceUsd: price.get(id)!,
|
|
203
|
+
priceUsd: price.get(id)!, // still 1e8 scale
|
|
176
204
|
});
|
|
177
205
|
}
|
|
178
206
|
|
package/src/staker.ts
CHANGED
|
@@ -37,9 +37,11 @@ export class Staker {
|
|
|
37
37
|
config.forEach((cfg) => {
|
|
38
38
|
switch (cfg.network.chainId) {
|
|
39
39
|
case SolChainID.Devnet:
|
|
40
|
+
case SolChainID.WireTestnet:
|
|
40
41
|
this.clients.set(cfg.network.chainId, new SolanaStakingClient(cfg));
|
|
41
42
|
break;
|
|
42
43
|
|
|
44
|
+
case EvmChainID.Ethereum:
|
|
43
45
|
case EvmChainID.Hoodi:
|
|
44
46
|
this.clients.set(EvmChainID.Hoodi, new EthereumStakingClient(cfg));
|
|
45
47
|
break;
|
package/src/types.ts
CHANGED
|
@@ -26,13 +26,6 @@ export interface IStakingClient {
|
|
|
26
26
|
// Estimated total APY for staking yeild
|
|
27
27
|
getSystemAPY(): Promise<number>;
|
|
28
28
|
|
|
29
|
-
/**
|
|
30
|
-
* Protocol fee charged for deposit from Native to LIQ
|
|
31
|
-
* in Solana: amount in lamports
|
|
32
|
-
* in Ethereum: amount in wei
|
|
33
|
-
*/
|
|
34
|
-
getDepositFee(amount: bigint): Promise<bigint>;
|
|
35
|
-
|
|
36
29
|
/**
|
|
37
30
|
* Program-level prelaunch WIRE/tranche snapshot for this chain.
|
|
38
31
|
*
|
|
@@ -46,15 +39,23 @@ export interface IStakingClient {
|
|
|
46
39
|
windowAfter?: number;
|
|
47
40
|
}): Promise<TrancheSnapshot | null>;
|
|
48
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Protocol fee charged for deposit from Native to LIQ
|
|
44
|
+
* in Solana: amount in lamports
|
|
45
|
+
* in Ethereum: amount in wei
|
|
46
|
+
*/
|
|
47
|
+
getDepositFee(amount: bigint): Promise<bigint>;
|
|
48
|
+
|
|
49
49
|
/**
|
|
50
50
|
* Estimate a conservative ETH(wei) / SOL(lamports) buffer to leave in the wallet
|
|
51
51
|
* so the user can pay fees for the current deposit and at least one
|
|
52
52
|
* more transaction, plus a bit extra for future interactions.
|
|
53
53
|
*/
|
|
54
|
-
|
|
55
|
-
txCount?: number;
|
|
56
|
-
safetyMultiplier?: number;
|
|
57
|
-
|
|
54
|
+
getDepositBuffer(options?: {
|
|
55
|
+
txCount?: number; // how many txs to cover in gas buffer (default 2)
|
|
56
|
+
safetyMultiplier?: number; // safety multiplier on per-tx fee (default 3x)
|
|
57
|
+
minBufferLamports?: bigint; // minimum gas buffer (default ~0.01 SOL)
|
|
58
|
+
balanceOverrideLamports?: bigint; // for tests/custom callers
|
|
58
59
|
}): Promise<bigint>
|
|
59
60
|
}
|
|
60
61
|
|