@aintivirus-ai/mixer-sdk 1.0.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 +711 -0
- package/dist/evm/index.d.ts +117 -0
- package/dist/evm/index.js +377 -0
- package/dist/hooks/index.d.ts +29 -0
- package/dist/hooks/index.js +36 -0
- package/dist/hooks/useAdmin.d.ts +35 -0
- package/dist/hooks/useAdmin.js +195 -0
- package/dist/hooks/useAintiVirus.d.ts +48 -0
- package/dist/hooks/useAintiVirus.js +238 -0
- package/dist/hooks/useClaim.d.ts +31 -0
- package/dist/hooks/useClaim.js +110 -0
- package/dist/hooks/useDeploy.d.ts +32 -0
- package/dist/hooks/useDeploy.js +96 -0
- package/dist/hooks/useDeposit.d.ts +30 -0
- package/dist/hooks/useDeposit.js +96 -0
- package/dist/hooks/useStake.d.ts +31 -0
- package/dist/hooks/useStake.js +112 -0
- package/dist/hooks/useView.d.ts +40 -0
- package/dist/hooks/useView.js +255 -0
- package/dist/hooks/useWithdraw.d.ts +30 -0
- package/dist/hooks/useWithdraw.js +98 -0
- package/dist/hooks/utils.d.ts +11 -0
- package/dist/hooks/utils.js +65 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +97 -0
- package/dist/solana/index.d.ts +139 -0
- package/dist/solana/index.js +694 -0
- package/dist/types/index.d.ts +103 -0
- package/dist/types/index.js +19 -0
- package/dist/utils/crypto.d.ts +23 -0
- package/dist/utils/crypto.js +43 -0
- package/dist/utils/proof.d.ts +34 -0
- package/dist/utils/proof.js +120 -0
- package/package.json +63 -0
|
@@ -0,0 +1,694 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.AintiVirusSolana = void 0;
|
|
37
|
+
const anchor = __importStar(require("@coral-xyz/anchor"));
|
|
38
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
39
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
40
|
+
const types_1 = require("../types");
|
|
41
|
+
/**
|
|
42
|
+
* Solana SDK for AintiVirus Mixer
|
|
43
|
+
*/
|
|
44
|
+
class AintiVirusSolana {
|
|
45
|
+
constructor(factoryProgramId, mixerProgramId, stakingProgramId, wallet, connection, tokenMint) {
|
|
46
|
+
this.connection = connection;
|
|
47
|
+
this.wallet = wallet;
|
|
48
|
+
// Initialize programs (using any type for IDL flexibility)
|
|
49
|
+
this.factoryProgram = new anchor.Program({}, // IDL should be loaded separately
|
|
50
|
+
new web3_js_1.PublicKey(factoryProgramId), new anchor.AnchorProvider(connection, wallet, {}));
|
|
51
|
+
this.mixerProgram = new anchor.Program({}, new web3_js_1.PublicKey(mixerProgramId), new anchor.AnchorProvider(connection, wallet, {}));
|
|
52
|
+
this.stakingProgram = new anchor.Program({}, new web3_js_1.PublicKey(stakingProgramId), new anchor.AnchorProvider(connection, wallet, {}));
|
|
53
|
+
if (tokenMint) {
|
|
54
|
+
this.tokenMint = new web3_js_1.PublicKey(tokenMint);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get factory PDA
|
|
59
|
+
*/
|
|
60
|
+
getFactoryPda() {
|
|
61
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("factory")], this.factoryProgram.programId);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get mixer pool PDA
|
|
65
|
+
*/
|
|
66
|
+
getMixerPoolPda(mode, amount) {
|
|
67
|
+
const amountBuffer = Buffer.allocUnsafe(8);
|
|
68
|
+
amountBuffer.writeBigUInt64LE(amount, 0);
|
|
69
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("mixer_pool"), Buffer.from([mode]), amountBuffer], this.factoryProgram.programId);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get mixer config PDA
|
|
73
|
+
*/
|
|
74
|
+
getMixerConfigPda(mode, amount) {
|
|
75
|
+
const amountBuffer = Buffer.allocUnsafe(8);
|
|
76
|
+
amountBuffer.writeBigUInt64LE(amount, 0);
|
|
77
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("mixer_config"), Buffer.from([mode]), amountBuffer], this.mixerProgram.programId);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get merkle tree PDA
|
|
81
|
+
*/
|
|
82
|
+
getMerkleTreePda(mixerConfigPda) {
|
|
83
|
+
return web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("merkle_tree"), mixerConfigPda.toBuffer()], this.mixerProgram.programId);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get mixer address for a specific mode and amount
|
|
87
|
+
*/
|
|
88
|
+
async getMixer(mode, amount) {
|
|
89
|
+
const [mixerPoolPda] = this.getMixerPoolPda(mode, amount);
|
|
90
|
+
// Call get_mixer instruction (view function)
|
|
91
|
+
try {
|
|
92
|
+
const mixerConfigPubkey = await this.factoryProgram.methods
|
|
93
|
+
.getMixer(mode, new anchor.BN(amount.toString()))
|
|
94
|
+
.accounts({
|
|
95
|
+
mixerPool: mixerPoolPda,
|
|
96
|
+
})
|
|
97
|
+
.view();
|
|
98
|
+
return mixerConfigPubkey;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
throw new Error(`Mixer not found for mode ${mode}, amount ${amount}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if mixer exists
|
|
106
|
+
*/
|
|
107
|
+
async mixerExists(mode, amount) {
|
|
108
|
+
try {
|
|
109
|
+
await this.getMixer(mode, amount);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Deposit SOL into the mixer
|
|
118
|
+
*/
|
|
119
|
+
async depositSol(amount, commitment) {
|
|
120
|
+
const [factoryPda] = this.getFactoryPda();
|
|
121
|
+
const [mixerPoolPda] = this.getMixerPoolPda(types_1.AssetMode.ETH, amount);
|
|
122
|
+
const [mixerConfigPda] = this.getMixerConfigPda(types_1.AssetMode.ETH, amount);
|
|
123
|
+
const [merkleTreePda] = this.getMerkleTreePda(mixerConfigPda);
|
|
124
|
+
const commitmentBytes = Buffer.allocUnsafe(32);
|
|
125
|
+
const commitmentBigInt = commitment;
|
|
126
|
+
commitmentBytes.writeBigUInt64LE(commitmentBigInt & BigInt("0xFFFFFFFFFFFFFFFF"), 0);
|
|
127
|
+
commitmentBytes.writeBigUInt64LE((commitmentBigInt >> 64n) & BigInt("0xFFFFFFFFFFFFFFFF"), 8);
|
|
128
|
+
commitmentBytes.writeBigUInt64LE((commitmentBigInt >> 128n) & BigInt("0xFFFFFFFFFFFFFFFF"), 16);
|
|
129
|
+
commitmentBytes.writeBigUInt64LE((commitmentBigInt >> 192n) & BigInt("0xFFFFFFFFFFFFFFFF"), 24);
|
|
130
|
+
const tx = await this.factoryProgram.methods
|
|
131
|
+
.deposit(types_1.AssetMode.ETH, new anchor.BN(amount.toString()), Array.from(commitmentBytes))
|
|
132
|
+
.accounts({
|
|
133
|
+
factory: factoryPda,
|
|
134
|
+
payer: this.wallet.publicKey,
|
|
135
|
+
mixerProgram: this.mixerProgram.programId,
|
|
136
|
+
mixerPool: mixerPoolPda,
|
|
137
|
+
mixerConfig: mixerConfigPda,
|
|
138
|
+
merkleTree: merkleTreePda,
|
|
139
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
140
|
+
})
|
|
141
|
+
.rpc();
|
|
142
|
+
const signature = tx;
|
|
143
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
144
|
+
commitment: "confirmed",
|
|
145
|
+
});
|
|
146
|
+
return {
|
|
147
|
+
txHash: signature,
|
|
148
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Deposit tokens into the mixer
|
|
153
|
+
*/
|
|
154
|
+
async depositToken(amount, commitment) {
|
|
155
|
+
if (!this.tokenMint) {
|
|
156
|
+
throw new Error("Token mint not configured");
|
|
157
|
+
}
|
|
158
|
+
const [factoryPda] = this.getFactoryPda();
|
|
159
|
+
const [mixerPoolPda] = this.getMixerPoolPda(types_1.AssetMode.TOKEN, amount);
|
|
160
|
+
const [mixerConfigPda] = this.getMixerConfigPda(types_1.AssetMode.TOKEN, amount);
|
|
161
|
+
const [merkleTreePda] = this.getMerkleTreePda(mixerConfigPda);
|
|
162
|
+
const userTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, this.wallet.publicKey);
|
|
163
|
+
const factoryTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, factoryPda, true // allowOwnerOffCurve
|
|
164
|
+
);
|
|
165
|
+
const commitmentBytes = Buffer.allocUnsafe(32);
|
|
166
|
+
const commitmentBigInt = commitment;
|
|
167
|
+
commitmentBytes.writeBigUInt64LE(commitmentBigInt & BigInt("0xFFFFFFFFFFFFFFFF"), 0);
|
|
168
|
+
commitmentBytes.writeBigUInt64LE((commitmentBigInt >> 64n) & BigInt("0xFFFFFFFFFFFFFFFF"), 8);
|
|
169
|
+
commitmentBytes.writeBigUInt64LE((commitmentBigInt >> 128n) & BigInt("0xFFFFFFFFFFFFFFFF"), 16);
|
|
170
|
+
commitmentBytes.writeBigUInt64LE((commitmentBigInt >> 192n) & BigInt("0xFFFFFFFFFFFFFFFF"), 24);
|
|
171
|
+
const tx = await this.factoryProgram.methods
|
|
172
|
+
.deposit(types_1.AssetMode.TOKEN, new anchor.BN(amount.toString()), Array.from(commitmentBytes))
|
|
173
|
+
.accounts({
|
|
174
|
+
factory: factoryPda,
|
|
175
|
+
payer: this.wallet.publicKey,
|
|
176
|
+
mixerProgram: this.mixerProgram.programId,
|
|
177
|
+
mixerPool: mixerPoolPda,
|
|
178
|
+
mixerConfig: mixerConfigPda,
|
|
179
|
+
merkleTree: merkleTreePda,
|
|
180
|
+
tokenMint: this.tokenMint,
|
|
181
|
+
userTokenAccount: userTokenAccount,
|
|
182
|
+
factoryTokenAccount: factoryTokenAccount,
|
|
183
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
184
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
185
|
+
})
|
|
186
|
+
.rpc();
|
|
187
|
+
const signature = tx;
|
|
188
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
189
|
+
commitment: "confirmed",
|
|
190
|
+
});
|
|
191
|
+
return {
|
|
192
|
+
txHash: signature,
|
|
193
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Withdraw from the mixer
|
|
198
|
+
*/
|
|
199
|
+
async withdraw(instructionData, nullifierHash, amount, mode) {
|
|
200
|
+
const [factoryPda] = this.getFactoryPda();
|
|
201
|
+
const [mixerPoolPda] = this.getMixerPoolPda(mode, amount);
|
|
202
|
+
const [mixerConfigPda] = this.getMixerConfigPda(mode, amount);
|
|
203
|
+
const [merkleTreePda] = this.getMerkleTreePda(mixerConfigPda);
|
|
204
|
+
const nullifierHashBytes = Buffer.allocUnsafe(32);
|
|
205
|
+
const nullifierHashBigInt = nullifierHash;
|
|
206
|
+
nullifierHashBytes.writeBigUInt64LE(nullifierHashBigInt & BigInt("0xFFFFFFFFFFFFFFFF"), 0);
|
|
207
|
+
nullifierHashBytes.writeBigUInt64LE((nullifierHashBigInt >> 64n) & BigInt("0xFFFFFFFFFFFFFFFF"), 8);
|
|
208
|
+
nullifierHashBytes.writeBigUInt64LE((nullifierHashBigInt >> 128n) & BigInt("0xFFFFFFFFFFFFFFFF"), 16);
|
|
209
|
+
nullifierHashBytes.writeBigUInt64LE((nullifierHashBigInt >> 192n) & BigInt("0xFFFFFFFFFFFFFFFF"), 24);
|
|
210
|
+
const accounts = {
|
|
211
|
+
factory: factoryPda,
|
|
212
|
+
payer: this.wallet.publicKey,
|
|
213
|
+
mixerProgram: this.mixerProgram.programId,
|
|
214
|
+
mixerPool: mixerPoolPda,
|
|
215
|
+
mixerConfig: mixerConfigPda,
|
|
216
|
+
merkleTree: merkleTreePda,
|
|
217
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
218
|
+
};
|
|
219
|
+
if (mode === types_1.AssetMode.TOKEN && this.tokenMint) {
|
|
220
|
+
const userTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, this.wallet.publicKey);
|
|
221
|
+
const factoryTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, factoryPda, true);
|
|
222
|
+
accounts.tokenMint = this.tokenMint;
|
|
223
|
+
accounts.userTokenAccount = userTokenAccount;
|
|
224
|
+
accounts.factoryTokenAccount = factoryTokenAccount;
|
|
225
|
+
accounts.tokenProgram = spl_token_1.TOKEN_PROGRAM_ID;
|
|
226
|
+
}
|
|
227
|
+
const tx = await this.factoryProgram.methods
|
|
228
|
+
.withdraw(mode, new anchor.BN(amount.toString()), Array.from(instructionData), Array.from(nullifierHashBytes))
|
|
229
|
+
.accounts(accounts)
|
|
230
|
+
.rpc();
|
|
231
|
+
const signature = tx;
|
|
232
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
233
|
+
commitment: "confirmed",
|
|
234
|
+
});
|
|
235
|
+
return {
|
|
236
|
+
txHash: signature,
|
|
237
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Stake SOL
|
|
242
|
+
*/
|
|
243
|
+
async stakeSol(amount) {
|
|
244
|
+
const [factoryPda] = this.getFactoryPda();
|
|
245
|
+
const tx = await this.factoryProgram.methods
|
|
246
|
+
.stakeEther(new anchor.BN(amount.toString()))
|
|
247
|
+
.accounts({
|
|
248
|
+
factory: factoryPda,
|
|
249
|
+
staker: this.wallet.publicKey,
|
|
250
|
+
stakingProgram: this.stakingProgram.programId,
|
|
251
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
252
|
+
})
|
|
253
|
+
.rpc();
|
|
254
|
+
const signature = tx;
|
|
255
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
256
|
+
commitment: "confirmed",
|
|
257
|
+
});
|
|
258
|
+
return {
|
|
259
|
+
txHash: signature,
|
|
260
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Stake tokens
|
|
265
|
+
*/
|
|
266
|
+
async stakeToken(amount) {
|
|
267
|
+
if (!this.tokenMint) {
|
|
268
|
+
throw new Error("Token mint not configured");
|
|
269
|
+
}
|
|
270
|
+
const [factoryPda] = this.getFactoryPda();
|
|
271
|
+
const userTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, this.wallet.publicKey);
|
|
272
|
+
const factoryTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, factoryPda, true);
|
|
273
|
+
const tx = await this.factoryProgram.methods
|
|
274
|
+
.stakeToken(new anchor.BN(amount.toString()))
|
|
275
|
+
.accounts({
|
|
276
|
+
factory: factoryPda,
|
|
277
|
+
staker: this.wallet.publicKey,
|
|
278
|
+
stakingProgram: this.stakingProgram.programId,
|
|
279
|
+
tokenMint: this.tokenMint,
|
|
280
|
+
userTokenAccount: userTokenAccount,
|
|
281
|
+
factoryTokenAccount: factoryTokenAccount,
|
|
282
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
283
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
284
|
+
})
|
|
285
|
+
.rpc();
|
|
286
|
+
const signature = tx;
|
|
287
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
288
|
+
commitment: "confirmed",
|
|
289
|
+
});
|
|
290
|
+
return {
|
|
291
|
+
txHash: signature,
|
|
292
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Claim SOL rewards
|
|
297
|
+
*/
|
|
298
|
+
async claimSol(seasonId) {
|
|
299
|
+
const [factoryPda] = this.getFactoryPda();
|
|
300
|
+
const tx = await this.factoryProgram.methods
|
|
301
|
+
.claimEth(new anchor.BN(seasonId.toString()))
|
|
302
|
+
.accounts({
|
|
303
|
+
factory: factoryPda,
|
|
304
|
+
staker: this.wallet.publicKey,
|
|
305
|
+
stakingProgram: this.stakingProgram.programId,
|
|
306
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
307
|
+
})
|
|
308
|
+
.rpc();
|
|
309
|
+
const signature = tx;
|
|
310
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
311
|
+
commitment: "confirmed",
|
|
312
|
+
});
|
|
313
|
+
return {
|
|
314
|
+
txHash: signature,
|
|
315
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Claim token rewards
|
|
320
|
+
*/
|
|
321
|
+
async claimToken(seasonId) {
|
|
322
|
+
if (!this.tokenMint) {
|
|
323
|
+
throw new Error("Token mint not configured");
|
|
324
|
+
}
|
|
325
|
+
const [factoryPda] = this.getFactoryPda();
|
|
326
|
+
const userTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, this.wallet.publicKey);
|
|
327
|
+
const factoryTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, factoryPda, true);
|
|
328
|
+
const tx = await this.factoryProgram.methods
|
|
329
|
+
.claimToken(new anchor.BN(seasonId.toString()))
|
|
330
|
+
.accounts({
|
|
331
|
+
factory: factoryPda,
|
|
332
|
+
staker: this.wallet.publicKey,
|
|
333
|
+
stakingProgram: this.stakingProgram.programId,
|
|
334
|
+
tokenMint: this.tokenMint,
|
|
335
|
+
userTokenAccount: userTokenAccount,
|
|
336
|
+
factoryTokenAccount: factoryTokenAccount,
|
|
337
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
338
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
339
|
+
})
|
|
340
|
+
.rpc();
|
|
341
|
+
const signature = tx;
|
|
342
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
343
|
+
commitment: "confirmed",
|
|
344
|
+
});
|
|
345
|
+
return {
|
|
346
|
+
txHash: signature,
|
|
347
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Unstake SOL
|
|
352
|
+
*/
|
|
353
|
+
async unstakeSol() {
|
|
354
|
+
const [factoryPda] = this.getFactoryPda();
|
|
355
|
+
const tx = await this.factoryProgram.methods
|
|
356
|
+
.unstakeEth()
|
|
357
|
+
.accounts({
|
|
358
|
+
factory: factoryPda,
|
|
359
|
+
staker: this.wallet.publicKey,
|
|
360
|
+
stakingProgram: this.stakingProgram.programId,
|
|
361
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
362
|
+
})
|
|
363
|
+
.rpc();
|
|
364
|
+
const signature = tx;
|
|
365
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
366
|
+
commitment: "confirmed",
|
|
367
|
+
});
|
|
368
|
+
return {
|
|
369
|
+
txHash: signature,
|
|
370
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Unstake tokens
|
|
375
|
+
*/
|
|
376
|
+
async unstakeToken() {
|
|
377
|
+
if (!this.tokenMint) {
|
|
378
|
+
throw new Error("Token mint not configured");
|
|
379
|
+
}
|
|
380
|
+
const [factoryPda] = this.getFactoryPda();
|
|
381
|
+
const userTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, this.wallet.publicKey);
|
|
382
|
+
const factoryTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, factoryPda, true);
|
|
383
|
+
const tx = await this.factoryProgram.methods
|
|
384
|
+
.unstakeToken()
|
|
385
|
+
.accounts({
|
|
386
|
+
factory: factoryPda,
|
|
387
|
+
staker: this.wallet.publicKey,
|
|
388
|
+
stakingProgram: this.stakingProgram.programId,
|
|
389
|
+
tokenMint: this.tokenMint,
|
|
390
|
+
userTokenAccount: userTokenAccount,
|
|
391
|
+
factoryTokenAccount: factoryTokenAccount,
|
|
392
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
393
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
394
|
+
})
|
|
395
|
+
.rpc();
|
|
396
|
+
const signature = tx;
|
|
397
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
398
|
+
commitment: "confirmed",
|
|
399
|
+
});
|
|
400
|
+
return {
|
|
401
|
+
txHash: signature,
|
|
402
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Get current stake season
|
|
407
|
+
*/
|
|
408
|
+
async getCurrentStakeSeason() {
|
|
409
|
+
const [factoryPda] = this.getFactoryPda();
|
|
410
|
+
const factoryAccount = await this.factoryProgram.account.factory.fetch(factoryPda);
|
|
411
|
+
// Assuming factory account has currentStakeSeason field
|
|
412
|
+
// This may need adjustment based on actual account structure
|
|
413
|
+
return BigInt(factoryAccount.currentStakeSeason?.toString() || "0");
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Get SOL balance
|
|
417
|
+
*/
|
|
418
|
+
async getSolBalance(address) {
|
|
419
|
+
const balance = await this.connection.getBalance(address);
|
|
420
|
+
return BigInt(balance);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Get token balance
|
|
424
|
+
*/
|
|
425
|
+
async getTokenBalance(address) {
|
|
426
|
+
if (!this.tokenMint) {
|
|
427
|
+
throw new Error("Token mint not configured");
|
|
428
|
+
}
|
|
429
|
+
const tokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, address);
|
|
430
|
+
try {
|
|
431
|
+
const accountInfo = await this.connection.getTokenAccountBalance(tokenAccount);
|
|
432
|
+
return BigInt(accountInfo.value.amount);
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
return 0n;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Deploy mixer instance
|
|
440
|
+
*/
|
|
441
|
+
async deployMixer(mode, amount) {
|
|
442
|
+
const [factoryPda] = this.getFactoryPda();
|
|
443
|
+
const [mixerPoolPda] = this.getMixerPoolPda(mode, amount);
|
|
444
|
+
const [mixerConfigPda] = this.getMixerConfigPda(mode, amount);
|
|
445
|
+
const [merkleTreePda] = this.getMerkleTreePda(mixerConfigPda);
|
|
446
|
+
const accounts = {
|
|
447
|
+
factory: factoryPda,
|
|
448
|
+
payer: this.wallet.publicKey,
|
|
449
|
+
mixerProgram: this.mixerProgram.programId,
|
|
450
|
+
mixerPool: mixerPoolPda,
|
|
451
|
+
mixerConfig: mixerConfigPda,
|
|
452
|
+
merkleTree: merkleTreePda,
|
|
453
|
+
systemProgram: web3_js_1.SystemProgram.programId,
|
|
454
|
+
};
|
|
455
|
+
if (mode === types_1.AssetMode.TOKEN && this.tokenMint) {
|
|
456
|
+
const factoryTokenAccount = await (0, spl_token_1.getAssociatedTokenAddress)(this.tokenMint, factoryPda, true);
|
|
457
|
+
accounts.tokenMint = this.tokenMint;
|
|
458
|
+
accounts.factoryTokenAccount = factoryTokenAccount;
|
|
459
|
+
accounts.tokenProgram = spl_token_1.TOKEN_PROGRAM_ID;
|
|
460
|
+
}
|
|
461
|
+
const tx = await this.factoryProgram.methods
|
|
462
|
+
.deployMixer(mode, new anchor.BN(amount.toString()))
|
|
463
|
+
.accounts(accounts)
|
|
464
|
+
.rpc();
|
|
465
|
+
const signature = tx;
|
|
466
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
467
|
+
commitment: "confirmed",
|
|
468
|
+
});
|
|
469
|
+
return {
|
|
470
|
+
txHash: signature,
|
|
471
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Set fee rate (admin function)
|
|
476
|
+
*/
|
|
477
|
+
async setFeeRate(feeRate) {
|
|
478
|
+
const [factoryPda] = this.getFactoryPda();
|
|
479
|
+
const tx = await this.factoryProgram.methods
|
|
480
|
+
.setFeeRate(new anchor.BN(feeRate.toString()))
|
|
481
|
+
.accounts({
|
|
482
|
+
factory: factoryPda,
|
|
483
|
+
authority: this.wallet.publicKey,
|
|
484
|
+
})
|
|
485
|
+
.rpc();
|
|
486
|
+
const signature = tx;
|
|
487
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
488
|
+
commitment: "confirmed",
|
|
489
|
+
});
|
|
490
|
+
return {
|
|
491
|
+
txHash: signature,
|
|
492
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Set staking season period (admin function)
|
|
497
|
+
*/
|
|
498
|
+
async setStakingSeasonPeriod(period) {
|
|
499
|
+
const [factoryPda] = this.getFactoryPda();
|
|
500
|
+
const tx = await this.factoryProgram.methods
|
|
501
|
+
.setStakingSeasonPeriod(new anchor.BN(period.toString()))
|
|
502
|
+
.accounts({
|
|
503
|
+
factory: factoryPda,
|
|
504
|
+
authority: this.wallet.publicKey,
|
|
505
|
+
})
|
|
506
|
+
.rpc();
|
|
507
|
+
const signature = tx;
|
|
508
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
509
|
+
commitment: "confirmed",
|
|
510
|
+
});
|
|
511
|
+
return {
|
|
512
|
+
txHash: signature,
|
|
513
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Start stake season (admin function)
|
|
518
|
+
*/
|
|
519
|
+
async startStakeSeason() {
|
|
520
|
+
const [factoryPda] = this.getFactoryPda();
|
|
521
|
+
const tx = await this.factoryProgram.methods
|
|
522
|
+
.startStakeSeason()
|
|
523
|
+
.accounts({
|
|
524
|
+
factory: factoryPda,
|
|
525
|
+
authority: this.wallet.publicKey,
|
|
526
|
+
stakingProgram: this.stakingProgram.programId,
|
|
527
|
+
})
|
|
528
|
+
.rpc();
|
|
529
|
+
const signature = tx;
|
|
530
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
531
|
+
commitment: "confirmed",
|
|
532
|
+
});
|
|
533
|
+
return {
|
|
534
|
+
txHash: signature,
|
|
535
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Set verifier address (admin function)
|
|
540
|
+
*/
|
|
541
|
+
async setVerifier(verifierAddress) {
|
|
542
|
+
const [factoryPda] = this.getFactoryPda();
|
|
543
|
+
const tx = await this.factoryProgram.methods
|
|
544
|
+
.setVerifier(new web3_js_1.PublicKey(verifierAddress))
|
|
545
|
+
.accounts({
|
|
546
|
+
factory: factoryPda,
|
|
547
|
+
authority: this.wallet.publicKey,
|
|
548
|
+
})
|
|
549
|
+
.rpc();
|
|
550
|
+
const signature = tx;
|
|
551
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
552
|
+
commitment: "confirmed",
|
|
553
|
+
});
|
|
554
|
+
return {
|
|
555
|
+
txHash: signature,
|
|
556
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Set hasher address (admin function)
|
|
561
|
+
*/
|
|
562
|
+
async setHasher(hasherAddress) {
|
|
563
|
+
const [factoryPda] = this.getFactoryPda();
|
|
564
|
+
const tx = await this.factoryProgram.methods
|
|
565
|
+
.setHasher(new web3_js_1.PublicKey(hasherAddress))
|
|
566
|
+
.accounts({
|
|
567
|
+
factory: factoryPda,
|
|
568
|
+
authority: this.wallet.publicKey,
|
|
569
|
+
})
|
|
570
|
+
.rpc();
|
|
571
|
+
const signature = tx;
|
|
572
|
+
const txDetails = await this.connection.getTransaction(signature, {
|
|
573
|
+
commitment: "confirmed",
|
|
574
|
+
});
|
|
575
|
+
return {
|
|
576
|
+
txHash: signature,
|
|
577
|
+
blockTime: txDetails?.blockTime ?? undefined,
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Calculate deposit amount including fees
|
|
582
|
+
*/
|
|
583
|
+
async calculateDepositAmount(amount) {
|
|
584
|
+
const [factoryPda] = this.getFactoryPda();
|
|
585
|
+
const factoryAccount = await this.factoryProgram.account.factory.fetch(factoryPda);
|
|
586
|
+
const feeRate = BigInt(factoryAccount.feeRate?.toString() || "0");
|
|
587
|
+
// Calculate: amount + (amount * feeRate / 10000)
|
|
588
|
+
return amount + (amount * feeRate) / 10000n;
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Get fee rate
|
|
592
|
+
*/
|
|
593
|
+
async getFeeRate() {
|
|
594
|
+
const [factoryPda] = this.getFactoryPda();
|
|
595
|
+
const factoryAccount = await this.factoryProgram.account.factory.fetch(factoryPda);
|
|
596
|
+
return BigInt(factoryAccount.feeRate?.toString() || "0");
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Get stake season information
|
|
600
|
+
*/
|
|
601
|
+
async getStakeSeason(seasonId) {
|
|
602
|
+
const [factoryPda] = this.getFactoryPda();
|
|
603
|
+
// Fetch stake season from staking program
|
|
604
|
+
const seasonPda = web3_js_1.PublicKey.findProgramAddressSync([
|
|
605
|
+
Buffer.from("stake_season"),
|
|
606
|
+
new anchor.BN(seasonId.toString()).toArrayLike(Buffer, "be", 8),
|
|
607
|
+
], this.stakingProgram.programId)[0];
|
|
608
|
+
try {
|
|
609
|
+
const seasonAccount = await this.stakingProgram.account.stakeSeason.fetch(seasonPda);
|
|
610
|
+
return {
|
|
611
|
+
seasonId: BigInt(seasonAccount.seasonId?.toString() || "0"),
|
|
612
|
+
startTimestamp: BigInt(seasonAccount.startTimestamp?.toString() || "0"),
|
|
613
|
+
endTimestamp: BigInt(seasonAccount.endTimestamp?.toString() || "0"),
|
|
614
|
+
totalStakedEthAmount: BigInt(seasonAccount.totalStakedEthAmount?.toString() || "0"),
|
|
615
|
+
totalStakedTokenAmount: BigInt(seasonAccount.totalStakedTokenAmount?.toString() || "0"),
|
|
616
|
+
totalRewardEthAmount: BigInt(seasonAccount.totalRewardEthAmount?.toString() || "0"),
|
|
617
|
+
totalRewardTokenAmount: BigInt(seasonAccount.totalRewardTokenAmount?.toString() || "0"),
|
|
618
|
+
totalEthWeightValue: BigInt(seasonAccount.totalEthWeightValue?.toString() || "0"),
|
|
619
|
+
totalTokenWeightValue: BigInt(seasonAccount.totalTokenWeightValue?.toString() || "0"),
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
catch {
|
|
623
|
+
throw new Error(`Stake season ${seasonId} not found`);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Get staker record
|
|
628
|
+
*/
|
|
629
|
+
async getStakerRecord(address) {
|
|
630
|
+
const stakerPubkey = new web3_js_1.PublicKey(address);
|
|
631
|
+
const stakerRecordPda = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("staker_record"), stakerPubkey.toBuffer()], this.stakingProgram.programId)[0];
|
|
632
|
+
try {
|
|
633
|
+
const stakerRecord = await this.stakingProgram.account.stakerRecord.fetch(stakerRecordPda);
|
|
634
|
+
return {
|
|
635
|
+
ethStakedSeasonId: BigInt(stakerRecord.ethStakedSeasonId?.toString() || "0"),
|
|
636
|
+
tokenStakedSeasonId: BigInt(stakerRecord.tokenStakedSeasonId?.toString() || "0"),
|
|
637
|
+
ethStakedTimestamp: BigInt(stakerRecord.ethStakedTimestamp?.toString() || "0"),
|
|
638
|
+
tokenStakedTimestamp: BigInt(stakerRecord.tokenStakedTimestamp?.toString() || "0"),
|
|
639
|
+
stakedEthAmount: BigInt(stakerRecord.stakedEthAmount?.toString() || "0"),
|
|
640
|
+
stakedTokenAmount: BigInt(stakerRecord.stakedTokenAmount?.toString() || "0"),
|
|
641
|
+
ethWeightValue: BigInt(stakerRecord.ethWeightValue?.toString() || "0"),
|
|
642
|
+
tokenWeightValue: BigInt(stakerRecord.tokenWeightValue?.toString() || "0"),
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
catch {
|
|
646
|
+
throw new Error(`Staker record for ${address} not found`);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Check if address has claimed SOL for a season
|
|
651
|
+
*/
|
|
652
|
+
async hasClaimedSol(address, seasonId) {
|
|
653
|
+
const stakerPubkey = new web3_js_1.PublicKey(address);
|
|
654
|
+
const claimPda = web3_js_1.PublicKey.findProgramAddressSync([
|
|
655
|
+
Buffer.from("season_claimed_eth"),
|
|
656
|
+
stakerPubkey.toBuffer(),
|
|
657
|
+
new anchor.BN(seasonId.toString()).toArrayLike(Buffer, "be", 8),
|
|
658
|
+
], this.stakingProgram.programId)[0];
|
|
659
|
+
try {
|
|
660
|
+
await this.stakingProgram.account.seasonClaimedEth.fetch(claimPda);
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
663
|
+
catch {
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Check if address has claimed tokens for a season
|
|
669
|
+
*/
|
|
670
|
+
async hasClaimedToken(address, seasonId) {
|
|
671
|
+
const stakerPubkey = new web3_js_1.PublicKey(address);
|
|
672
|
+
const claimPda = web3_js_1.PublicKey.findProgramAddressSync([
|
|
673
|
+
Buffer.from("season_claimed_token"),
|
|
674
|
+
stakerPubkey.toBuffer(),
|
|
675
|
+
new anchor.BN(seasonId.toString()).toArrayLike(Buffer, "be", 8),
|
|
676
|
+
], this.stakingProgram.programId)[0];
|
|
677
|
+
try {
|
|
678
|
+
await this.stakingProgram.account.seasonClaimedToken.fetch(claimPda);
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
681
|
+
catch {
|
|
682
|
+
return false;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Get staking address (PDA)
|
|
687
|
+
*/
|
|
688
|
+
async getStakingAddress() {
|
|
689
|
+
const [factoryPda] = this.getFactoryPda();
|
|
690
|
+
const factoryAccount = await this.factoryProgram.account.factory.fetch(factoryPda);
|
|
691
|
+
return factoryAccount.staking;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
exports.AintiVirusSolana = AintiVirusSolana;
|