@synapseia-network/node 0.8.5
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/LICENSE +105 -0
- package/README.md +232 -0
- package/dist/bid-responder-Q725ZIUC.js +86 -0
- package/dist/bootstrap.js +22 -0
- package/dist/chain-info-lightweight-2UWAQZBF.js +303 -0
- package/dist/chat-stream-handler-BSHSGMFF.js +127 -0
- package/dist/chunk-2X7MSWD4.js +270 -0
- package/dist/chunk-3BHRQWSM.js +531 -0
- package/dist/chunk-5QFTU52A.js +442 -0
- package/dist/chunk-5ZAJBIAV.js +25 -0
- package/dist/chunk-7FLDR5NT.js +186 -0
- package/dist/chunk-C5XRYLYP.js +137 -0
- package/dist/chunk-D7ADMHK2.js +36 -0
- package/dist/chunk-DXUYWRO7.js +23 -0
- package/dist/chunk-F5UDK56Z.js +289 -0
- package/dist/chunk-NEHR6XY7.js +111 -0
- package/dist/chunk-NMJVODKH.js +453 -0
- package/dist/chunk-PRVT22SM.js +324 -0
- package/dist/chunk-T2ZRG5CX.js +1380 -0
- package/dist/chunk-V2L5SXTL.js +88 -0
- package/dist/chunk-XL2NJWFY.js +702 -0
- package/dist/embedding-C6GE3WVM.js +16 -0
- package/dist/hardware-ITQQJ5YI.js +37 -0
- package/dist/index.js +16836 -0
- package/dist/inference-server-CIGRJ36H.js +25 -0
- package/dist/local-cors-J6RWNMMD.js +44 -0
- package/dist/model-catalog-C53SDFMG.js +15 -0
- package/dist/model-discovery-LA6YMT3I.js +10 -0
- package/dist/ollama-XVXA3A37.js +9 -0
- package/dist/rewards-vault-cli-HW7H4EMD.js +147 -0
- package/dist/scripts/create_nodes.sh +6 -0
- package/dist/scripts/diloco_train.py +319 -0
- package/dist/scripts/train_lora.py +237 -0
- package/dist/scripts/train_micro.py +586 -0
- package/dist/trainer-HQMV2ZAR.js +21 -0
- package/package.json +128 -0
- package/scripts/create_nodes.sh +6 -0
- package/scripts/diloco_train.py +319 -0
- package/scripts/train_lora.py +237 -0
- package/scripts/train_micro.py +586 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
import { fileURLToPath as __synFup } from "url";import { dirname as __synDn } from "path";const __filename = __synFup(import.meta.url);const __dirname = __synDn(__filename);
|
|
2
|
+
import {
|
|
3
|
+
init_logger,
|
|
4
|
+
logger_default
|
|
5
|
+
} from "./chunk-V2L5SXTL.js";
|
|
6
|
+
import {
|
|
7
|
+
__name
|
|
8
|
+
} from "./chunk-D7ADMHK2.js";
|
|
9
|
+
|
|
10
|
+
// src/modules/staking/staking-cli.ts
|
|
11
|
+
init_logger();
|
|
12
|
+
import { Connection, PublicKey, Keypair, Transaction, TransactionInstruction, SystemProgram, ComputeBudgetProgram } from "@solana/web3.js";
|
|
13
|
+
import { getAssociatedTokenAddress, TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, createTransferInstruction } from "@solana/spl-token";
|
|
14
|
+
import * as fs from "fs";
|
|
15
|
+
import * as path from "path";
|
|
16
|
+
import * as os from "os";
|
|
17
|
+
import * as crypto from "crypto";
|
|
18
|
+
import { password } from "@inquirer/prompts";
|
|
19
|
+
var DEFAULT_CU_LIMIT = 14e5;
|
|
20
|
+
var DEFAULT_CU_PRICE_MICROLAMPORTS = 1e4;
|
|
21
|
+
function requireEnvPublicKey(key) {
|
|
22
|
+
const val = process.env[key];
|
|
23
|
+
if (!val) throw new Error(`${key} not informed`);
|
|
24
|
+
return new PublicKey(val);
|
|
25
|
+
}
|
|
26
|
+
__name(requireEnvPublicKey, "requireEnvPublicKey");
|
|
27
|
+
function requireEnv(key, fallback) {
|
|
28
|
+
const val = process.env[key];
|
|
29
|
+
if (!val && fallback === void 0) throw new Error(`${key} not informed`);
|
|
30
|
+
return val ?? fallback;
|
|
31
|
+
}
|
|
32
|
+
__name(requireEnv, "requireEnv");
|
|
33
|
+
var getStakingProgramId = /* @__PURE__ */ __name(() => requireEnvPublicKey("STAKING_PROGRAM_ID"), "getStakingProgramId");
|
|
34
|
+
var getSynMint = /* @__PURE__ */ __name(() => requireEnvPublicKey("SYN_TOKEN_MINT"), "getSynMint");
|
|
35
|
+
var getSolanaRpcUrl = /* @__PURE__ */ __name(() => requireEnv("SOLANA_RPC_URL"), "getSolanaRpcUrl");
|
|
36
|
+
var COORDINATOR_URL = process.env.COORDINATOR_URL || "http://localhost:3701";
|
|
37
|
+
var TOKEN_PROGRAM = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
|
|
38
|
+
var _STAKING_PROGRAM_ID = null;
|
|
39
|
+
var _SYN_MINT = null;
|
|
40
|
+
var _SOLANA_RPC_URL = null;
|
|
41
|
+
var STAKING_PROGRAM_ID = /* @__PURE__ */ __name(() => _STAKING_PROGRAM_ID ??= getStakingProgramId(), "STAKING_PROGRAM_ID");
|
|
42
|
+
var SYN_MINT = /* @__PURE__ */ __name(() => _SYN_MINT ??= getSynMint(), "SYN_MINT");
|
|
43
|
+
var SOLANA_RPC_URL_GETTER = /* @__PURE__ */ __name(() => _SOLANA_RPC_URL ??= getSolanaRpcUrl(), "SOLANA_RPC_URL_GETTER");
|
|
44
|
+
function getVaultAuthorityPDA() {
|
|
45
|
+
return PublicKey.findProgramAddressSync([
|
|
46
|
+
Buffer.from("stake_vault_authority")
|
|
47
|
+
], STAKING_PROGRAM_ID());
|
|
48
|
+
}
|
|
49
|
+
__name(getVaultAuthorityPDA, "getVaultAuthorityPDA");
|
|
50
|
+
function getStakingPoolPDA() {
|
|
51
|
+
return PublicKey.findProgramAddressSync([
|
|
52
|
+
Buffer.from("staking_pool")
|
|
53
|
+
], STAKING_PROGRAM_ID());
|
|
54
|
+
}
|
|
55
|
+
__name(getStakingPoolPDA, "getStakingPoolPDA");
|
|
56
|
+
function isAlreadyProcessedError(err) {
|
|
57
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
58
|
+
return /already been processed|already processed/i.test(msg);
|
|
59
|
+
}
|
|
60
|
+
__name(isAlreadyProcessedError, "isAlreadyProcessedError");
|
|
61
|
+
async function sendAndConfirmFresh(connection, tx, signers) {
|
|
62
|
+
const payer = signers[0];
|
|
63
|
+
if (!payer) throw new Error("sendAndConfirmFresh: at least one signer required");
|
|
64
|
+
const hasCuIx = tx.instructions.some((ix) => ix.programId.equals(ComputeBudgetProgram.programId));
|
|
65
|
+
if (!hasCuIx) {
|
|
66
|
+
tx.instructions = [
|
|
67
|
+
ComputeBudgetProgram.setComputeUnitPrice({
|
|
68
|
+
microLamports: DEFAULT_CU_PRICE_MICROLAMPORTS
|
|
69
|
+
}),
|
|
70
|
+
ComputeBudgetProgram.setComputeUnitLimit({
|
|
71
|
+
units: DEFAULT_CU_LIMIT
|
|
72
|
+
}),
|
|
73
|
+
...tx.instructions
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
|
|
77
|
+
tx.recentBlockhash = blockhash;
|
|
78
|
+
tx.feePayer = payer.publicKey;
|
|
79
|
+
tx.sign(...signers);
|
|
80
|
+
try {
|
|
81
|
+
const sig = await connection.sendRawTransaction(tx.serialize(), {
|
|
82
|
+
skipPreflight: false,
|
|
83
|
+
preflightCommitment: "confirmed"
|
|
84
|
+
});
|
|
85
|
+
await connection.confirmTransaction({
|
|
86
|
+
signature: sig,
|
|
87
|
+
blockhash,
|
|
88
|
+
lastValidBlockHeight
|
|
89
|
+
}, "confirmed");
|
|
90
|
+
return sig;
|
|
91
|
+
} catch (err) {
|
|
92
|
+
if (isAlreadyProcessedError(err)) {
|
|
93
|
+
logger_default.warn('[staking-cli] tx flagged "already been processed" \u2014 first submission already landed, returning existing signature');
|
|
94
|
+
const s = tx.signatures[0]?.signature;
|
|
95
|
+
return s ? s.toString("base64") : "";
|
|
96
|
+
}
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
__name(sendAndConfirmFresh, "sendAndConfirmFresh");
|
|
101
|
+
async function getStakeVaultATA(connection) {
|
|
102
|
+
const [vaultAuthority] = getVaultAuthorityPDA();
|
|
103
|
+
return getAssociatedTokenAddress(SYN_MINT(), vaultAuthority, true);
|
|
104
|
+
}
|
|
105
|
+
__name(getStakeVaultATA, "getStakeVaultATA");
|
|
106
|
+
function getTreasuryAuthorityPDA() {
|
|
107
|
+
return PublicKey.findProgramAddressSync([
|
|
108
|
+
Buffer.from("treasury_authority")
|
|
109
|
+
], STAKING_PROGRAM_ID());
|
|
110
|
+
}
|
|
111
|
+
__name(getTreasuryAuthorityPDA, "getTreasuryAuthorityPDA");
|
|
112
|
+
async function getTreasuryTokenAccount(connection) {
|
|
113
|
+
const [treasuryAuthority] = getTreasuryAuthorityPDA();
|
|
114
|
+
return getAssociatedTokenAddress(SYN_MINT(), treasuryAuthority, true);
|
|
115
|
+
}
|
|
116
|
+
__name(getTreasuryTokenAccount, "getTreasuryTokenAccount");
|
|
117
|
+
var WALLET_DIR = /* @__PURE__ */ __name(() => process.env.SYNAPSEIA_HOME || path.join(os.homedir(), ".synapseia"), "WALLET_DIR");
|
|
118
|
+
var WALLET_FILE = /* @__PURE__ */ __name(() => path.join(WALLET_DIR(), "wallet.json"), "WALLET_FILE");
|
|
119
|
+
var PBKDF2_ITERATIONS = 1e5;
|
|
120
|
+
var KEY_LENGTH = 32;
|
|
121
|
+
var IV_LENGTH = 16;
|
|
122
|
+
var SALT_LENGTH = 32;
|
|
123
|
+
var AUTH_TAG_LENGTH = 16;
|
|
124
|
+
function deriveKey(password2, salt) {
|
|
125
|
+
return crypto.pbkdf2Sync(password2, salt, PBKDF2_ITERATIONS, KEY_LENGTH, "sha256");
|
|
126
|
+
}
|
|
127
|
+
__name(deriveKey, "deriveKey");
|
|
128
|
+
function decryptWallet(encryptedData, password2) {
|
|
129
|
+
const combined = Buffer.from(encryptedData, "base64");
|
|
130
|
+
const salt = combined.subarray(0, SALT_LENGTH);
|
|
131
|
+
const iv = combined.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
|
|
132
|
+
const authTag = combined.subarray(SALT_LENGTH + IV_LENGTH, SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH);
|
|
133
|
+
const ciphertext = combined.subarray(SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH);
|
|
134
|
+
const key = deriveKey(password2, salt);
|
|
135
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
|
|
136
|
+
decipher.setAuthTag(authTag);
|
|
137
|
+
const decrypted = Buffer.concat([
|
|
138
|
+
decipher.update(ciphertext),
|
|
139
|
+
decipher.final()
|
|
140
|
+
]);
|
|
141
|
+
return new Uint8Array(decrypted);
|
|
142
|
+
}
|
|
143
|
+
__name(decryptWallet, "decryptWallet");
|
|
144
|
+
async function loadWalletWithPassword() {
|
|
145
|
+
const walletFile = WALLET_FILE();
|
|
146
|
+
if (!fs.existsSync(walletFile)) {
|
|
147
|
+
throw new Error(`Wallet not found at ${walletFile}. Run 'synapseia-node setup' first.`);
|
|
148
|
+
}
|
|
149
|
+
const walletData = JSON.parse(fs.readFileSync(walletFile, "utf-8"));
|
|
150
|
+
if (!walletData.encryptedData) {
|
|
151
|
+
const secretKey = new Uint8Array(walletData.secretKey);
|
|
152
|
+
return Keypair.fromSecretKey(secretKey);
|
|
153
|
+
}
|
|
154
|
+
const envPassword = process.env.SYNAPSEIA_WALLET_PASSWORD ?? process.env.WALLET_PASSWORD;
|
|
155
|
+
const walletPassword = envPassword ? envPassword : await password({
|
|
156
|
+
message: "Enter wallet password:",
|
|
157
|
+
mask: "*"
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
const secretKey = decryptWallet(walletData.encryptedData, walletPassword);
|
|
161
|
+
return Keypair.fromSecretKey(secretKey);
|
|
162
|
+
} catch (e) {
|
|
163
|
+
throw new Error("Invalid password or corrupted wallet file");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
__name(loadWalletWithPassword, "loadWalletWithPassword");
|
|
167
|
+
async function getUserTokenAccount(connection, wallet) {
|
|
168
|
+
return getAssociatedTokenAddress(SYN_MINT(), wallet);
|
|
169
|
+
}
|
|
170
|
+
__name(getUserTokenAccount, "getUserTokenAccount");
|
|
171
|
+
function createStakeInstructionData(amount) {
|
|
172
|
+
const discriminator = Buffer.from([
|
|
173
|
+
206,
|
|
174
|
+
176,
|
|
175
|
+
202,
|
|
176
|
+
18,
|
|
177
|
+
200,
|
|
178
|
+
209,
|
|
179
|
+
179,
|
|
180
|
+
108
|
|
181
|
+
]);
|
|
182
|
+
const amountBuffer = Buffer.alloc(8);
|
|
183
|
+
amountBuffer.writeBigUInt64LE(BigInt(Math.floor(amount * 1e9)));
|
|
184
|
+
return Buffer.concat([
|
|
185
|
+
discriminator,
|
|
186
|
+
amountBuffer
|
|
187
|
+
]);
|
|
188
|
+
}
|
|
189
|
+
__name(createStakeInstructionData, "createStakeInstructionData");
|
|
190
|
+
function createUnstakeInstructionData(amount) {
|
|
191
|
+
const discriminator = Buffer.from([
|
|
192
|
+
90,
|
|
193
|
+
95,
|
|
194
|
+
107,
|
|
195
|
+
42,
|
|
196
|
+
205,
|
|
197
|
+
124,
|
|
198
|
+
50,
|
|
199
|
+
225
|
|
200
|
+
]);
|
|
201
|
+
const amountBuffer = Buffer.alloc(8);
|
|
202
|
+
amountBuffer.writeBigUInt64LE(BigInt(Math.floor(amount * 1e9)));
|
|
203
|
+
return Buffer.concat([
|
|
204
|
+
discriminator,
|
|
205
|
+
amountBuffer
|
|
206
|
+
]);
|
|
207
|
+
}
|
|
208
|
+
__name(createUnstakeInstructionData, "createUnstakeInstructionData");
|
|
209
|
+
function createInitializeStakeInstructionData(tier) {
|
|
210
|
+
const discriminator = Buffer.from([
|
|
211
|
+
33,
|
|
212
|
+
175,
|
|
213
|
+
216,
|
|
214
|
+
4,
|
|
215
|
+
116,
|
|
216
|
+
130,
|
|
217
|
+
164,
|
|
218
|
+
177
|
|
219
|
+
]);
|
|
220
|
+
const tierBuffer = Buffer.alloc(1);
|
|
221
|
+
tierBuffer.writeUInt8(tier);
|
|
222
|
+
return Buffer.concat([
|
|
223
|
+
discriminator,
|
|
224
|
+
tierBuffer
|
|
225
|
+
]);
|
|
226
|
+
}
|
|
227
|
+
__name(createInitializeStakeInstructionData, "createInitializeStakeInstructionData");
|
|
228
|
+
function createClaimRewardsInstructionData() {
|
|
229
|
+
return Buffer.from([
|
|
230
|
+
4,
|
|
231
|
+
144,
|
|
232
|
+
132,
|
|
233
|
+
71,
|
|
234
|
+
116,
|
|
235
|
+
23,
|
|
236
|
+
151,
|
|
237
|
+
80
|
|
238
|
+
]);
|
|
239
|
+
}
|
|
240
|
+
__name(createClaimRewardsInstructionData, "createClaimRewardsInstructionData");
|
|
241
|
+
async function stakeTokens(amount) {
|
|
242
|
+
logger_default.log(`
|
|
243
|
+
\u{1F504} Connecting to Solana...`);
|
|
244
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
245
|
+
const wallet = await loadWalletWithPassword();
|
|
246
|
+
logger_default.log(`\u2705 Connected. Wallet: ${wallet.publicKey.toBase58()}`);
|
|
247
|
+
const stakeAccountAddress = await findStakeAccount(connection, wallet.publicKey);
|
|
248
|
+
let stakeAccount;
|
|
249
|
+
let stakeAccountPubkey;
|
|
250
|
+
if (!stakeAccountAddress) {
|
|
251
|
+
logger_default.log(`\u{1F4DD} Creating new stake account...`);
|
|
252
|
+
stakeAccount = Keypair.generate();
|
|
253
|
+
stakeAccountPubkey = stakeAccount.publicKey;
|
|
254
|
+
const coordInfoRes = await fetch(`${COORDINATOR_URL}/stake/info/coordinator-authority`);
|
|
255
|
+
if (!coordInfoRes.ok) throw new Error(`Failed to get coordinator authority: ${coordInfoRes.status}`);
|
|
256
|
+
const { coordinatorAuthority } = await coordInfoRes.json();
|
|
257
|
+
const initIx = new TransactionInstruction({
|
|
258
|
+
programId: STAKING_PROGRAM_ID(),
|
|
259
|
+
data: createInitializeStakeInstructionData(1),
|
|
260
|
+
keys: [
|
|
261
|
+
{
|
|
262
|
+
pubkey: stakeAccount.publicKey,
|
|
263
|
+
isSigner: true,
|
|
264
|
+
isWritable: true
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
pubkey: wallet.publicKey,
|
|
268
|
+
isSigner: true,
|
|
269
|
+
isWritable: true
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
pubkey: new PublicKey(coordinatorAuthority),
|
|
273
|
+
isSigner: false,
|
|
274
|
+
isWritable: false
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
pubkey: SystemProgram.programId,
|
|
278
|
+
isSigner: false,
|
|
279
|
+
isWritable: false
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
});
|
|
283
|
+
const initTx = new Transaction().add(initIx);
|
|
284
|
+
const initSig = await sendAndConfirmFresh(connection, initTx, [
|
|
285
|
+
wallet,
|
|
286
|
+
stakeAccount
|
|
287
|
+
]);
|
|
288
|
+
logger_default.log(` Stake account created: ${initSig}`);
|
|
289
|
+
} else {
|
|
290
|
+
stakeAccountPubkey = new PublicKey(stakeAccountAddress);
|
|
291
|
+
}
|
|
292
|
+
const userTokenAccount = await getUserTokenAccount(connection, wallet.publicKey);
|
|
293
|
+
const stakeVault = await getStakeVaultATA(connection);
|
|
294
|
+
const [vaultAuthority] = getVaultAuthorityPDA();
|
|
295
|
+
const [stakingPool] = getStakingPoolPDA();
|
|
296
|
+
logger_default.log(`
|
|
297
|
+
\u{1F4E4} Staking ${amount} SYN tokens...`);
|
|
298
|
+
const stakeIx = new TransactionInstruction({
|
|
299
|
+
programId: STAKING_PROGRAM_ID(),
|
|
300
|
+
data: createStakeInstructionData(amount),
|
|
301
|
+
keys: [
|
|
302
|
+
{
|
|
303
|
+
pubkey: stakeAccountPubkey,
|
|
304
|
+
isSigner: false,
|
|
305
|
+
isWritable: true
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
pubkey: wallet.publicKey,
|
|
309
|
+
isSigner: true,
|
|
310
|
+
isWritable: true
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
pubkey: userTokenAccount,
|
|
314
|
+
isSigner: false,
|
|
315
|
+
isWritable: true
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
pubkey: stakeVault,
|
|
319
|
+
isSigner: false,
|
|
320
|
+
isWritable: true
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
pubkey: SYN_MINT(),
|
|
324
|
+
isSigner: false,
|
|
325
|
+
isWritable: false
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
pubkey: vaultAuthority,
|
|
329
|
+
isSigner: false,
|
|
330
|
+
isWritable: false
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
pubkey: TOKEN_PROGRAM,
|
|
334
|
+
isSigner: false,
|
|
335
|
+
isWritable: false
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
pubkey: stakingPool,
|
|
339
|
+
isSigner: false,
|
|
340
|
+
isWritable: true
|
|
341
|
+
}
|
|
342
|
+
]
|
|
343
|
+
});
|
|
344
|
+
const stakeTx = new Transaction().add(stakeIx);
|
|
345
|
+
const tx = await sendAndConfirmFresh(connection, stakeTx, [
|
|
346
|
+
wallet
|
|
347
|
+
]);
|
|
348
|
+
logger_default.log(`\u2705 Stake successful!`);
|
|
349
|
+
logger_default.log(` Transaction: ${tx}`);
|
|
350
|
+
return tx;
|
|
351
|
+
}
|
|
352
|
+
__name(stakeTokens, "stakeTokens");
|
|
353
|
+
async function unstakeTokens(amount) {
|
|
354
|
+
logger_default.log(`
|
|
355
|
+
\u{1F504} Connecting to Solana...`);
|
|
356
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
357
|
+
const wallet = await loadWalletWithPassword();
|
|
358
|
+
logger_default.log(`\u2705 Connected. Wallet: ${wallet.publicKey.toBase58()}`);
|
|
359
|
+
const stakeAccountAddress = await findStakeAccount(connection, wallet.publicKey);
|
|
360
|
+
if (!stakeAccountAddress) {
|
|
361
|
+
throw new Error("No stake account found. Have you staked any tokens?");
|
|
362
|
+
}
|
|
363
|
+
const stakeAccount = new PublicKey(stakeAccountAddress);
|
|
364
|
+
const userTokenAccount = await getUserTokenAccount(connection, wallet.publicKey);
|
|
365
|
+
const stakeVault = await getStakeVaultATA(connection);
|
|
366
|
+
const [vaultAuthority] = getVaultAuthorityPDA();
|
|
367
|
+
const [stakingPool] = getStakingPoolPDA();
|
|
368
|
+
logger_default.log(`
|
|
369
|
+
\u{1F4E5} Unstaking ${amount} SYN tokens...`);
|
|
370
|
+
const unstakeIx = new TransactionInstruction({
|
|
371
|
+
programId: STAKING_PROGRAM_ID(),
|
|
372
|
+
data: createUnstakeInstructionData(amount),
|
|
373
|
+
keys: [
|
|
374
|
+
{
|
|
375
|
+
pubkey: stakeAccount,
|
|
376
|
+
isSigner: false,
|
|
377
|
+
isWritable: true
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
pubkey: wallet.publicKey,
|
|
381
|
+
isSigner: true,
|
|
382
|
+
isWritable: true
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
pubkey: userTokenAccount,
|
|
386
|
+
isSigner: false,
|
|
387
|
+
isWritable: true
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
pubkey: stakeVault,
|
|
391
|
+
isSigner: false,
|
|
392
|
+
isWritable: true
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
pubkey: SYN_MINT(),
|
|
396
|
+
isSigner: false,
|
|
397
|
+
isWritable: false
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
pubkey: vaultAuthority,
|
|
401
|
+
isSigner: false,
|
|
402
|
+
isWritable: false
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
pubkey: TOKEN_PROGRAM,
|
|
406
|
+
isSigner: false,
|
|
407
|
+
isWritable: false
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
pubkey: stakingPool,
|
|
411
|
+
isSigner: false,
|
|
412
|
+
isWritable: true
|
|
413
|
+
}
|
|
414
|
+
]
|
|
415
|
+
});
|
|
416
|
+
const unstakeTx = new Transaction().add(unstakeIx);
|
|
417
|
+
const tx = await sendAndConfirmFresh(connection, unstakeTx, [
|
|
418
|
+
wallet
|
|
419
|
+
]);
|
|
420
|
+
logger_default.log(`\u2705 Unstake successful!`);
|
|
421
|
+
logger_default.log(` Transaction: ${tx}`);
|
|
422
|
+
return tx;
|
|
423
|
+
}
|
|
424
|
+
__name(unstakeTokens, "unstakeTokens");
|
|
425
|
+
async function claimStakingRewards() {
|
|
426
|
+
logger_default.log(`
|
|
427
|
+
\u{1F504} Connecting to Solana...`);
|
|
428
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
429
|
+
const wallet = await loadWalletWithPassword();
|
|
430
|
+
logger_default.log(`\u2705 Connected. Wallet: ${wallet.publicKey.toBase58()}`);
|
|
431
|
+
const stakeAccountAddress = await findStakeAccount(connection, wallet.publicKey);
|
|
432
|
+
if (!stakeAccountAddress) {
|
|
433
|
+
throw new Error("No stake account found. Have you staked any tokens?");
|
|
434
|
+
}
|
|
435
|
+
const accountInfo = await connection.getAccountInfo(new PublicKey(stakeAccountAddress));
|
|
436
|
+
if (!accountInfo) {
|
|
437
|
+
throw new Error("Stake account not found on chain");
|
|
438
|
+
}
|
|
439
|
+
const data = accountInfo.data;
|
|
440
|
+
const rewardsPending = data.readBigUInt64LE(170);
|
|
441
|
+
const rewards = Number(rewardsPending) / 1e9;
|
|
442
|
+
if (rewards <= 0) {
|
|
443
|
+
logger_default.log(`\u2139\uFE0F No pending rewards to claim.`);
|
|
444
|
+
return "";
|
|
445
|
+
}
|
|
446
|
+
logger_default.log(`
|
|
447
|
+
\u{1F4B0} Claiming ${rewards} SYN in rewards...`);
|
|
448
|
+
const userTokenAccount = await getUserTokenAccount(connection, wallet.publicKey);
|
|
449
|
+
const [treasuryAuthority] = getTreasuryAuthorityPDA();
|
|
450
|
+
const treasuryTokenAccount = await getTreasuryTokenAccount(connection);
|
|
451
|
+
const [stakingPool] = getStakingPoolPDA();
|
|
452
|
+
const preIxs = [];
|
|
453
|
+
const treasuryAtaInfo = await connection.getAccountInfo(treasuryTokenAccount);
|
|
454
|
+
if (!treasuryAtaInfo) {
|
|
455
|
+
const { createAssociatedTokenAccountInstruction } = await import("@solana/spl-token");
|
|
456
|
+
preIxs.push(createAssociatedTokenAccountInstruction(wallet.publicKey, treasuryTokenAccount, treasuryAuthority, SYN_MINT(), TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID));
|
|
457
|
+
logger_default.log(` Treasury ATA missing \u2014 will create it in the same tx`);
|
|
458
|
+
}
|
|
459
|
+
const claimIx = new TransactionInstruction({
|
|
460
|
+
programId: STAKING_PROGRAM_ID(),
|
|
461
|
+
data: createClaimRewardsInstructionData(),
|
|
462
|
+
keys: [
|
|
463
|
+
{
|
|
464
|
+
pubkey: new PublicKey(stakeAccountAddress),
|
|
465
|
+
isSigner: false,
|
|
466
|
+
isWritable: true
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
pubkey: wallet.publicKey,
|
|
470
|
+
isSigner: true,
|
|
471
|
+
isWritable: true
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
pubkey: userTokenAccount,
|
|
475
|
+
isSigner: false,
|
|
476
|
+
isWritable: true
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
pubkey: treasuryTokenAccount,
|
|
480
|
+
isSigner: false,
|
|
481
|
+
isWritable: true
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
pubkey: treasuryAuthority,
|
|
485
|
+
isSigner: false,
|
|
486
|
+
isWritable: false
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
pubkey: SYN_MINT(),
|
|
490
|
+
isSigner: false,
|
|
491
|
+
isWritable: false
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
pubkey: TOKEN_PROGRAM,
|
|
495
|
+
isSigner: false,
|
|
496
|
+
isWritable: false
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
pubkey: stakingPool,
|
|
500
|
+
isSigner: false,
|
|
501
|
+
isWritable: false
|
|
502
|
+
}
|
|
503
|
+
]
|
|
504
|
+
});
|
|
505
|
+
const claimTx = new Transaction().add(...preIxs, claimIx);
|
|
506
|
+
const tx = await sendAndConfirmFresh(connection, claimTx, [
|
|
507
|
+
wallet
|
|
508
|
+
]);
|
|
509
|
+
logger_default.log(`\u2705 Rewards claimed!`);
|
|
510
|
+
logger_default.log(` Transaction: ${tx}`);
|
|
511
|
+
return tx;
|
|
512
|
+
}
|
|
513
|
+
__name(claimStakingRewards, "claimStakingRewards");
|
|
514
|
+
async function depositSol(amount) {
|
|
515
|
+
logger_default.log(`
|
|
516
|
+
\u{1F504} Connecting to Solana...`);
|
|
517
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
518
|
+
const wallet = await loadWalletWithPassword();
|
|
519
|
+
logger_default.log(`\u2705 Connected. Wallet: ${wallet.publicKey.toBase58()}`);
|
|
520
|
+
const airdropAmount = Math.floor(amount * 1e9);
|
|
521
|
+
logger_default.log(`
|
|
522
|
+
\u{1F4B8} Requesting ${amount} SOL airdrop...`);
|
|
523
|
+
try {
|
|
524
|
+
const airdropSig = await connection.requestAirdrop(wallet.publicKey, airdropAmount);
|
|
525
|
+
await connection.confirmTransaction(airdropSig);
|
|
526
|
+
logger_default.log(`\u2705 Airdrop successful!`);
|
|
527
|
+
logger_default.log(` Transaction: ${airdropSig}`);
|
|
528
|
+
return airdropSig;
|
|
529
|
+
} catch (e) {
|
|
530
|
+
logger_default.log(`\u26A0\uFE0F Airdrop not available on this network`);
|
|
531
|
+
logger_default.log(` Send SOL to: ${wallet.publicKey.toBase58()}`);
|
|
532
|
+
throw e;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
__name(depositSol, "depositSol");
|
|
536
|
+
async function depositSyn(amount) {
|
|
537
|
+
logger_default.log(`
|
|
538
|
+
\u{1F504} Connecting to Solana...`);
|
|
539
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
540
|
+
const wallet = await loadWalletWithPassword();
|
|
541
|
+
logger_default.log(`\u2705 Connected. Wallet: ${wallet.publicKey.toBase58()}`);
|
|
542
|
+
const userTokenAccount = await getUserTokenAccount(connection, wallet.publicKey);
|
|
543
|
+
logger_default.log(`
|
|
544
|
+
\u{1F4E5} To deposit SYN, send tokens to your token account:`);
|
|
545
|
+
logger_default.log(` Address: ${userTokenAccount.toBase58()}`);
|
|
546
|
+
logger_default.log(` (This is your ATA - Associated Token Account for SYN)`);
|
|
547
|
+
const balance = await connection.getTokenAccountBalance(userTokenAccount).catch(() => null);
|
|
548
|
+
if (balance) {
|
|
549
|
+
logger_default.log(` Current balance: ${Number(balance.value.uiAmountString)} SYN`);
|
|
550
|
+
}
|
|
551
|
+
return "";
|
|
552
|
+
}
|
|
553
|
+
__name(depositSyn, "depositSyn");
|
|
554
|
+
async function withdrawSol(amount, destinationAddress) {
|
|
555
|
+
logger_default.log(`
|
|
556
|
+
\u{1F504} Connecting to Solana...`);
|
|
557
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
558
|
+
const wallet = await loadWalletWithPassword();
|
|
559
|
+
logger_default.log(`\u2705 Connected. Wallet: ${wallet.publicKey.toBase58()}`);
|
|
560
|
+
const destination = new PublicKey(destinationAddress);
|
|
561
|
+
const amountLamports = Math.floor(amount * 1e9);
|
|
562
|
+
const minBalance = await connection.getMinimumBalanceForRentExemption(0);
|
|
563
|
+
const balance = await connection.getBalance(wallet.publicKey);
|
|
564
|
+
if (balance - amountLamports < minBalance) {
|
|
565
|
+
throw new Error(`Cannot withdraw ${amount} SOL. Need to keep ~0.01 SOL for rent.`);
|
|
566
|
+
}
|
|
567
|
+
logger_default.log(`
|
|
568
|
+
\u{1F4E4} Withdrawing ${amount} SOL to ${destinationAddress}...`);
|
|
569
|
+
const tx = new Transaction().add(SystemProgram.transfer({
|
|
570
|
+
fromPubkey: wallet.publicKey,
|
|
571
|
+
toPubkey: destination,
|
|
572
|
+
lamports: amountLamports
|
|
573
|
+
}));
|
|
574
|
+
const signature = await sendAndConfirmFresh(connection, tx, [
|
|
575
|
+
wallet
|
|
576
|
+
]);
|
|
577
|
+
logger_default.log(`\u2705 Withdraw successful!`);
|
|
578
|
+
logger_default.log(` Transaction: ${signature}`);
|
|
579
|
+
return signature;
|
|
580
|
+
}
|
|
581
|
+
__name(withdrawSol, "withdrawSol");
|
|
582
|
+
async function withdrawSyn(amount, destinationAddress) {
|
|
583
|
+
logger_default.log(`
|
|
584
|
+
\u{1F504} Connecting to Solana...`);
|
|
585
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
586
|
+
const wallet = await loadWalletWithPassword();
|
|
587
|
+
logger_default.log(`\u2705 Connected. Wallet: ${wallet.publicKey.toBase58()}`);
|
|
588
|
+
const destination = new PublicKey(destinationAddress);
|
|
589
|
+
const sourceTokenAccount = await getAssociatedTokenAddress(SYN_MINT(), wallet.publicKey);
|
|
590
|
+
let destTokenAccount;
|
|
591
|
+
try {
|
|
592
|
+
destTokenAccount = await getAssociatedTokenAddress(SYN_MINT(), destination);
|
|
593
|
+
const destAccountInfo = await connection.getAccountInfo(destTokenAccount);
|
|
594
|
+
if (!destAccountInfo) {
|
|
595
|
+
logger_default.log(`
|
|
596
|
+
\u{1F4DD} Creating destination token account...`);
|
|
597
|
+
}
|
|
598
|
+
} catch (e) {
|
|
599
|
+
destTokenAccount = await getAssociatedTokenAddress(SYN_MINT(), destination, true);
|
|
600
|
+
}
|
|
601
|
+
const amountLamports = Math.floor(amount * 1e9);
|
|
602
|
+
logger_default.log(`
|
|
603
|
+
\u{1F4E4} Withdrawing ${amount} SYN to ${destinationAddress}...`);
|
|
604
|
+
const transferIx = createTransferInstruction(sourceTokenAccount, destTokenAccount, wallet.publicKey, amountLamports);
|
|
605
|
+
const preIxs = [];
|
|
606
|
+
const destAtaInfo = await connection.getAccountInfo(destTokenAccount);
|
|
607
|
+
if (!destAtaInfo) {
|
|
608
|
+
const { createAssociatedTokenAccountInstruction } = await import("@solana/spl-token");
|
|
609
|
+
preIxs.push(createAssociatedTokenAccountInstruction(wallet.publicKey, destTokenAccount, destination, SYN_MINT(), TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID));
|
|
610
|
+
logger_default.log(` Destination ATA missing \u2014 will create it in the same tx`);
|
|
611
|
+
}
|
|
612
|
+
const tx = new Transaction().add(...preIxs, transferIx);
|
|
613
|
+
const signature = await sendAndConfirmFresh(connection, tx, [
|
|
614
|
+
wallet
|
|
615
|
+
]);
|
|
616
|
+
logger_default.log(`\u2705 Withdraw successful!`);
|
|
617
|
+
logger_default.log(` Transaction: ${signature}`);
|
|
618
|
+
return signature;
|
|
619
|
+
}
|
|
620
|
+
__name(withdrawSyn, "withdrawSyn");
|
|
621
|
+
async function getStakeInfo() {
|
|
622
|
+
const wallet = await loadWalletWithPassword();
|
|
623
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
624
|
+
const stakeAccountAddress = await findStakeAccount(connection, wallet.publicKey);
|
|
625
|
+
if (!stakeAccountAddress) {
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
try {
|
|
629
|
+
const accountInfo = await connection.getAccountInfo(new PublicKey(stakeAccountAddress));
|
|
630
|
+
if (!accountInfo) {
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
const data = accountInfo.data;
|
|
634
|
+
const amount = Number(data.readBigUInt64LE(72)) / 1e9;
|
|
635
|
+
const tier = data.readUInt8(80);
|
|
636
|
+
const lockedUntil = Number(data.readBigInt64LE(162));
|
|
637
|
+
const rewardsPending = Number(data.readBigUInt64LE(170)) / 1e9;
|
|
638
|
+
return {
|
|
639
|
+
amount,
|
|
640
|
+
tier,
|
|
641
|
+
rewardsPending,
|
|
642
|
+
lockedUntil
|
|
643
|
+
};
|
|
644
|
+
} catch (e) {
|
|
645
|
+
logger_default.error("Error fetching stake info:", e);
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
__name(getStakeInfo, "getStakeInfo");
|
|
650
|
+
async function getWalletBalance() {
|
|
651
|
+
const wallet = await loadWalletWithPassword();
|
|
652
|
+
const connection = new Connection(SOLANA_RPC_URL_GETTER(), "confirmed");
|
|
653
|
+
const solBalance = await connection.getBalance(wallet.publicKey);
|
|
654
|
+
const sol = solBalance / 1e9;
|
|
655
|
+
let syn = 0;
|
|
656
|
+
try {
|
|
657
|
+
const tokenAccount = await getUserTokenAccount(connection, wallet.publicKey);
|
|
658
|
+
const tokenBalance = await connection.getTokenAccountBalance(tokenAccount);
|
|
659
|
+
syn = Number(tokenBalance.value.uiAmountString);
|
|
660
|
+
} catch (e) {
|
|
661
|
+
}
|
|
662
|
+
return {
|
|
663
|
+
sol,
|
|
664
|
+
syn
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
__name(getWalletBalance, "getWalletBalance");
|
|
668
|
+
async function findStakeAccount(connection, owner) {
|
|
669
|
+
try {
|
|
670
|
+
const accounts = await connection.getProgramAccounts(STAKING_PROGRAM_ID(), {
|
|
671
|
+
filters: [
|
|
672
|
+
{
|
|
673
|
+
memcmp: {
|
|
674
|
+
offset: 8,
|
|
675
|
+
bytes: owner.toBase58()
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
]
|
|
679
|
+
});
|
|
680
|
+
if (accounts.length > 0) {
|
|
681
|
+
return accounts[0].pubkey.toBase58();
|
|
682
|
+
}
|
|
683
|
+
} catch (e) {
|
|
684
|
+
logger_default.warn("Failed to search stake accounts:", e);
|
|
685
|
+
}
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
__name(findStakeAccount, "findStakeAccount");
|
|
689
|
+
|
|
690
|
+
export {
|
|
691
|
+
sendAndConfirmFresh,
|
|
692
|
+
loadWalletWithPassword,
|
|
693
|
+
stakeTokens,
|
|
694
|
+
unstakeTokens,
|
|
695
|
+
claimStakingRewards,
|
|
696
|
+
depositSol,
|
|
697
|
+
depositSyn,
|
|
698
|
+
withdrawSol,
|
|
699
|
+
withdrawSyn,
|
|
700
|
+
getStakeInfo,
|
|
701
|
+
getWalletBalance
|
|
702
|
+
};
|