@wireio/stake 0.0.6 → 0.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/README.md +203 -13
- package/lib/stake.browser.js +2800 -3329
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.d.ts +376 -6261
- package/lib/stake.js +2937 -3476
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +2800 -3329
- package/lib/stake.m.js.map +1 -1
- package/package.json +2 -2
- package/src/assets/solana/idl/deposit.json +46 -10
- package/src/assets/solana/idl/distribution.json +40 -8
- package/src/assets/solana/idl/liq_sol_token.json +25 -2
- package/src/assets/solana/idl/mint_helper.json +110 -0
- package/src/assets/solana/idl/read_tracked_balance.json +140 -0
- package/src/assets/solana/idl/stake_controller.json +1141 -780
- package/src/assets/solana/idl/treasury.json +1 -227
- package/src/assets/solana/idl/validator_leaderboard.json +88 -47
- package/src/assets/solana/idl/validator_registry.json +115 -46
- package/src/assets/solana/idl/yield_oracle.json +1 -1
- package/src/assets/solana/types/deposit.ts +46 -10
- package/src/assets/solana/types/distribution.ts +40 -8
- package/src/assets/solana/types/liq_sol_token.ts +25 -2
- package/src/assets/solana/types/mint_helper.ts +116 -0
- package/src/assets/solana/types/read_tracked_balance.ts +146 -0
- package/src/assets/solana/types/stake_controller.ts +1141 -780
- package/src/assets/solana/types/treasury.ts +1 -227
- package/src/assets/solana/types/validator_leaderboard.ts +88 -47
- package/src/assets/solana/types/validator_registry.ts +115 -46
- package/src/assets/solana/types/yield_oracle.ts +1 -1
- package/src/index.ts +3 -4
- package/src/networks/ethereum/ethereum.ts +2 -2
- package/src/networks/solana/clients/deposit.client.ts +71 -80
- package/src/networks/solana/clients/distribution.client.ts +392 -141
- package/src/networks/solana/clients/leaderboard.client.ts +82 -107
- package/src/networks/solana/constants.ts +141 -56
- package/src/networks/solana/program.ts +36 -89
- package/src/networks/solana/solana.ts +168 -34
- package/src/networks/solana/types.ts +57 -0
- package/src/scripts/fetch-artifacts.sh +24 -0
- package/src/staker/staker.ts +32 -28
- package/src/staker/types.ts +24 -21
- package/src/assets/solana/idl/stake_registry.json +0 -435
- package/src/networks/solana/utils.ts +0 -122
- /package/src/{utils.ts → common/utils.ts} +0 -0
|
@@ -1,45 +1,43 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Connection,
|
|
3
3
|
PublicKey as SolPubKey,
|
|
4
|
-
Transaction,
|
|
5
|
-
VersionedTransaction,
|
|
6
4
|
TransactionSignature,
|
|
7
5
|
Commitment,
|
|
6
|
+
ConnectionConfig,
|
|
7
|
+
Transaction,
|
|
8
8
|
} from '@solana/web3.js';
|
|
9
9
|
import { AnchorProvider } from '@coral-xyz/anchor';
|
|
10
10
|
import { BaseSignerWalletAdapter } from '@solana/wallet-adapter-base';
|
|
11
|
-
import { IStakingClient,
|
|
11
|
+
import { IStakingClient, Portfolio, StakerConfig } from '../../staker/types';
|
|
12
12
|
import { ChainID, ExternalNetwork, KeyType, PublicKey } from '@wireio/core';
|
|
13
13
|
import { DepositClient } from './clients/deposit.client';
|
|
14
|
+
import { deriveStakeControllerReservePoolPDA, deriveStakeControllerVaultPDA, getUserLiqsolATA } from './constants';
|
|
14
15
|
import { DistributionClient } from './clients/distribution.client';
|
|
15
|
-
import {
|
|
16
|
+
import { SolanaTransaction } from './types';
|
|
17
|
+
// import { ValidatorLeaderboardClient } from './clients/leaderboard.client';
|
|
16
18
|
|
|
17
19
|
const commitment: Commitment = 'confirmed';
|
|
18
20
|
|
|
19
21
|
export class SolanaStakingClient implements IStakingClient {
|
|
20
22
|
public pubKey: PublicKey;
|
|
21
|
-
public network: ExternalNetwork;
|
|
22
|
-
|
|
23
23
|
public connection: Connection;
|
|
24
24
|
public anchor: AnchorProvider;
|
|
25
25
|
|
|
26
26
|
private depositClient: DepositClient;
|
|
27
27
|
private distributionClient: DistributionClient;
|
|
28
|
-
private leaderboardClient: ValidatorLeaderboardClient;
|
|
29
|
-
|
|
30
|
-
balanceNative: number = 0;
|
|
31
|
-
balanceLiquid: number = 0;
|
|
28
|
+
// private leaderboardClient: ValidatorLeaderboardClient;
|
|
32
29
|
|
|
33
30
|
get solPubKey(): SolPubKey {
|
|
34
31
|
return new SolPubKey(this.pubKey.data.array);
|
|
35
32
|
}
|
|
36
33
|
|
|
34
|
+
get network() { return this.config.network; }
|
|
35
|
+
|
|
37
36
|
constructor(private config: StakerConfig) {
|
|
38
37
|
// 1) unwrap & validate wallet adapter
|
|
39
38
|
const adapter = config.provider as BaseSignerWalletAdapter;
|
|
40
|
-
if (!adapter.publicKey)
|
|
41
|
-
|
|
42
|
-
}
|
|
39
|
+
if (!adapter.publicKey) throw new Error('Solana wallet adapter not connected');
|
|
40
|
+
if (!config.network.rpcUrls.length) throw new Error('No RPC URLs provided');
|
|
43
41
|
|
|
44
42
|
// 2) sanity‐check wire ↔ solana pubkey
|
|
45
43
|
const publicKey = adapter.publicKey;
|
|
@@ -48,10 +46,14 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
48
46
|
throw new Error('Passed-in pubKey doesn\'t match adapter.publicKey');
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
|
|
49
|
+
// build connection config
|
|
50
|
+
let opts: ConnectionConfig = { commitment }
|
|
51
|
+
if (config.network.rpcUrls.length > 1 && config.network.rpcUrls[1].startsWith('ws')) {
|
|
52
|
+
opts.wsEndpoint = config.network.rpcUrls[1];
|
|
53
|
+
}
|
|
54
|
+
|
|
52
55
|
this.pubKey = wirePub;
|
|
53
|
-
this.connection = new Connection(config.network.rpcUrls[0],
|
|
54
|
-
this.setBalances();
|
|
56
|
+
this.connection = new Connection(config.network.rpcUrls[0], opts);
|
|
55
57
|
|
|
56
58
|
const anchorWallet = {
|
|
57
59
|
publicKey,
|
|
@@ -63,27 +65,122 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
63
65
|
},
|
|
64
66
|
};
|
|
65
67
|
|
|
66
|
-
this.anchor = new AnchorProvider(
|
|
67
|
-
this.connection,
|
|
68
|
-
anchorWallet,
|
|
69
|
-
{ commitment }
|
|
70
|
-
);
|
|
68
|
+
this.anchor = new AnchorProvider(this.connection, anchorWallet, { commitment });
|
|
71
69
|
|
|
72
70
|
// 4) staking clients
|
|
73
71
|
this.depositClient = new DepositClient(this.anchor);
|
|
74
72
|
this.distributionClient = new DistributionClient(this.anchor);
|
|
75
|
-
this.leaderboardClient = new ValidatorLeaderboardClient(this.anchor);
|
|
73
|
+
// this.leaderboardClient = new ValidatorLeaderboardClient(this.anchor);
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
77
|
+
* Resolve the user's liqSOL ATA and balances + key protocol balances.
|
|
78
|
+
* native = SOL in wallet
|
|
79
|
+
* actual = liqSOL token balance (from ATA)
|
|
80
|
+
* tracked = liqSOL tracked balance (from Distribution.userRecord)
|
|
81
81
|
*/
|
|
82
|
-
async
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
async getPortfolio(): Promise<Portfolio> {
|
|
83
|
+
const user = this.solPubKey;
|
|
84
|
+
|
|
85
|
+
// Handy PDAs & ATA
|
|
86
|
+
const [reservePoolPDA] = deriveStakeControllerReservePoolPDA();
|
|
87
|
+
const [vaultPDA] = deriveStakeControllerVaultPDA();
|
|
88
|
+
const userLiqsolAta = getUserLiqsolATA(user);
|
|
89
|
+
|
|
90
|
+
// Pull balances in parallel; ATA may not exist yet
|
|
91
|
+
const [nativeLamports, actualBalResp, userRecord] = await Promise.all([
|
|
92
|
+
this.connection.getBalance(user),
|
|
93
|
+
this.connection.getTokenAccountBalance(userLiqsolAta).catch(() => null),
|
|
94
|
+
this.distributionClient.getUserRecord(user).catch(() => null),
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
// Actual (LiqSOL) balance + decimals (fallback to 9 if ATA missing)
|
|
98
|
+
const actualAmountStr = actualBalResp?.value?.amount ?? '0';
|
|
99
|
+
const actualDecimals = actualBalResp?.value?.decimals ?? 9;
|
|
100
|
+
|
|
101
|
+
// Tracked (from userRecord in Distribution program)
|
|
102
|
+
const trackedAmountStr = userRecord?.trackedBalance
|
|
103
|
+
? (userRecord.trackedBalance as any).toString()
|
|
104
|
+
: '0';
|
|
105
|
+
const trackedDecimals = actualDecimals; // same mint as liqSOL
|
|
106
|
+
|
|
107
|
+
// Assemble the portfolio
|
|
108
|
+
const portfolio: Portfolio = {
|
|
109
|
+
native: {
|
|
110
|
+
symbol: 'SOL',
|
|
111
|
+
decimals: 9,
|
|
112
|
+
amount: BigInt(nativeLamports),
|
|
113
|
+
},
|
|
114
|
+
actual: {
|
|
115
|
+
symbol: 'LiqSOL',
|
|
116
|
+
decimals: actualDecimals,
|
|
117
|
+
amount: BigInt(actualAmountStr),
|
|
118
|
+
},
|
|
119
|
+
tracked: {
|
|
120
|
+
symbol: 'LiqSOL',
|
|
121
|
+
decimals: trackedDecimals,
|
|
122
|
+
amount: BigInt(trackedAmountStr),
|
|
123
|
+
},
|
|
124
|
+
extras: {
|
|
125
|
+
userLiqsolAta: userLiqsolAta.toBase58(),
|
|
126
|
+
reservePoolPDA: reservePoolPDA.toBase58(),
|
|
127
|
+
vaultPDA: vaultPDA.toBase58(),
|
|
128
|
+
},
|
|
129
|
+
};
|
|
85
130
|
|
|
86
|
-
|
|
131
|
+
// console.log('>> PORTFOLIO SET', this.network.name, this.portfolio);
|
|
132
|
+
return portfolio;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Optional: fetch your Distribution program user record
|
|
136
|
+
* (often contains per-user deposit/claim state).
|
|
137
|
+
*/
|
|
138
|
+
async getUserRecord(): Promise<any | null> {
|
|
139
|
+
return this.distributionClient.getUserRecord(this.solPubKey);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getProtocolFee() {
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Build, sign, and submit a single transaction that:
|
|
148
|
+
* - Corrects other users (if needed) to free available balance, then
|
|
149
|
+
* - Registers the caller’s untracked liqSOL.
|
|
150
|
+
*
|
|
151
|
+
* @param amount Optional: register a smaller amount than your full untracked balance.
|
|
152
|
+
* @returns signature string
|
|
153
|
+
*/
|
|
154
|
+
async register(amount?: bigint): Promise<string> {
|
|
155
|
+
try {
|
|
156
|
+
console.log('Building CorrectAndRegister transaction with amount:', amount);
|
|
157
|
+
|
|
158
|
+
// Build the transaction using the Distribution client (self = this.solPubKey)
|
|
159
|
+
const build = await this.distributionClient.buildCorrectRegisterTx({ amount });
|
|
160
|
+
if (!build.canSucceed || !build.transaction)
|
|
161
|
+
throw new Error(build.reason ?? 'Unable to build Correct&Register transaction');
|
|
162
|
+
|
|
163
|
+
console.log('buildCorrectRegisterTx:', build);
|
|
164
|
+
|
|
165
|
+
const { tx, blockhash, lastValidBlockHeight } = await this.prepareTx(build.transaction);
|
|
166
|
+
const signed = await this.signTransaction(tx);
|
|
167
|
+
const result = await this.sendAndConfirmHttp(signed, { blockhash, lastValidBlockHeight });
|
|
168
|
+
|
|
169
|
+
// Optionally refresh portfolio after success (non-blocking)
|
|
170
|
+
console.log('Registered:', {
|
|
171
|
+
needToRegister: build.needToRegister,
|
|
172
|
+
freed: build.plan.willFree,
|
|
173
|
+
corrected: build.plan.selected.map(c => ({
|
|
174
|
+
owner: c.owner.toBase58(),
|
|
175
|
+
delta: c.delta.toString(),
|
|
176
|
+
}))
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return result.signature;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.error('Error in register:', error);
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
87
184
|
}
|
|
88
185
|
|
|
89
186
|
/**
|
|
@@ -92,12 +189,35 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
92
189
|
* @returns The transaction signature.
|
|
93
190
|
*/
|
|
94
191
|
async deposit(lamports: number): Promise<string> {
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
192
|
+
const { transaction } = await this.depositClient.buildDepositTx(this.solPubKey, lamports);
|
|
193
|
+
const { tx, blockhash, lastValidBlockHeight } = await this.prepareTx(transaction);
|
|
194
|
+
const signed = await this.signTransaction(tx);
|
|
195
|
+
const result = await this.sendAndConfirmHttp(signed, { blockhash, lastValidBlockHeight });
|
|
196
|
+
return result.signature;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private async sendAndConfirmHttp(
|
|
200
|
+
signed: SolanaTransaction,
|
|
201
|
+
ctx: { blockhash: string; lastValidBlockHeight: number }
|
|
202
|
+
): Promise<TxResult> {
|
|
203
|
+
// sendRawTransaction is HTTP
|
|
204
|
+
const signature = await this.connection.sendRawTransaction(signed.serialize(), {
|
|
205
|
+
skipPreflight: false,
|
|
206
|
+
preflightCommitment: commitment,
|
|
207
|
+
maxRetries: 3,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Poll confirmation using blockhash/lastValidBlockHeight
|
|
211
|
+
const conf = await this.connection.confirmTransaction(
|
|
212
|
+
{ signature, blockhash: ctx.blockhash, lastValidBlockHeight: ctx.lastValidBlockHeight },
|
|
213
|
+
commitment
|
|
98
214
|
);
|
|
99
|
-
|
|
100
|
-
|
|
215
|
+
|
|
216
|
+
const ok = !conf.value.err;
|
|
217
|
+
if (!ok) {
|
|
218
|
+
throw new Error(`Transaction failed: ${JSON.stringify(conf.value.err)}`);
|
|
219
|
+
}
|
|
220
|
+
return { signature, slot: conf.context.slot, confirmed: true };
|
|
101
221
|
}
|
|
102
222
|
|
|
103
223
|
async signTransaction(tx: SolanaTransaction): Promise<SolanaTransaction> {
|
|
@@ -107,4 +227,18 @@ export class SolanaStakingClient implements IStakingClient {
|
|
|
107
227
|
async sendTransaction(signed: SolanaTransaction): Promise<TransactionSignature> {
|
|
108
228
|
return await this.anchor.sendAndConfirm(signed);
|
|
109
229
|
}
|
|
110
|
-
|
|
230
|
+
|
|
231
|
+
async prepareTx(tx: Transaction): Promise<{ tx: Transaction; blockhash: string; lastValidBlockHeight: number }> {
|
|
232
|
+
const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash('confirmed');
|
|
233
|
+
tx.recentBlockhash = blockhash;
|
|
234
|
+
tx.feePayer = this.solPubKey;
|
|
235
|
+
|
|
236
|
+
return { tx, blockhash, lastValidBlockHeight };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export interface TxResult {
|
|
241
|
+
signature: string;
|
|
242
|
+
slot: number;
|
|
243
|
+
confirmed: boolean;
|
|
244
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
|
|
2
|
+
|
|
3
|
+
export type SolanaTransaction = Transaction | VersionedTransaction
|
|
4
|
+
|
|
5
|
+
/** Raw mismatch row (per user with a userRecord) */
|
|
6
|
+
export type MismatchCandidate = {
|
|
7
|
+
/** Wallet that owns the ATA (decoded from token account) */
|
|
8
|
+
owner: PublicKey;
|
|
9
|
+
/** user_record PDA */
|
|
10
|
+
userRecordPda: PublicKey;
|
|
11
|
+
/** user’s ATA for liqSOL */
|
|
12
|
+
userAta: PublicKey;
|
|
13
|
+
/** protocol tracked balance (u64) */
|
|
14
|
+
tracked: bigint;
|
|
15
|
+
/** actual on-chain token balance (u64) */
|
|
16
|
+
actual: bigint;
|
|
17
|
+
/** tracked - actual (positive means “freeable”) */
|
|
18
|
+
delta: bigint;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Output when choosing candidates to free liquidity */
|
|
22
|
+
export type CorrectionPlan = {
|
|
23
|
+
/** selected candidates sorted by delta desc */
|
|
24
|
+
selected: MismatchCandidate[];
|
|
25
|
+
/** total delta we’ll free by correcting selected */
|
|
26
|
+
willFree: bigint;
|
|
27
|
+
/** how much still missing after selection (0 if we can meet the target) */
|
|
28
|
+
deficit: bigint;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** What the builder returns to your caller/UI */
|
|
32
|
+
export type CorrectAndRegisterBuild = {
|
|
33
|
+
/** The ready-to-send transaction (if buildable) */
|
|
34
|
+
transaction?: Transaction;
|
|
35
|
+
/** True if the tx can succeed with current state */
|
|
36
|
+
canSucceed: boolean;
|
|
37
|
+
/** Explanation if not buildable */
|
|
38
|
+
reason?: string;
|
|
39
|
+
|
|
40
|
+
/** Current liqSOL mint; useful for UI */
|
|
41
|
+
liqsolMint: PublicKey;
|
|
42
|
+
/** Amount you need to register (actual - tracked if positive) */
|
|
43
|
+
needToRegister: bigint;
|
|
44
|
+
/** Distribution “availableBalance” before this action */
|
|
45
|
+
availableBefore: bigint;
|
|
46
|
+
|
|
47
|
+
/** Candidates we scanned (already sorted by delta desc) */
|
|
48
|
+
candidates: MismatchCandidate[];
|
|
49
|
+
/** Subset we’d correct (maybe empty) */
|
|
50
|
+
plan: CorrectionPlan;
|
|
51
|
+
|
|
52
|
+
/** Convenience for caller */
|
|
53
|
+
accounts: {
|
|
54
|
+
selfUserRecordPda: PublicKey;
|
|
55
|
+
selfUserAta: PublicKey;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Define variables
|
|
5
|
+
IDL_ZIP_URL="https://bucket.gitgo.app/solana/idl.zip"
|
|
6
|
+
TYPES_ZIP_URL="https://bucket.gitgo.app/solana/types.zip"
|
|
7
|
+
DEST_DIR="$(dirname "$0")/../assets/solana"
|
|
8
|
+
TMP_DIR="$(mktemp -d)"
|
|
9
|
+
|
|
10
|
+
# Download the zip files
|
|
11
|
+
curl -L "$IDL_ZIP_URL" -o "$TMP_DIR/idl.zip"
|
|
12
|
+
curl -L "$TYPES_ZIP_URL" -o "$TMP_DIR/types.zip"
|
|
13
|
+
|
|
14
|
+
# Create destination directory if it doesn't exist
|
|
15
|
+
mkdir -p "$DEST_DIR"
|
|
16
|
+
|
|
17
|
+
# Unzip into the destination directory
|
|
18
|
+
unzip -o "$TMP_DIR/idl.zip" -d "$DEST_DIR"
|
|
19
|
+
unzip -o "$TMP_DIR/types.zip" -d "$DEST_DIR"
|
|
20
|
+
|
|
21
|
+
# Clean up
|
|
22
|
+
rm -rf "$TMP_DIR"
|
|
23
|
+
|
|
24
|
+
echo "IDL and types files fetched and extracted to $DEST_DIR"
|
package/src/staker/staker.ts
CHANGED
|
@@ -1,14 +1,34 @@
|
|
|
1
1
|
// src/staker/staker.ts
|
|
2
2
|
|
|
3
|
-
import { ChainID,
|
|
4
|
-
import { IStakingClient,
|
|
3
|
+
import { ChainID, SolChainID } from '@wireio/core';
|
|
4
|
+
import { IStakingClient, StakerConfig } from './types';
|
|
5
5
|
import { SolanaStakingClient } from '../networks/solana/solana';
|
|
6
|
-
import { EthereumStakingClient } from '../networks/ethereum/ethereum';
|
|
7
6
|
|
|
8
7
|
export class Staker {
|
|
8
|
+
public selectedChainID?: ChainID;
|
|
9
9
|
private clients: Map<ChainID, IStakingClient> = new Map();
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Get the staking client for the currently selected chain.
|
|
13
|
+
* @returns The staking client instance.
|
|
14
|
+
*/
|
|
15
|
+
get client(): IStakingClient | undefined {
|
|
16
|
+
return this.selectedChainID && this.isConfigured(this.selectedChainID)
|
|
17
|
+
? this.clients.get(this.selectedChainID) : undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Is there a client configured for this chain? */
|
|
21
|
+
isConfigured(chainId: ChainID): boolean {
|
|
22
|
+
return this.clients.has(chainId);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** List of configured chains */
|
|
26
|
+
listConfigured(): ChainID[] {
|
|
27
|
+
return [...this.clients.keys()];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
constructor(config: StakerConfig | StakerConfig[], selectedChainID?: ChainID) {
|
|
31
|
+
if (!config) throw new Error('StakerConfig is required');
|
|
12
32
|
if (!Array.isArray(config)) config = [config];
|
|
13
33
|
|
|
14
34
|
config.forEach((cfg) => {
|
|
@@ -21,36 +41,20 @@ export class Staker {
|
|
|
21
41
|
// this.clients.set(EvmChainID.Sepolia, new EthereumStakingClient(cfg));
|
|
22
42
|
// break;
|
|
23
43
|
default:
|
|
24
|
-
|
|
44
|
+
// console.log(`No staking client available for chain ${cfg.network.chainId}`);
|
|
45
|
+
// throw new Error(`Unsupported network curve: ${cfg.network.name}`);
|
|
25
46
|
}
|
|
26
47
|
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Return the raw client (if any) for a chain */
|
|
30
|
-
getClient(chainId: ChainID): IStakingClient | undefined {
|
|
31
|
-
return this.clients.get(chainId);
|
|
32
|
-
}
|
|
33
48
|
|
|
34
|
-
|
|
35
|
-
private ensureClient(chainId: ChainID): IStakingClient {
|
|
36
|
-
const c = this.clients.get(chainId);
|
|
37
|
-
if (!c) throw new Error(`Staker not initialized for chain ${chainId}`);
|
|
38
|
-
return c;
|
|
49
|
+
this.selectedChainID = selectedChainID;
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @param amount The amount to deposit (in smallest unit i.e. Lamport or Wei).
|
|
45
|
-
* @returns The transaction signature.
|
|
53
|
+
* Select a chain. Returns true if a client exists for it, false otherwise.
|
|
54
|
+
* (We still record the selectedChainID so the UI can reflect the chosen chain.)
|
|
46
55
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
setChain(chainID: ChainID): boolean {
|
|
57
|
+
this.selectedChainID = chainID;
|
|
58
|
+
return this.clients.has(chainID);
|
|
49
59
|
}
|
|
50
|
-
|
|
51
|
-
getBalance(chainId: ChainID): Promise<StakeBalance> {
|
|
52
|
-
return this.ensureClient(chainId).setBalances();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// …withdraw, claimRewards, etc…
|
|
56
60
|
}
|
package/src/staker/types.ts
CHANGED
|
@@ -1,41 +1,44 @@
|
|
|
1
1
|
// types.ts
|
|
2
2
|
|
|
3
3
|
import { BaseSignerWalletAdapter } from '@solana/wallet-adapter-base';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { PublicKey as SolPubKey } from '@solana/web3.js';
|
|
5
|
+
import { ExternalNetwork, PublicKey } from '@wireio/core';
|
|
6
6
|
import { ethers } from 'ethers';
|
|
7
7
|
|
|
8
|
-
export
|
|
9
|
-
export interface IStakingClient{
|
|
8
|
+
export interface IStakingClient {
|
|
10
9
|
pubKey: PublicKey;
|
|
11
10
|
network: ExternalNetwork;
|
|
12
11
|
|
|
13
|
-
balanceNative: number;
|
|
14
|
-
balanceLiquid: number;
|
|
15
|
-
|
|
16
12
|
/** Amount is in the chain's smallest unit (lamports/wei, etc.) */
|
|
17
13
|
deposit(amount: number): Promise<string>;
|
|
18
14
|
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// /** Return native balance in the chain’s smallest unit (lamports for Sol) */
|
|
23
|
-
// getBalanceNative(): Promise<number>;
|
|
15
|
+
/** Register any untracked LIQ staked tokens */
|
|
16
|
+
register(): Promise<string>;
|
|
24
17
|
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
/** Fetch the portfolio for the LIQ stake user */
|
|
19
|
+
getPortfolio(): Promise<Portfolio>;
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
/**
|
|
30
|
-
* Union config for our unified Staker
|
|
31
|
-
*/
|
|
32
22
|
export type StakerConfig = {
|
|
33
23
|
network: ExternalNetwork;
|
|
34
24
|
provider: BaseSignerWalletAdapter | ethers.providers.Web3Provider;
|
|
35
25
|
pubKey: PublicKey;
|
|
36
26
|
}
|
|
37
27
|
|
|
38
|
-
export interface
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
28
|
+
export interface Portfolio {
|
|
29
|
+
/** Native SOL balance on chain */
|
|
30
|
+
native: BalanceView;
|
|
31
|
+
/** Actual liquid SOL balance from ATA */
|
|
32
|
+
actual: BalanceView;
|
|
33
|
+
/** Tracked liquid SOL balance from distribution program */
|
|
34
|
+
tracked: BalanceView;
|
|
35
|
+
/** Extra PDAs and account addresses */
|
|
36
|
+
extras?: Record<string, any>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type BalanceView = {
|
|
40
|
+
amount: bigint; // raw on-chain integer value
|
|
41
|
+
decimals: number; // number of decimal places
|
|
42
|
+
symbol?: string; // optional token symbol identifier
|
|
43
|
+
ata?: SolPubKey; // associated token account address
|
|
44
|
+
};
|