@zcomb/programs-sdk 1.5.1 → 1.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.
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ /*
3
+ * Low-level instruction builders for the SVault program.
4
+ * These are thin wrappers around the program methods - use SVaultClient for higher-level operations.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.FEE_AUTHORITY = void 0;
8
+ exports.initializeStakingVault = initializeStakingVault;
9
+ exports.stake = stake;
10
+ exports.initiateUnstake = initiateUnstake;
11
+ exports.withdraw = withdraw;
12
+ exports.postRewards = postRewards;
13
+ exports.claimRewards = claimRewards;
14
+ exports.setConfig = setConfig;
15
+ exports.slash = slash;
16
+ exports.addDelegate = addDelegate;
17
+ exports.removeDelegate = removeDelegate;
18
+ const anchor_1 = require("@coral-xyz/anchor");
19
+ const web3_js_1 = require("@solana/web3.js");
20
+ const spl_token_1 = require("@solana/spl-token");
21
+ const utils_1 = require("./utils");
22
+ /* Fee Authority (same as AMM program) */
23
+ exports.FEE_AUTHORITY = new web3_js_1.PublicKey("FEEnkcCNE2623LYCPtLf63LFzXpCFigBLTu4qZovRGZC");
24
+ function initializeStakingVault(program, admin, tokenMint, unstakingPeriod, volumeWindow, nonce) {
25
+ const unstakingPeriodBN = typeof unstakingPeriod === "number" ? new anchor_1.BN(unstakingPeriod) : unstakingPeriod;
26
+ const volumeWindowBN = typeof volumeWindow === "number" ? new anchor_1.BN(volumeWindow) : volumeWindow;
27
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
28
+ const [stakeVault] = (0, utils_1.deriveStakeVaultPDA)(configPda, program.programId);
29
+ const [rewardVault] = (0, utils_1.deriveRewardVaultPDA)(configPda, program.programId);
30
+ return program.methods
31
+ .initializeStakingVault(unstakingPeriodBN, volumeWindowBN, nonce)
32
+ .accountsPartial({
33
+ admin,
34
+ tokenMint,
35
+ config: configPda,
36
+ stakeVault,
37
+ rewardVault,
38
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
39
+ });
40
+ }
41
+ function stake(program, user, tokenMint, nonce, amount) {
42
+ const amountBN = typeof amount === "number" ? new anchor_1.BN(amount) : amount;
43
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
44
+ const [userStakePda] = (0, utils_1.deriveUserStakePDA)(configPda, user, program.programId);
45
+ const [stakeVault] = (0, utils_1.deriveStakeVaultPDA)(configPda, program.programId);
46
+ const userTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, user);
47
+ return program.methods.stake(amountBN).accountsPartial({
48
+ user,
49
+ tokenMint,
50
+ config: configPda,
51
+ userStake: userStakePda,
52
+ stakeVault,
53
+ userTokenAccount,
54
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
55
+ });
56
+ }
57
+ function initiateUnstake(program, user, tokenMint, nonce, amount) {
58
+ const amountBN = typeof amount === "number" ? new anchor_1.BN(amount) : amount;
59
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
60
+ const [userStakePda] = (0, utils_1.deriveUserStakePDA)(configPda, user, program.programId);
61
+ return program.methods.initiateUnstake(amountBN).accountsPartial({
62
+ user,
63
+ tokenMint,
64
+ config: configPda,
65
+ userStake: userStakePda,
66
+ });
67
+ }
68
+ function withdraw(program, user, tokenMint, nonce) {
69
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
70
+ const [userStakePda] = (0, utils_1.deriveUserStakePDA)(configPda, user, program.programId);
71
+ const [stakeVault] = (0, utils_1.deriveStakeVaultPDA)(configPda, program.programId);
72
+ const userTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, user);
73
+ return program.methods.withdraw().accountsPartial({
74
+ user,
75
+ tokenMint,
76
+ config: configPda,
77
+ userStake: userStakePda,
78
+ stakeVault,
79
+ userTokenAccount,
80
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
81
+ });
82
+ }
83
+ function postRewards(program, admin, tokenMint, nonce, merkleRoot, totalAmount) {
84
+ const merkleRootArray = merkleRoot;
85
+ const totalAmountBN = typeof totalAmount === "number" ? new anchor_1.BN(totalAmount) : totalAmount;
86
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
87
+ const [rewardVault] = (0, utils_1.deriveRewardVaultPDA)(configPda, program.programId);
88
+ const adminTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, admin);
89
+ return program.methods
90
+ .postRewards(merkleRootArray, totalAmountBN)
91
+ .accountsPartial({
92
+ admin,
93
+ tokenMint,
94
+ config: configPda,
95
+ rewardVault,
96
+ adminTokenAccount,
97
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
98
+ });
99
+ }
100
+ function claimRewards(program, user, tokenMint, nonce, cumulativeAmount, proof) {
101
+ const cumulativeAmountBN = typeof cumulativeAmount === "number" ? new anchor_1.BN(cumulativeAmount) : cumulativeAmount;
102
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
103
+ const [userStakePda] = (0, utils_1.deriveUserStakePDA)(configPda, user, program.programId);
104
+ const [rewardVault] = (0, utils_1.deriveRewardVaultPDA)(configPda, program.programId);
105
+ const userTokenAccount = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, user);
106
+ return program.methods
107
+ .claimRewards(cumulativeAmountBN, proof)
108
+ .accountsPartial({
109
+ user,
110
+ tokenMint,
111
+ config: configPda,
112
+ userStake: userStakePda,
113
+ rewardVault,
114
+ userTokenAccount,
115
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
116
+ });
117
+ }
118
+ function setConfig(program, admin, tokenMint, nonce, unstakingPeriod, volumeWindow) {
119
+ const unstakingPeriodArg = unstakingPeriod === null
120
+ ? null
121
+ : typeof unstakingPeriod === "number"
122
+ ? new anchor_1.BN(unstakingPeriod)
123
+ : unstakingPeriod;
124
+ const volumeWindowArg = volumeWindow === null
125
+ ? null
126
+ : typeof volumeWindow === "number"
127
+ ? new anchor_1.BN(volumeWindow)
128
+ : volumeWindow;
129
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
130
+ return program.methods
131
+ .setConfig(unstakingPeriodArg, volumeWindowArg)
132
+ .accountsPartial({
133
+ admin,
134
+ config: configPda,
135
+ });
136
+ }
137
+ function slash(program, admin, tokenMint, nonce, userStakePda, basisPoints) {
138
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
139
+ const [stakeVault] = (0, utils_1.deriveStakeVaultPDA)(configPda, program.programId);
140
+ const feeVault = (0, spl_token_1.getAssociatedTokenAddressSync)(tokenMint, exports.FEE_AUTHORITY);
141
+ return program.methods.slash(basisPoints).accountsPartial({
142
+ admin,
143
+ tokenMint,
144
+ config: configPda,
145
+ userStake: userStakePda,
146
+ stakeVault,
147
+ feeVault,
148
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
149
+ });
150
+ }
151
+ function addDelegate(program, staker, delegateWallet, tokenMint, nonce) {
152
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
153
+ const [userStakePda] = (0, utils_1.deriveUserStakePDA)(configPda, staker, program.programId);
154
+ const [delegatePda] = (0, utils_1.deriveDelegatePDA)(configPda, delegateWallet, program.programId);
155
+ return program.methods.addDelegate().accountsPartial({
156
+ staker,
157
+ delegateWallet,
158
+ config: configPda,
159
+ userStake: userStakePda,
160
+ delegate: delegatePda,
161
+ });
162
+ }
163
+ function removeDelegate(program, staker, delegateWallet, tokenMint, nonce) {
164
+ const [configPda] = (0, utils_1.deriveStakingConfigPDA)(tokenMint, nonce, program.programId);
165
+ const [delegatePda] = (0, utils_1.deriveDelegatePDA)(configPda, delegateWallet, program.programId);
166
+ return program.methods.removeDelegate().accountsPartial({
167
+ staker,
168
+ config: configPda,
169
+ delegate: delegatePda,
170
+ });
171
+ }
172
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5zdHJ1Y3Rpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N2YXVsdC9pbnN0cnVjdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7R0FHRzs7O0FBaUJILHdEQXlCQztBQUVELHNCQXVCQztBQUVELDBDQWtCQztBQUVELDRCQW9CQztBQUVELGtDQXlCQztBQUVELG9DQTBCQztBQUVELDhCQTRCQztBQUVELHNCQXFCQztBQUVELGtDQWtCQztBQUVELHdDQWVDO0FBNVBELDhDQUFnRDtBQUNoRCw2Q0FBNEM7QUFDNUMsaURBQW9GO0FBRXBGLG1DQU1pQjtBQUVqQix5Q0FBeUM7QUFDNUIsUUFBQSxhQUFhLEdBQUcsSUFBSSxtQkFBUyxDQUFDLDhDQUE4QyxDQUFDLENBQUM7QUFFM0YsU0FBZ0Isc0JBQXNCLENBQ3BDLE9BQXdCLEVBQ3hCLEtBQWdCLEVBQ2hCLFNBQW9CLEVBQ3BCLGVBQTRCLEVBQzVCLFlBQXlCLEVBQ3pCLEtBQWE7SUFFYixNQUFNLGlCQUFpQixHQUFHLE9BQU8sZUFBZSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxXQUFFLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQztJQUMxRyxNQUFNLGNBQWMsR0FBRyxPQUFPLFlBQVksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksV0FBRSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUM7SUFFOUYsTUFBTSxDQUFDLFNBQVMsQ0FBQyxHQUFHLElBQUEsOEJBQXNCLEVBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDaEYsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLElBQUEsMkJBQW1CLEVBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN2RSxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsSUFBQSw0QkFBb0Is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QU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxlQUFlLENBQUM7UUFDdEQsTUFBTTtRQUNOLE1BQU0sRUFBRSxTQUFTO1FBQ2pCLFFBQVEsRUFBRSxXQUFXO0tBQ3RCLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogTG93LWxldmVsIGluc3RydWN0aW9uIGJ1aWxkZXJzIGZvciB0aGUgU1ZhdWx0IHByb2dyYW0uXG4gKiBUaGVzZSBhcmUgdGhpbiB3cmFwcGVycyBhcm91bmQgdGhlIHByb2dyYW0gbWV0aG9kcyAtIHVzZSBTVmF1bHRDbGllbnQgZm9yIGhpZ2hlci1sZXZlbCBvcGVyYXRpb25zLlxuICovXG5cbmltcG9ydCB7IFByb2dyYW0sIEJOIH0gZnJvbSBcIkBjb3JhbC14eXovYW5jaG9yXCI7XG5pbXBvcnQgeyBQdWJsaWNLZXkgfSBmcm9tIFwiQHNvbGFuYS93ZWIzLmpzXCI7XG5pbXBvcnQgeyBnZXRBc3NvY2lhdGVkVG9rZW5BZGRyZXNzU3luYywgVE9LRU5fUFJPR1JBTV9JRCB9IGZyb20gXCJAc29sYW5hL3NwbC10b2tlblwiO1xuaW1wb3J0IHsgU3ZhdWx0IH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7XG4gIGRlcml2ZVN0YWtpbmdDb25maWdQREEsXG4gIGRlcml2ZVVzZXJTdGFrZVBEQSxcbiAgZGVyaXZlU3Rha2VWYXVsdFBEQSxcbiAgZGVyaXZlUmV3YXJkVmF1bHRQREEsXG4gIGRlcml2ZURlbGVnYXRlUERBLFxufSBmcm9tIFwiLi91dGlsc1wiO1xuXG4vKiBGZWUgQXV0aG9yaXR5IChzYW1lIGFzIEFNTSBwcm9ncmFtKSAqL1xuZXhwb3J0IGNvbnN0IEZFRV9BVVRIT1JJVFkgPSBuZXcgUHVibGljS2V5KFwiRkVFbmtjQ05FMjYyM0xZQ1B0TGY2M0xGelhwQ0ZpZ0JMVHU0cVpvdlJHWkNcIik7XG5cbmV4cG9ydCBmdW5jdGlvbiBpbml0aWFsaXplU3Rha2luZ1ZhdWx0KFxuICBwcm9ncmFtOiBQcm9ncmFtPFN2YXVsdD4sXG4gIGFkbWluOiBQdWJsaWNLZXksXG4gIHRva2VuTWludDogUHVibGljS2V5LFxuICB1bnN0YWtpbmdQZXJpb2Q6IEJOIHwgbnVtYmVyLFxuICB2b2x1bWVXaW5kb3c6IEJOIHwgbnVtYmVyLFxuICBub25jZTogbnVtYmVyXG4pIHtcbiAgY29uc3QgdW5zdGFraW5nUGVyaW9kQk4gPSB0eXBlb2YgdW5zdGFraW5nUGVyaW9kID09PSBcIm51bWJlclwiID8gbmV3IEJOKHVuc3Rha2luZ1BlcmlvZCkgOiB1bnN0YWtpbmdQZXJpb2Q7XG4gIGNvbnN0IHZvbHVtZVdpbmRvd0JOID0gdHlwZW9mIHZvbHVtZVdpbmRvdyA9PT0gXCJudW1iZXJcIiA/IG5ldyBCTih2b2x1bWVXaW5kb3cpIDogdm9sdW1lV2luZG93O1xuXG4gIGNvbnN0IFtjb25maWdQZGFdID0gZGVyaXZlU3Rha2luZ0NvbmZpZ1BEQSh0b2tlbk1pbnQsIG5vbmNlLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IFtzdGFrZVZhdWx0XSA9IGRlcml2ZVN0YWtlVmF1bHRQREEoY29uZmlnUGRhLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IFtyZXdhcmRWYXVsdF0gPSBkZXJpdmVSZXdhcmRWYXVsdFBEQShjb25maWdQZGEsIHByb2dyYW0ucHJvZ3JhbUlkKTtcblxuICByZXR1cm4gcHJvZ3JhbS5tZXRob2RzXG4gICAgLmluaXRpYWxpemVTdGFraW5nVmF1bHQodW5zdGFraW5nUGVyaW9kQk4sIHZvbHVtZVdpbmRvd0JOLCBub25jZSlcbiAgICAuYWNjb3VudHNQYXJ0aWFsKHtcbiAgICAgIGFkbWluLFxuICAgICAgdG9rZW5NaW50LFxuICAgICAgY29uZmlnOiBjb25maWdQZGEsXG4gICAgICBzdGFrZVZhdWx0LFxuICAgICAgcmV3YXJkVmF1bHQsXG4gICAgICB0b2tlblByb2dyYW06IFRPS0VOX1BST0dSQU1fSUQsXG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzdGFrZShcbiAgcHJvZ3JhbTogUHJvZ3JhbTxTdmF1bHQ+LFxuICB1c2VyOiBQdWJsaWNLZXksXG4gIHRva2VuTWludDogUHVibGljS2V5LFxuICBub25jZTogbnVtYmVyLFxuICBhbW91bnQ6IEJOIHwgbnVtYmVyXG4pIHtcbiAgY29uc3QgYW1vdW50Qk4gPSB0eXBlb2YgYW1vdW50ID09PSBcIm51bWJlclwiID8gbmV3IEJOKGFtb3VudCkgOiBhbW91bnQ7XG5cbiAgY29uc3QgW2NvbmZpZ1BkYV0gPSBkZXJpdmVTdGFraW5nQ29uZmlnUERBKHRva2VuTWludCwgbm9uY2UsIHByb2dyYW0ucHJvZ3JhbUlkKTtcbiAgY29uc3QgW3VzZXJTdGFrZVBkYV0gPSBkZXJpdmVVc2VyU3Rha2VQREEoY29uZmlnUGRhLCB1c2VyLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IFtzdGFrZVZhdWx0XSA9IGRlcml2ZVN0YWtlVmF1bHRQREEoY29uZmlnUGRhLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IHVzZXJUb2tlbkFjY291bnQgPSBnZXRBc3NvY2lhdGVkVG9rZW5BZGRyZXNzU3luYyh0b2tlbk1pbnQsIHVzZXIpO1xuXG4gIHJldHVybiBwcm9ncmFtLm1ldGhvZHMuc3Rha2UoYW1vdW50Qk4pLmFjY291bnRzUGFydGlhbCh7XG4gICAgdXNlcixcbiAgICB0b2tlbk1pbnQsXG4gICAgY29uZmlnOiBjb25maWdQZGEsXG4gICAgdXNlclN0YWtlOiB1c2VyU3Rha2VQZGEsXG4gICAgc3Rha2VWYXVsdCxcbiAgICB1c2VyVG9rZW5BY2NvdW50LFxuICAgIHRva2VuUHJvZ3JhbTogVE9LRU5fUFJPR1JBTV9JRCxcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpbml0aWF0ZVVuc3Rha2UoXG4gIHByb2dyYW06IFByb2dyYW08U3ZhdWx0PixcbiAgdXNlcjogUHVibGljS2V5LFxuICB0b2tlbk1pbnQ6IFB1YmxpY0tleSxcbiAgbm9uY2U6IG51bWJlcixcbiAgYW1vdW50OiBCTiB8IG51bWJlclxuKSB7XG4gIGNvbnN0IGFtb3VudEJOID0gdHlwZW9mIGFtb3VudCA9PT0gXCJudW1iZXJcIiA/IG5ldyBCTihhbW91bnQpIDogYW1vdW50O1xuXG4gIGNvbnN0IFtjb25maWdQZGFdID0gZGVyaXZlU3Rha2luZ0NvbmZpZ1BEQSh0b2tlbk1pbnQsIG5vbmNlLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IFt1c2VyU3Rha2VQZGFdID0gZGVyaXZlVXNlclN0YWtlUERBKGNvbmZpZ1BkYSwgdXNlciwgcHJvZ3JhbS5wcm9ncmFtSWQpO1xuXG4gIHJldHVybiBwcm9ncmFtLm1ldGhvZHMuaW5pdGlhdGVVbnN0YWtlKGFtb3VudEJOKS5hY2NvdW50c1BhcnRpYWwoe1xuICAgIHVzZXIsXG4gICAgdG9rZW5NaW50LFxuICAgIGNvbmZpZzogY29uZmlnUGRhLFxuICAgIHVzZXJTdGFrZTogdXNlclN0YWtlUGRhLFxuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHdpdGhkcmF3KFxuICBwcm9ncmFtOiBQcm9ncmFtPFN2YXVsdD4sXG4gIHVzZXI6IFB1YmxpY0tleSxcbiAgdG9rZW5NaW50OiBQdWJsaWNLZXksXG4gIG5vbmNlOiBudW1iZXJcbikge1xuICBjb25zdCBbY29uZmlnUGRhXSA9IGRlcml2ZVN0YWtpbmdDb25maWdQREEodG9rZW5NaW50LCBub25jZSwgcHJvZ3JhbS5wcm9ncmFtSWQpO1xuICBjb25zdCBbdXNlclN0YWtlUGRhXSA9IGRlcml2ZVVzZXJTdGFrZVBEQShjb25maWdQZGEsIHVzZXIsIHByb2dyYW0ucHJvZ3JhbUlkKTtcbiAgY29uc3QgW3N0YWtlVmF1bHRdID0gZGVyaXZlU3Rha2VWYXVsdFBEQShjb25maWdQZGEsIHByb2dyYW0ucHJvZ3JhbUlkKTtcbiAgY29uc3QgdXNlclRva2VuQWNjb3VudCA9IGdldEFzc29jaWF0ZWRUb2tlbkFkZHJlc3NTeW5jKHRva2VuTWludCwgdXNlcik7XG5cbiAgcmV0dXJuIHByb2dyYW0ubWV0aG9kcy53aXRoZHJhdygpLmFjY291bnRzUGFydGlhbCh7XG4gICAgdXNlcixcbiAgICB0b2tlbk1pbnQsXG4gICAgY29uZmlnOiBjb25maWdQZGEsXG4gICAgdXNlclN0YWtlOiB1c2VyU3Rha2VQZGEsXG4gICAgc3Rha2VWYXVsdCxcbiAgICB1c2VyVG9rZW5BY2NvdW50LFxuICAgIHRva2VuUHJvZ3JhbTogVE9LRU5fUFJPR1JBTV9JRCxcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwb3N0UmV3YXJkcyhcbiAgcHJvZ3JhbTogUHJvZ3JhbTxTdmF1bHQ+LFxuICBhZG1pbjogUHVibGljS2V5LFxuICB0b2tlbk1pbnQ6IFB1YmxpY0tleSxcbiAgbm9uY2U6IG51bWJlcixcbiAgbWVya2xlUm9vdDogbnVtYmVyW10sXG4gIHRvdGFsQW1vdW50OiBCTiB8IG51bWJlclxuKSB7XG4gIGNvbnN0IG1lcmtsZVJvb3RBcnJheSA9IG1lcmtsZVJvb3QgYXMgbnVtYmVyW107XG4gIGNvbnN0IHRvdGFsQW1vdW50Qk4gPSB0eXBlb2YgdG90YWxBbW91bnQgPT09IFwibnVtYmVyXCIgPyBuZXcgQk4odG90YWxBbW91bnQpIDogdG90YWxBbW91bnQ7XG5cbiAgY29uc3QgW2NvbmZpZ1BkYV0gPSBkZXJpdmVTdGFraW5nQ29uZmlnUERBKHRva2VuTWludCwgbm9uY2UsIHByb2dyYW0ucHJvZ3JhbUlkKTtcbiAgY29uc3QgW3Jld2FyZFZhdWx0XSA9IGRlcml2ZVJld2FyZFZhdWx0UERBKGNvbmZpZ1BkYSwgcHJvZ3JhbS5wcm9ncmFtSWQpO1xuICBjb25zdCBhZG1pblRva2VuQWNjb3VudCA9IGdldEFzc29jaWF0ZWRUb2tlbkFkZHJlc3NTeW5jKHRva2VuTWludCwgYWRtaW4pO1xuXG4gIHJldHVybiBwcm9ncmFtLm1ldGhvZHNcbiAgICAucG9zdFJld2FyZHMobWVya2xlUm9vdEFycmF5LCB0b3RhbEFtb3VudEJOKVxuICAgIC5hY2NvdW50c1BhcnRpYWwoe1xuICAgICAgYWRtaW4sXG4gICAgICB0b2tlbk1pbnQsXG4gICAgICBjb25maWc6IGNvbmZpZ1BkYSxcbiAgICAgIHJld2FyZFZhdWx0LFxuICAgICAgYWRtaW5Ub2tlbkFjY291bnQsXG4gICAgICB0b2tlblByb2dyYW06IFRPS0VOX1BST0dSQU1fSUQsXG4gICAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjbGFpbVJld2FyZHMoXG4gIHByb2dyYW06IFByb2dyYW08U3ZhdWx0PixcbiAgdXNlcjogUHVibGljS2V5LFxuICB0b2tlbk1pbnQ6IFB1YmxpY0tleSxcbiAgbm9uY2U6IG51bWJlcixcbiAgY3VtdWxhdGl2ZUFtb3VudDogQk4gfCBudW1iZXIsXG4gIHByb29mOiBudW1iZXJbXVtdXG4pIHtcbiAgY29uc3QgY3VtdWxhdGl2ZUFtb3VudEJOID0gdHlwZW9mIGN1bXVsYXRpdmVBbW91bnQgPT09IFwibnVtYmVyXCIgPyBuZXcgQk4oY3VtdWxhdGl2ZUFtb3VudCkgOiBjdW11bGF0aXZlQW1vdW50O1xuXG4gIGNvbnN0IFtjb25maWdQZGFdID0gZGVyaXZlU3Rha2luZ0NvbmZpZ1BEQSh0b2tlbk1pbnQsIG5vbmNlLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IFt1c2VyU3Rha2VQZGFdID0gZGVyaXZlVXNlclN0YWtlUERBKGNvbmZpZ1BkYSwgdXNlciwgcHJvZ3JhbS5wcm9ncmFtSWQpO1xuICBjb25zdCBbcmV3YXJkVmF1bHRdID0gZGVyaXZlUmV3YXJkVmF1bHRQREEoY29uZmlnUGRhLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IHVzZXJUb2tlbkFjY291bnQgPSBnZXRBc3NvY2lhdGVkVG9rZW5BZGRyZXNzU3luYyh0b2tlbk1pbnQsIHVzZXIpO1xuXG4gIHJldHVybiBwcm9ncmFtLm1ldGhvZHNcbiAgICAuY2xhaW1SZXdhcmRzKGN1bXVsYXRpdmVBbW91bnRCTiwgcHJvb2YpXG4gICAgLmFjY291bnRzUGFydGlhbCh7XG4gICAgICB1c2VyLFxuICAgICAgdG9rZW5NaW50LFxuICAgICAgY29uZmlnOiBjb25maWdQZGEsXG4gICAgICB1c2VyU3Rha2U6IHVzZXJTdGFrZVBkYSxcbiAgICAgIHJld2FyZFZhdWx0LFxuICAgICAgdXNlclRva2VuQWNjb3VudCxcbiAgICAgIHRva2VuUHJvZ3JhbTogVE9LRU5fUFJPR1JBTV9JRCxcbiAgICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNldENvbmZpZyhcbiAgcHJvZ3JhbTogUHJvZ3JhbTxTdmF1bHQ+LFxuICBhZG1pbjogUHVibGljS2V5LFxuICB0b2tlbk1pbnQ6IFB1YmxpY0tleSxcbiAgbm9uY2U6IG51bWJlcixcbiAgdW5zdGFraW5nUGVyaW9kOiBCTiB8IG51bWJlciB8IG51bGwsXG4gIHZvbHVtZVdpbmRvdzogQk4gfCBudW1iZXIgfCBudWxsXG4pIHtcbiAgY29uc3QgdW5zdGFraW5nUGVyaW9kQXJnID0gdW5zdGFraW5nUGVyaW9kID09PSBudWxsXG4gICAgPyBudWxsXG4gICAgOiB0eXBlb2YgdW5zdGFraW5nUGVyaW9kID09PSBcIm51bWJlclwiXG4gICAgICA/IG5ldyBCTih1bnN0YWtpbmdQZXJpb2QpXG4gICAgICA6IHVuc3Rha2luZ1BlcmlvZDtcblxuICBjb25zdCB2b2x1bWVXaW5kb3dBcmcgPSB2b2x1bWVXaW5kb3cgPT09IG51bGxcbiAgICA/IG51bGxcbiAgICA6IHR5cGVvZiB2b2x1bWVXaW5kb3cgPT09IFwibnVtYmVyXCJcbiAgICAgID8gbmV3IEJOKHZvbHVtZVdpbmRvdylcbiAgICAgIDogdm9sdW1lV2luZG93O1xuXG4gIGNvbnN0IFtjb25maWdQZGFdID0gZGVyaXZlU3Rha2luZ0NvbmZpZ1BEQSh0b2tlbk1pbnQsIG5vbmNlLCBwcm9ncmFtLnByb2dyYW1JZCk7XG5cbiAgcmV0dXJuIHByb2dyYW0ubWV0aG9kc1xuICAgIC5zZXRDb25maWcodW5zdGFraW5nUGVyaW9kQXJnLCB2b2x1bWVXaW5kb3dBcmcpXG4gICAgLmFjY291bnRzUGFydGlhbCh7XG4gICAgICBhZG1pbixcbiAgICAgIGNvbmZpZzogY29uZmlnUGRhLFxuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2xhc2goXG4gIHByb2dyYW06IFByb2dyYW08U3ZhdWx0PixcbiAgYWRtaW46IFB1YmxpY0tleSxcbiAgdG9rZW5NaW50OiBQdWJsaWNLZXksXG4gIG5vbmNlOiBudW1iZXIsXG4gIHVzZXJTdGFrZVBkYTogUHVibGljS2V5LFxuICBiYXNpc1BvaW50czogbnVtYmVyXG4pIHtcbiAgY29uc3QgW2NvbmZpZ1BkYV0gPSBkZXJpdmVTdGFraW5nQ29uZmlnUERBKHRva2VuTWludCwgbm9uY2UsIHByb2dyYW0ucHJvZ3JhbUlkKTtcbiAgY29uc3QgW3N0YWtlVmF1bHRdID0gZGVyaXZlU3Rha2VWYXVsdFBEQShjb25maWdQZGEsIHByb2dyYW0ucHJvZ3JhbUlkKTtcbiAgY29uc3QgZmVlVmF1bHQgPSBnZXRBc3NvY2lhdGVkVG9rZW5BZGRyZXNzU3luYyh0b2tlbk1pbnQsIEZFRV9BVVRIT1JJVFkpO1xuXG4gIHJldHVybiBwcm9ncmFtLm1ldGhvZHMuc2xhc2goYmFzaXNQb2ludHMpLmFjY291bnRzUGFydGlhbCh7XG4gICAgYWRtaW4sXG4gICAgdG9rZW5NaW50LFxuICAgIGNvbmZpZzogY29uZmlnUGRhLFxuICAgIHVzZXJTdGFrZTogdXNlclN0YWtlUGRhLFxuICAgIHN0YWtlVmF1bHQsXG4gICAgZmVlVmF1bHQsXG4gICAgdG9rZW5Qcm9ncmFtOiBUT0tFTl9QUk9HUkFNX0lELFxuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGFkZERlbGVnYXRlKFxuICBwcm9ncmFtOiBQcm9ncmFtPFN2YXVsdD4sXG4gIHN0YWtlcjogUHVibGljS2V5LFxuICBkZWxlZ2F0ZVdhbGxldDogUHVibGljS2V5LFxuICB0b2tlbk1pbnQ6IFB1YmxpY0tleSxcbiAgbm9uY2U6IG51bWJlclxuKSB7XG4gIGNvbnN0IFtjb25maWdQZGFdID0gZGVyaXZlU3Rha2luZ0NvbmZpZ1BEQSh0b2tlbk1pbnQsIG5vbmNlLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IFt1c2VyU3Rha2VQZGFdID0gZGVyaXZlVXNlclN0YWtlUERBKGNvbmZpZ1BkYSwgc3Rha2VyLCBwcm9ncmFtLnByb2dyYW1JZCk7XG4gIGNvbnN0IFtkZWxlZ2F0ZVBkYV0gPSBkZXJpdmVEZWxlZ2F0ZVBEQShjb25maWdQZGEsIGRlbGVnYXRlV2FsbGV0LCBwcm9ncmFtLnByb2dyYW1JZCk7XG5cbiAgcmV0dXJuIHByb2dyYW0ubWV0aG9kcy5hZGREZWxlZ2F0ZSgpLmFjY291bnRzUGFydGlhbCh7XG4gICAgc3Rha2VyLFxuICAgIGRlbGVnYXRlV2FsbGV0LFxuICAgIGNvbmZpZzogY29uZmlnUGRhLFxuICAgIHVzZXJTdGFrZTogdXNlclN0YWtlUGRhLFxuICAgIGRlbGVnYXRlOiBkZWxlZ2F0ZVBkYSxcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZW1vdmVEZWxlZ2F0ZShcbiAgcHJvZ3JhbTogUHJvZ3JhbTxTdmF1bHQ+LFxuICBzdGFrZXI6IFB1YmxpY0tleSxcbiAgZGVsZWdhdGVXYWxsZXQ6IFB1YmxpY0tleSxcbiAgdG9rZW5NaW50OiBQdWJsaWNLZXksXG4gIG5vbmNlOiBudW1iZXJcbikge1xuICBjb25zdCBbY29uZmlnUGRhXSA9IGRlcml2ZVN0YWtpbmdDb25maWdQREEodG9rZW5NaW50LCBub25jZSwgcHJvZ3JhbS5wcm9ncmFtSWQpO1xuICBjb25zdCBbZGVsZWdhdGVQZGFdID0gZGVyaXZlRGVsZWdhdGVQREEoY29uZmlnUGRhLCBkZWxlZ2F0ZVdhbGxldCwgcHJvZ3JhbS5wcm9ncmFtSWQpO1xuXG4gIHJldHVybiBwcm9ncmFtLm1ldGhvZHMucmVtb3ZlRGVsZWdhdGUoKS5hY2NvdW50c1BhcnRpYWwoe1xuICAgIHN0YWtlcixcbiAgICBjb25maWc6IGNvbmZpZ1BkYSxcbiAgICBkZWxlZ2F0ZTogZGVsZWdhdGVQZGEsXG4gIH0pO1xufVxuIl19
@@ -0,0 +1,46 @@
1
+ import { IdlAccounts, IdlEvents } from "@coral-xyz/anchor";
2
+ import { TxOptions } from "../utils";
3
+ export { Svault } from "../generated/types";
4
+ import type { Svault } from "../generated/types";
5
+ export type StakingConfigAccount = IdlAccounts<Svault>["stakingConfig"];
6
+ export type UserStakeAccount = IdlAccounts<Svault>["userStake"];
7
+ export type DelegateAccount = IdlAccounts<Svault>["delegate"];
8
+ export type StakingVaultInitializedEvent = IdlEvents<Svault>["stakingVaultInitialized"];
9
+ export type StakedEvent = IdlEvents<Svault>["staked"];
10
+ export type UnstakeInitiatedEvent = IdlEvents<Svault>["unstakeInitiated"];
11
+ export type WithdrawnEvent = IdlEvents<Svault>["withdrawn"];
12
+ export type RewardsPostedEvent = IdlEvents<Svault>["rewardsPosted"];
13
+ export type RewardsClaimedEvent = IdlEvents<Svault>["rewardsClaimed"];
14
+ export type SlashedEvent = IdlEvents<Svault>["slashed"];
15
+ export type DelegateAddedEvent = IdlEvents<Svault>["delegateAdded"];
16
+ export type DelegateRemovedEvent = IdlEvents<Svault>["delegateRemoved"];
17
+ export type SVaultEvent = {
18
+ name: "StakingVaultInitialized";
19
+ data: StakingVaultInitializedEvent;
20
+ } | {
21
+ name: "Staked";
22
+ data: StakedEvent;
23
+ } | {
24
+ name: "UnstakeInitiated";
25
+ data: UnstakeInitiatedEvent;
26
+ } | {
27
+ name: "Withdrawn";
28
+ data: WithdrawnEvent;
29
+ } | {
30
+ name: "RewardsPosted";
31
+ data: RewardsPostedEvent;
32
+ } | {
33
+ name: "RewardsClaimed";
34
+ data: RewardsClaimedEvent;
35
+ } | {
36
+ name: "Slashed";
37
+ data: SlashedEvent;
38
+ } | {
39
+ name: "DelegateAdded";
40
+ data: DelegateAddedEvent;
41
+ } | {
42
+ name: "DelegateRemoved";
43
+ data: DelegateRemovedEvent;
44
+ };
45
+ export interface SVaultTxOptions extends TxOptions {
46
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /*
3
+ * Type definitions for the SVault program.
4
+ * Exports IDL-derived types and SDK-friendly enums.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3ZhdWx0L3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O0dBR0ciLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogVHlwZSBkZWZpbml0aW9ucyBmb3IgdGhlIFNWYXVsdCBwcm9ncmFtLlxuICogRXhwb3J0cyBJREwtZGVyaXZlZCB0eXBlcyBhbmQgU0RLLWZyaWVuZGx5IGVudW1zLlxuICovXG5cbmltcG9ydCB7IElkbEFjY291bnRzLCBJZGxFdmVudHMgfSBmcm9tIFwiQGNvcmFsLXh5ei9hbmNob3JcIjtcbmltcG9ydCB7IFR4T3B0aW9ucyB9IGZyb20gXCIuLi91dGlsc1wiO1xuXG5leHBvcnQgeyBTdmF1bHQgfSBmcm9tIFwiLi4vZ2VuZXJhdGVkL3R5cGVzXCI7XG5pbXBvcnQgdHlwZSB7IFN2YXVsdCB9IGZyb20gXCIuLi9nZW5lcmF0ZWQvdHlwZXNcIjtcblxuLyogSURMLWRlcml2ZWQgQWNjb3VudCBUeXBlcyAqL1xuXG5leHBvcnQgdHlwZSBTdGFraW5nQ29uZmlnQWNjb3VudCA9IElkbEFjY291bnRzPFN2YXVsdD5bXCJzdGFraW5nQ29uZmlnXCJdO1xuZXhwb3J0IHR5cGUgVXNlclN0YWtlQWNjb3VudCA9IElkbEFjY291bnRzPFN2YXVsdD5bXCJ1c2VyU3Rha2VcIl07XG5leHBvcnQgdHlwZSBEZWxlZ2F0ZUFjY291bnQgPSBJZGxBY2NvdW50czxTdmF1bHQ+W1wiZGVsZWdhdGVcIl07XG5cbi8qIElETC1kZXJpdmVkIEV2ZW50IFR5cGVzICovXG5cbmV4cG9ydCB0eXBlIFN0YWtpbmdWYXVsdEluaXRpYWxpemVkRXZlbnQgPSBJZGxFdmVudHM8U3ZhdWx0PltcInN0YWtpbmdWYXVsdEluaXRpYWxpemVkXCJdO1xuZXhwb3J0IHR5cGUgU3Rha2VkRXZlbnQgPSBJZGxFdmVudHM8U3ZhdWx0PltcInN0YWtlZFwiXTtcbmV4cG9ydCB0eXBlIFVuc3Rha2VJbml0aWF0ZWRFdmVudCA9IElkbEV2ZW50czxTdmF1bHQ+W1widW5zdGFrZUluaXRpYXRlZFwiXTtcbmV4cG9ydCB0eXBlIFdpdGhkcmF3bkV2ZW50ID0gSWRsRXZlbnRzPFN2YXVsdD5bXCJ3aXRoZHJhd25cIl07XG5leHBvcnQgdHlwZSBSZXdhcmRzUG9zdGVkRXZlbnQgPSBJZGxFdmVudHM8U3ZhdWx0PltcInJld2FyZHNQb3N0ZWRcIl07XG5leHBvcnQgdHlwZSBSZXdhcmRzQ2xhaW1lZEV2ZW50ID0gSWRsRXZlbnRzPFN2YXVsdD5bXCJyZXdhcmRzQ2xhaW1lZFwiXTtcbmV4cG9ydCB0eXBlIFNsYXNoZWRFdmVudCA9IElkbEV2ZW50czxTdmF1bHQ+W1wic2xhc2hlZFwiXTtcbmV4cG9ydCB0eXBlIERlbGVnYXRlQWRkZWRFdmVudCA9IElkbEV2ZW50czxTdmF1bHQ+W1wiZGVsZWdhdGVBZGRlZFwiXTtcbmV4cG9ydCB0eXBlIERlbGVnYXRlUmVtb3ZlZEV2ZW50ID0gSWRsRXZlbnRzPFN2YXVsdD5bXCJkZWxlZ2F0ZVJlbW92ZWRcIl07XG5cbi8qIEV2ZW50IFVuaW9uIFR5cGUgKi9cblxuZXhwb3J0IHR5cGUgU1ZhdWx0RXZlbnQgPVxuICB8IHsgbmFtZTogXCJTdGFraW5nVmF1bHRJbml0aWFsaXplZFwiOyBkYXRhOiBTdGFraW5nVmF1bHRJbml0aWFsaXplZEV2ZW50IH1cbiAgfCB7IG5hbWU6IFwiU3Rha2VkXCI7IGRhdGE6IFN0YWtlZEV2ZW50IH1cbiAgfCB7IG5hbWU6IFwiVW5zdGFrZUluaXRpYXRlZFwiOyBkYXRhOiBVbnN0YWtlSW5pdGlhdGVkRXZlbnQgfVxuICB8IHsgbmFtZTogXCJXaXRoZHJhd25cIjsgZGF0YTogV2l0aGRyYXduRXZlbnQgfVxuICB8IHsgbmFtZTogXCJSZXdhcmRzUG9zdGVkXCI7IGRhdGE6IFJld2FyZHNQb3N0ZWRFdmVudCB9XG4gIHwgeyBuYW1lOiBcIlJld2FyZHNDbGFpbWVkXCI7IGRhdGE6IFJld2FyZHNDbGFpbWVkRXZlbnQgfVxuICB8IHsgbmFtZTogXCJTbGFzaGVkXCI7IGRhdGE6IFNsYXNoZWRFdmVudCB9XG4gIHwgeyBuYW1lOiBcIkRlbGVnYXRlQWRkZWRcIjsgZGF0YTogRGVsZWdhdGVBZGRlZEV2ZW50IH1cbiAgfCB7IG5hbWU6IFwiRGVsZWdhdGVSZW1vdmVkXCI7IGRhdGE6IERlbGVnYXRlUmVtb3ZlZEV2ZW50IH07XG5cbi8qIENsaWVudCBPcHRpb25zICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgU1ZhdWx0VHhPcHRpb25zIGV4dGVuZHMgVHhPcHRpb25zIHt9XG4iXX0=
@@ -0,0 +1,32 @@
1
+ import { Program } from "@coral-xyz/anchor";
2
+ import { PublicKey } from "@solana/web3.js";
3
+ import { Svault, StakingConfigAccount, UserStakeAccount, DelegateAccount } from "./types";
4
+ export declare function deriveStakingConfigPDA(tokenMint: PublicKey, nonce: number, programId?: PublicKey): [PublicKey, number];
5
+ export declare function deriveUserStakePDA(stakingConfig: PublicKey, user: PublicKey, programId?: PublicKey): [PublicKey, number];
6
+ export declare function deriveDelegatePDA(stakingConfig: PublicKey, delegate: PublicKey, programId?: PublicKey): [PublicKey, number];
7
+ export declare function deriveStakeVaultPDA(stakingConfig: PublicKey, programId?: PublicKey): [PublicKey, number];
8
+ export declare function deriveRewardVaultPDA(stakingConfig: PublicKey, programId?: PublicKey): [PublicKey, number];
9
+ export declare function fetchStakingConfigAccount(program: Program<Svault>, pda: PublicKey): Promise<StakingConfigAccount>;
10
+ export declare function fetchUserStakeAccount(program: Program<Svault>, pda: PublicKey): Promise<UserStakeAccount>;
11
+ export declare function fetchDelegateAccount(program: Program<Svault>, pda: PublicKey): Promise<DelegateAccount>;
12
+ /**
13
+ * Compute when withdrawal will be available based on unstake initiation time.
14
+ * @param unstakeInitiatedAt Unix timestamp when unstake was initiated (seconds)
15
+ * @param unstakingPeriodDays Number of days in unstaking period
16
+ * @returns Date when withdrawal becomes available
17
+ */
18
+ export declare function computeWithdrawAvailableAt(unstakeInitiatedAt: number, unstakingPeriodDays: number): Date;
19
+ /**
20
+ * Check if withdrawal is currently available.
21
+ * @param unstakeInitiatedAt Unix timestamp when unstake was initiated (seconds)
22
+ * @param unstakingPeriodDays Number of days in unstaking period
23
+ * @returns true if unstaking period has elapsed
24
+ */
25
+ export declare function isWithdrawAvailable(unstakeInitiatedAt: number, unstakingPeriodDays: number): boolean;
26
+ /**
27
+ * Compute the time remaining until withdrawal is available.
28
+ * @param unstakeInitiatedAt Unix timestamp when unstake was initiated (seconds)
29
+ * @param unstakingPeriodDays Number of days in unstaking period
30
+ * @returns Seconds remaining, or 0 if already available
31
+ */
32
+ export declare function getTimeUntilWithdraw(unstakeInitiatedAt: number, unstakingPeriodDays: number): number;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /*
3
+ * Utility functions for the SVault program.
4
+ * PDA derivation, state parsing, and account fetching.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.deriveStakingConfigPDA = deriveStakingConfigPDA;
8
+ exports.deriveUserStakePDA = deriveUserStakePDA;
9
+ exports.deriveDelegatePDA = deriveDelegatePDA;
10
+ exports.deriveStakeVaultPDA = deriveStakeVaultPDA;
11
+ exports.deriveRewardVaultPDA = deriveRewardVaultPDA;
12
+ exports.fetchStakingConfigAccount = fetchStakingConfigAccount;
13
+ exports.fetchUserStakeAccount = fetchUserStakeAccount;
14
+ exports.fetchDelegateAccount = fetchDelegateAccount;
15
+ exports.computeWithdrawAvailableAt = computeWithdrawAvailableAt;
16
+ exports.isWithdrawAvailable = isWithdrawAvailable;
17
+ exports.getTimeUntilWithdraw = getTimeUntilWithdraw;
18
+ const web3_js_1 = require("@solana/web3.js");
19
+ const constants_1 = require("./constants");
20
+ /* PDA Derivation */
21
+ function deriveStakingConfigPDA(tokenMint, nonce, programId = constants_1.PROGRAM_ID) {
22
+ const nonceBuffer = Buffer.alloc(2);
23
+ nonceBuffer.writeUInt16LE(nonce);
24
+ return web3_js_1.PublicKey.findProgramAddressSync([constants_1.STAKING_CONFIG_SEED, tokenMint.toBuffer(), nonceBuffer], programId);
25
+ }
26
+ function deriveUserStakePDA(stakingConfig, user, programId = constants_1.PROGRAM_ID) {
27
+ return web3_js_1.PublicKey.findProgramAddressSync([constants_1.USER_STAKE_SEED, stakingConfig.toBuffer(), user.toBuffer()], programId);
28
+ }
29
+ function deriveDelegatePDA(stakingConfig, delegate, programId = constants_1.PROGRAM_ID) {
30
+ // Uses USER_STAKE_SEED to prevent delegate from also being a staker
31
+ return web3_js_1.PublicKey.findProgramAddressSync([constants_1.USER_STAKE_SEED, stakingConfig.toBuffer(), delegate.toBuffer()], programId);
32
+ }
33
+ function deriveStakeVaultPDA(stakingConfig, programId = constants_1.PROGRAM_ID) {
34
+ return web3_js_1.PublicKey.findProgramAddressSync([constants_1.STAKE_VAULT_SEED, stakingConfig.toBuffer()], programId);
35
+ }
36
+ function deriveRewardVaultPDA(stakingConfig, programId = constants_1.PROGRAM_ID) {
37
+ return web3_js_1.PublicKey.findProgramAddressSync([constants_1.REWARD_VAULT_SEED, stakingConfig.toBuffer()], programId);
38
+ }
39
+ /* Fetchers */
40
+ async function fetchStakingConfigAccount(program, pda) {
41
+ return program.account.stakingConfig.fetch(pda);
42
+ }
43
+ async function fetchUserStakeAccount(program, pda) {
44
+ return program.account.userStake.fetch(pda);
45
+ }
46
+ async function fetchDelegateAccount(program, pda) {
47
+ return program.account.delegate.fetch(pda);
48
+ }
49
+ /* Helpers */
50
+ /**
51
+ * Compute when withdrawal will be available based on unstake initiation time.
52
+ * @param unstakeInitiatedAt Unix timestamp when unstake was initiated (seconds)
53
+ * @param unstakingPeriodDays Number of days in unstaking period
54
+ * @returns Date when withdrawal becomes available
55
+ */
56
+ function computeWithdrawAvailableAt(unstakeInitiatedAt, unstakingPeriodDays) {
57
+ const availableAtSeconds = unstakeInitiatedAt + unstakingPeriodDays * constants_1.SECONDS_PER_DAY;
58
+ return new Date(availableAtSeconds * 1000);
59
+ }
60
+ /**
61
+ * Check if withdrawal is currently available.
62
+ * @param unstakeInitiatedAt Unix timestamp when unstake was initiated (seconds)
63
+ * @param unstakingPeriodDays Number of days in unstaking period
64
+ * @returns true if unstaking period has elapsed
65
+ */
66
+ function isWithdrawAvailable(unstakeInitiatedAt, unstakingPeriodDays) {
67
+ if (unstakeInitiatedAt === 0)
68
+ return false;
69
+ const now = Math.floor(Date.now() / 1000);
70
+ const availableAt = unstakeInitiatedAt + unstakingPeriodDays * constants_1.SECONDS_PER_DAY;
71
+ return now >= availableAt;
72
+ }
73
+ /**
74
+ * Compute the time remaining until withdrawal is available.
75
+ * @param unstakeInitiatedAt Unix timestamp when unstake was initiated (seconds)
76
+ * @param unstakingPeriodDays Number of days in unstaking period
77
+ * @returns Seconds remaining, or 0 if already available
78
+ */
79
+ function getTimeUntilWithdraw(unstakeInitiatedAt, unstakingPeriodDays) {
80
+ if (unstakeInitiatedAt === 0)
81
+ return 0;
82
+ const now = Math.floor(Date.now() / 1000);
83
+ const availableAt = unstakeInitiatedAt + unstakingPeriodDays * constants_1.SECONDS_PER_DAY;
84
+ return Math.max(0, availableAt - now);
85
+ }
86
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3ZhdWx0L3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O0dBR0c7O0FBZ0JILHdEQVdDO0FBRUQsZ0RBU0M7QUFFRCw4Q0FVQztBQUVELGtEQVFDO0FBRUQsb0RBUUM7QUFJRCw4REFLQztBQUVELHNEQUtDO0FBRUQsb0RBS0M7QUFVRCxnRUFNQztBQVFELGtEQVFDO0FBUUQsb0RBUUM7QUExSUQsNkNBQTRDO0FBQzVDLDJDQU9xQjtBQUdyQixvQkFBb0I7QUFFcEIsU0FBZ0Isc0JBQXNCLENBQ3BDLFNBQW9CLEVBQ3BCLEtBQWEsRUFDYixZQUF1QixzQkFBVTtJQUVqQyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BDLFdBQVcsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDakMsT0FBTyxtQkFBUyxDQUFDLHNCQUFzQixDQUNyQyxDQUFDLCtCQUFtQixFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxXQUFXLENBQUMsRUFDeEQsU0FBUyxDQUNWLENBQUM7QUFDSixDQUFDO0FBRUQsU0FBZ0Isa0JBQWtCLENBQ2hDLGFBQXdCLEVBQ3hCLElBQWUsRUFDZixZQUF1QixzQkFBVTtJQUVqQyxPQUFPLG1CQUFTLENBQUMsc0JBQXNCLENBQ3JDLENBQUMsMkJBQWUsRUFBRSxhQUFhLENBQUMsUUFBUSxFQUFFLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLEVBQzVELFNBQVMsQ0FDVixDQUFDO0FBQ0osQ0FBQztBQUVELFNBQWdCLGlCQUFpQixDQUMvQixhQUF3QixFQUN4QixRQUFtQixFQUNuQixZQUF1QixzQkFBVTtJQUVqQyxvRUFBb0U7SUFDcEUsT0FBTyxtQkFBUyxDQUFDLHNCQUFzQixDQUNyQyxDQUFDLDJCQUFlLEVBQUUsYUFBYSxDQUFDLFFBQVEsRUFBRSxFQUFFLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxFQUNoRSxTQUFTLENBQ1YsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQixtQkFBbUIsQ0FDakMsYUFBd0IsRUFDeEIsWUFBdUIsc0JBQVU7SUFFakMsT0FBTyxtQkFBUyxDQUFDLHNCQUFzQixDQUNyQyxDQUFDLDRCQUFnQixFQUFFLGFBQWEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxFQUM1QyxTQUFTLENBQ1YsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQixvQkFBb0IsQ0FDbEMsYUFBd0IsRUFDeEIsWUFBdUIsc0JBQVU7SUFFakMsT0FBTyxtQkFBUyxDQUFDLHNCQUFzQixDQUNyQyxDQUFDLDZCQUFpQixFQUFFLGFBQWEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxFQUM3QyxTQUFTLENBQ1YsQ0FBQztBQUNKLENBQUM7QUFFRCxjQUFjO0FBRVAsS0FBSyxVQUFVLHlCQUF5QixDQUM3QyxPQUF3QixFQUN4QixHQUFjO0lBRWQsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDbEQsQ0FBQztBQUVNLEtBQUssVUFBVSxxQkFBcUIsQ0FDekMsT0FBd0IsRUFDeEIsR0FBYztJQUVkLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzlDLENBQUM7QUFFTSxLQUFLLFVBQVUsb0JBQW9CLENBQ3hDLE9BQXdCLEVBQ3hCLEdBQWM7SUFFZCxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUM3QyxDQUFDO0FBRUQsYUFBYTtBQUViOzs7OztHQUtHO0FBQ0gsU0FBZ0IsMEJBQTBCLENBQ3hDLGtCQUEwQixFQUMxQixtQkFBMkI7SUFFM0IsTUFBTSxrQkFBa0IsR0FBRyxrQkFBa0IsR0FBRyxtQkFBbUIsR0FBRywyQkFBZSxDQUFDO0lBQ3RGLE9BQU8sSUFBSSxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLENBQUM7QUFDN0MsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0IsbUJBQW1CLENBQ2pDLGtCQUEwQixFQUMxQixtQkFBMkI7SUFFM0IsSUFBSSxrQkFBa0IsS0FBSyxDQUFDO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDM0MsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDMUMsTUFBTSxXQUFXLEdBQUcsa0JBQWtCLEdBQUcsbUJBQW1CLEdBQUcsMkJBQWUsQ0FBQztJQUMvRSxPQUFPLEdBQUcsSUFBSSxXQUFXLENBQUM7QUFDNUIsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBZ0Isb0JBQW9CLENBQ2xDLGtCQUEwQixFQUMxQixtQkFBMkI7SUFFM0IsSUFBSSxrQkFBa0IsS0FBSyxDQUFDO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDdkMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDMUMsTUFBTSxXQUFXLEdBQUcsa0JBQWtCLEdBQUcsbUJBQW1CLEdBQUcsMkJBQWUsQ0FBQztJQUMvRSxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFdBQVcsR0FBRyxHQUFHLENBQUMsQ0FBQztBQUN4QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIFV0aWxpdHkgZnVuY3Rpb25zIGZvciB0aGUgU1ZhdWx0IHByb2dyYW0uXG4gKiBQREEgZGVyaXZhdGlvbiwgc3RhdGUgcGFyc2luZywgYW5kIGFjY291bnQgZmV0Y2hpbmcuXG4gKi9cblxuaW1wb3J0IHsgUHJvZ3JhbSB9IGZyb20gXCJAY29yYWwteHl6L2FuY2hvclwiO1xuaW1wb3J0IHsgUHVibGljS2V5IH0gZnJvbSBcIkBzb2xhbmEvd2ViMy5qc1wiO1xuaW1wb3J0IHtcbiAgU1RBS0lOR19DT05GSUdfU0VFRCxcbiAgVVNFUl9TVEFLRV9TRUVELFxuICBTVEFLRV9WQVVMVF9TRUVELFxuICBSRVdBUkRfVkFVTFRfU0VFRCxcbiAgUFJPR1JBTV9JRCxcbiAgU0VDT05EU19QRVJfREFZLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IFN2YXVsdCwgU3Rha2luZ0NvbmZpZ0FjY291bnQsIFVzZXJTdGFrZUFjY291bnQsIERlbGVnYXRlQWNjb3VudCB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qIFBEQSBEZXJpdmF0aW9uICovXG5cbmV4cG9ydCBmdW5jdGlvbiBkZXJpdmVTdGFraW5nQ29uZmlnUERBKFxuICB0b2tlbk1pbnQ6IFB1YmxpY0tleSxcbiAgbm9uY2U6IG51bWJlcixcbiAgcHJvZ3JhbUlkOiBQdWJsaWNLZXkgPSBQUk9HUkFNX0lEXG4pOiBbUHVibGljS2V5LCBudW1iZXJdIHtcbiAgY29uc3Qgbm9uY2VCdWZmZXIgPSBCdWZmZXIuYWxsb2MoMik7XG4gIG5vbmNlQnVmZmVyLndyaXRlVUludDE2TEUobm9uY2UpO1xuICByZXR1cm4gUHVibGljS2V5LmZpbmRQcm9ncmFtQWRkcmVzc1N5bmMoXG4gICAgW1NUQUtJTkdfQ09ORklHX1NFRUQsIHRva2VuTWludC50b0J1ZmZlcigpLCBub25jZUJ1ZmZlcl0sXG4gICAgcHJvZ3JhbUlkXG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXJpdmVVc2VyU3Rha2VQREEoXG4gIHN0YWtpbmdDb25maWc6IFB1YmxpY0tleSxcbiAgdXNlcjogUHVibGljS2V5LFxuICBwcm9ncmFtSWQ6IFB1YmxpY0tleSA9IFBST0dSQU1fSURcbik6IFtQdWJsaWNLZXksIG51bWJlcl0ge1xuICByZXR1cm4gUHVibGljS2V5LmZpbmRQcm9ncmFtQWRkcmVzc1N5bmMoXG4gICAgW1VTRVJfU1RBS0VfU0VFRCwgc3Rha2luZ0NvbmZpZy50b0J1ZmZlcigpLCB1c2VyLnRvQnVmZmVyKCldLFxuICAgIHByb2dyYW1JZFxuICApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZGVyaXZlRGVsZWdhdGVQREEoXG4gIHN0YWtpbmdDb25maWc6IFB1YmxpY0tleSxcbiAgZGVsZWdhdGU6IFB1YmxpY0tleSxcbiAgcHJvZ3JhbUlkOiBQdWJsaWNLZXkgPSBQUk9HUkFNX0lEXG4pOiBbUHVibGljS2V5LCBudW1iZXJdIHtcbiAgLy8gVXNlcyBVU0VSX1NUQUtFX1NFRUQgdG8gcHJldmVudCBkZWxlZ2F0ZSBmcm9tIGFsc28gYmVpbmcgYSBzdGFrZXJcbiAgcmV0dXJuIFB1YmxpY0tleS5maW5kUHJvZ3JhbUFkZHJlc3NTeW5jKFxuICAgIFtVU0VSX1NUQUtFX1NFRUQsIHN0YWtpbmdDb25maWcudG9CdWZmZXIoKSwgZGVsZWdhdGUudG9CdWZmZXIoKV0sXG4gICAgcHJvZ3JhbUlkXG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXJpdmVTdGFrZVZhdWx0UERBKFxuICBzdGFraW5nQ29uZmlnOiBQdWJsaWNLZXksXG4gIHByb2dyYW1JZDogUHVibGljS2V5ID0gUFJPR1JBTV9JRFxuKTogW1B1YmxpY0tleSwgbnVtYmVyXSB7XG4gIHJldHVybiBQdWJsaWNLZXkuZmluZFByb2dyYW1BZGRyZXNzU3luYyhcbiAgICBbU1RBS0VfVkFVTFRfU0VFRCwgc3Rha2luZ0NvbmZpZy50b0J1ZmZlcigpXSxcbiAgICBwcm9ncmFtSWRcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlcml2ZVJld2FyZFZhdWx0UERBKFxuICBzdGFraW5nQ29uZmlnOiBQdWJsaWNLZXksXG4gIHByb2dyYW1JZDogUHVibGljS2V5ID0gUFJPR1JBTV9JRFxuKTogW1B1YmxpY0tleSwgbnVtYmVyXSB7XG4gIHJldHVybiBQdWJsaWNLZXkuZmluZFByb2dyYW1BZGRyZXNzU3luYyhcbiAgICBbUkVXQVJEX1ZBVUxUX1NFRUQsIHN0YWtpbmdDb25maWcudG9CdWZmZXIoKV0sXG4gICAgcHJvZ3JhbUlkXG4gICk7XG59XG5cbi8qIEZldGNoZXJzICovXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaFN0YWtpbmdDb25maWdBY2NvdW50KFxuICBwcm9ncmFtOiBQcm9ncmFtPFN2YXVsdD4sXG4gIHBkYTogUHVibGljS2V5XG4pOiBQcm9taXNlPFN0YWtpbmdDb25maWdBY2NvdW50PiB7XG4gIHJldHVybiBwcm9ncmFtLmFjY291bnQuc3Rha2luZ0NvbmZpZy5mZXRjaChwZGEpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmV0Y2hVc2VyU3Rha2VBY2NvdW50KFxuICBwcm9ncmFtOiBQcm9ncmFtPFN2YXVsdD4sXG4gIHBkYTogUHVibGljS2V5XG4pOiBQcm9taXNlPFVzZXJTdGFrZUFjY291bnQ+IHtcbiAgcmV0dXJuIHByb2dyYW0uYWNjb3VudC51c2VyU3Rha2UuZmV0Y2gocGRhKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZldGNoRGVsZWdhdGVBY2NvdW50KFxuICBwcm9ncmFtOiBQcm9ncmFtPFN2YXVsdD4sXG4gIHBkYTogUHVibGljS2V5XG4pOiBQcm9taXNlPERlbGVnYXRlQWNjb3VudD4ge1xuICByZXR1cm4gcHJvZ3JhbS5hY2NvdW50LmRlbGVnYXRlLmZldGNoKHBkYSk7XG59XG5cbi8qIEhlbHBlcnMgKi9cblxuLyoqXG4gKiBDb21wdXRlIHdoZW4gd2l0aGRyYXdhbCB3aWxsIGJlIGF2YWlsYWJsZSBiYXNlZCBvbiB1bnN0YWtlIGluaXRpYXRpb24gdGltZS5cbiAqIEBwYXJhbSB1bnN0YWtlSW5pdGlhdGVkQXQgVW5peCB0aW1lc3RhbXAgd2hlbiB1bnN0YWtlIHdhcyBpbml0aWF0ZWQgKHNlY29uZHMpXG4gKiBAcGFyYW0gdW5zdGFraW5nUGVyaW9kRGF5cyBOdW1iZXIgb2YgZGF5cyBpbiB1bnN0YWtpbmcgcGVyaW9kXG4gKiBAcmV0dXJucyBEYXRlIHdoZW4gd2l0aGRyYXdhbCBiZWNvbWVzIGF2YWlsYWJsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZVdpdGhkcmF3QXZhaWxhYmxlQXQoXG4gIHVuc3Rha2VJbml0aWF0ZWRBdDogbnVtYmVyLFxuICB1bnN0YWtpbmdQZXJpb2REYXlzOiBudW1iZXJcbik6IERhdGUge1xuICBjb25zdCBhdmFpbGFibGVBdFNlY29uZHMgPSB1bnN0YWtlSW5pdGlhdGVkQXQgKyB1bnN0YWtpbmdQZXJpb2REYXlzICogU0VDT05EU19QRVJfREFZO1xuICByZXR1cm4gbmV3IERhdGUoYXZhaWxhYmxlQXRTZWNvbmRzICogMTAwMCk7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgd2l0aGRyYXdhbCBpcyBjdXJyZW50bHkgYXZhaWxhYmxlLlxuICogQHBhcmFtIHVuc3Rha2VJbml0aWF0ZWRBdCBVbml4IHRpbWVzdGFtcCB3aGVuIHVuc3Rha2Ugd2FzIGluaXRpYXRlZCAoc2Vjb25kcylcbiAqIEBwYXJhbSB1bnN0YWtpbmdQZXJpb2REYXlzIE51bWJlciBvZiBkYXlzIGluIHVuc3Rha2luZyBwZXJpb2RcbiAqIEByZXR1cm5zIHRydWUgaWYgdW5zdGFraW5nIHBlcmlvZCBoYXMgZWxhcHNlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNXaXRoZHJhd0F2YWlsYWJsZShcbiAgdW5zdGFrZUluaXRpYXRlZEF0OiBudW1iZXIsXG4gIHVuc3Rha2luZ1BlcmlvZERheXM6IG51bWJlclxuKTogYm9vbGVhbiB7XG4gIGlmICh1bnN0YWtlSW5pdGlhdGVkQXQgPT09IDApIHJldHVybiBmYWxzZTtcbiAgY29uc3Qgbm93ID0gTWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCk7XG4gIGNvbnN0IGF2YWlsYWJsZUF0ID0gdW5zdGFrZUluaXRpYXRlZEF0ICsgdW5zdGFraW5nUGVyaW9kRGF5cyAqIFNFQ09ORFNfUEVSX0RBWTtcbiAgcmV0dXJuIG5vdyA+PSBhdmFpbGFibGVBdDtcbn1cblxuLyoqXG4gKiBDb21wdXRlIHRoZSB0aW1lIHJlbWFpbmluZyB1bnRpbCB3aXRoZHJhd2FsIGlzIGF2YWlsYWJsZS5cbiAqIEBwYXJhbSB1bnN0YWtlSW5pdGlhdGVkQXQgVW5peCB0aW1lc3RhbXAgd2hlbiB1bnN0YWtlIHdhcyBpbml0aWF0ZWQgKHNlY29uZHMpXG4gKiBAcGFyYW0gdW5zdGFraW5nUGVyaW9kRGF5cyBOdW1iZXIgb2YgZGF5cyBpbiB1bnN0YWtpbmcgcGVyaW9kXG4gKiBAcmV0dXJucyBTZWNvbmRzIHJlbWFpbmluZywgb3IgMCBpZiBhbHJlYWR5IGF2YWlsYWJsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0VGltZVVudGlsV2l0aGRyYXcoXG4gIHVuc3Rha2VJbml0aWF0ZWRBdDogbnVtYmVyLFxuICB1bnN0YWtpbmdQZXJpb2REYXlzOiBudW1iZXJcbik6IG51bWJlciB7XG4gIGlmICh1bnN0YWtlSW5pdGlhdGVkQXQgPT09IDApIHJldHVybiAwO1xuICBjb25zdCBub3cgPSBNYXRoLmZsb29yKERhdGUubm93KCkgLyAxMDAwKTtcbiAgY29uc3QgYXZhaWxhYmxlQXQgPSB1bnN0YWtlSW5pdGlhdGVkQXQgKyB1bnN0YWtpbmdQZXJpb2REYXlzICogU0VDT05EU19QRVJfREFZO1xuICByZXR1cm4gTWF0aC5tYXgoMCwgYXZhaWxhYmxlQXQgLSBub3cpO1xufVxuIl19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zcomb/programs-sdk",
3
- "version": "1.5.1",
3
+ "version": "1.7.0",
4
4
  "description": "SDK for ZCombinator Programs",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -606,13 +606,19 @@ export class FutarchyClient {
606
606
 
607
607
  // Create ALT
608
608
  const createTx = new Transaction().add(createIx);
609
- createTx.recentBlockhash = (await provider.connection.getLatestBlockhash()).blockhash;
609
+ const { blockhash: createBlockhash, lastValidBlockHeight: createLastValidBlockHeight } =
610
+ await provider.connection.getLatestBlockhash('confirmed');
611
+ createTx.recentBlockhash = createBlockhash;
610
612
  createTx.feePayer = creator;
611
613
  const signedTx = await provider.wallet.signTransaction(createTx);
612
614
  const sig = await provider.connection.sendRawTransaction(signedTx.serialize(), {
613
615
  skipPreflight: true,
614
616
  });
615
- await provider.connection.confirmTransaction(sig, "confirmed");
617
+ await provider.connection.confirmTransaction({
618
+ signature: sig,
619
+ blockhash: createBlockhash,
620
+ lastValidBlockHeight: createLastValidBlockHeight,
621
+ }, "confirmed");
616
622
 
617
623
  // Extend ALT with addresses
618
624
  // Use skipPreflight to avoid race condition where simulation sees stale state
@@ -627,13 +633,19 @@ export class FutarchyClient {
627
633
  addresses: chunk,
628
634
  });
629
635
  const extendTx = new Transaction().add(extendIx);
630
- extendTx.recentBlockhash = (await provider.connection.getLatestBlockhash()).blockhash;
636
+ const { blockhash: extendBlockhash, lastValidBlockHeight: extendLastValidBlockHeight } =
637
+ await provider.connection.getLatestBlockhash('confirmed');
638
+ extendTx.recentBlockhash = extendBlockhash;
631
639
  extendTx.feePayer = creator;
632
640
  const signedExtendTx = await provider.wallet.signTransaction(extendTx);
633
641
  const extendSig = await provider.connection.sendRawTransaction(signedExtendTx.serialize(), {
634
642
  skipPreflight: true,
635
643
  });
636
- await provider.connection.confirmTransaction(extendSig, "confirmed");
644
+ await provider.connection.confirmTransaction({
645
+ signature: extendSig,
646
+ blockhash: extendBlockhash,
647
+ lastValidBlockHeight: extendLastValidBlockHeight,
648
+ }, "confirmed");
637
649
  }
638
650
 
639
651
  return { altAddress };
@@ -646,13 +658,19 @@ export class FutarchyClient {
646
658
  * @param creator - The user redeeming
647
659
  * @param proposalPda - The proposal PDA
648
660
  * @param altAddress - Optional ALT address (will be created if not provided for 3+ options)
649
- * @returns Unsigned versioned transaction, ALT address, and number of options
661
+ * @returns Unsigned versioned transaction, ALT address, number of options, and blockhash info for confirmation
650
662
  */
651
663
  async redeemLiquidityVersioned(
652
664
  creator: PublicKey,
653
665
  proposalPda: PublicKey,
654
666
  altAddress?: PublicKey,
655
- ): Promise<{ versionedTx: VersionedTransaction; altAddress: PublicKey; numOptions: number }> {
667
+ ): Promise<{
668
+ versionedTx: VersionedTransaction;
669
+ altAddress: PublicKey;
670
+ numOptions: number;
671
+ blockhash: string;
672
+ lastValidBlockHeight: number;
673
+ }> {
656
674
  const provider = this.program.provider as AnchorProvider;
657
675
  const { builder, numOptions } = await this.redeemLiquidity(creator, proposalPda);
658
676
 
@@ -710,8 +728,8 @@ export class FutarchyClient {
710
728
  const instruction = await builder.instruction();
711
729
  const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 500_000 });
712
730
 
713
- // Get fresh blockhash
714
- const { blockhash } = await provider.connection.getLatestBlockhash();
731
+ // Get fresh blockhash with lastValidBlockHeight for confirmation tracking
732
+ const { blockhash, lastValidBlockHeight } = await provider.connection.getLatestBlockhash('confirmed');
715
733
 
716
734
  // Build versioned transaction using the verified ALT (no re-fetch)
717
735
  const versionedTx = this.buildVersionedTxWithALT(
@@ -721,23 +739,56 @@ export class FutarchyClient {
721
739
  blockhash,
722
740
  );
723
741
 
724
- // Return the versioned transaction for the caller to sign and send
742
+ // Return the versioned transaction along with blockhash info for proper confirmation
725
743
  // This allows the caller to use their own signing mechanism (e.g., keypair.sign)
726
- return { versionedTx, altAddress: altPubkey, numOptions };
744
+ return { versionedTx, altAddress: altPubkey, numOptions, blockhash, lastValidBlockHeight };
727
745
  }
728
746
 
729
747
  /**
730
- * Helper to send a signed versioned transaction.
748
+ * Helper to send a signed versioned transaction with robust confirmation handling.
749
+ * Uses blockhash-based confirmation to properly detect transaction expiration
750
+ * instead of relying on a fixed timeout.
751
+ *
752
+ * @param signedTx - The signed versioned transaction to send
753
+ * @param confirmationInfo - Optional blockhash info from when the transaction was built.
754
+ * If not provided, a fresh blockhash will be fetched (less accurate).
731
755
  */
732
756
  async sendVersionedTransaction(
733
757
  signedTx: VersionedTransaction,
758
+ confirmationInfo?: { blockhash: string; lastValidBlockHeight: number },
734
759
  ): Promise<string> {
735
760
  const provider = this.program.provider as AnchorProvider;
761
+
762
+ // Use provided blockhash info or fetch fresh one
763
+ // Using the original blockhash is more accurate for detecting expiration
764
+ let blockhash: string;
765
+ let lastValidBlockHeight: number;
766
+
767
+ if (confirmationInfo) {
768
+ blockhash = confirmationInfo.blockhash;
769
+ lastValidBlockHeight = confirmationInfo.lastValidBlockHeight;
770
+ } else {
771
+ // Fallback: get fresh blockhash (may wait longer than necessary if tx already expired)
772
+ const latestBlockhash = await provider.connection.getLatestBlockhash('confirmed');
773
+ blockhash = latestBlockhash.blockhash;
774
+ lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
775
+ }
776
+
736
777
  const signature = await provider.connection.sendTransaction(signedTx, {
737
778
  skipPreflight: false,
738
779
  preflightCommitment: 'confirmed',
739
780
  });
740
- await provider.connection.confirmTransaction(signature, 'confirmed');
781
+
782
+ // Use blockhash-based confirmation which waits until either:
783
+ // 1. Transaction is confirmed
784
+ // 2. Blockhash expires (lastValidBlockHeight passed)
785
+ // This is more robust than a fixed timeout on congested networks
786
+ await provider.connection.confirmTransaction({
787
+ signature,
788
+ blockhash,
789
+ lastValidBlockHeight,
790
+ }, 'confirmed');
791
+
741
792
  return signature;
742
793
  }
743
794
 
@@ -810,13 +861,19 @@ export class FutarchyClient {
810
861
 
811
862
  // Send create transaction immediately, skip preflight to avoid slot timing issues
812
863
  const createTx = new Transaction().add(createIx);
813
- createTx.recentBlockhash = (await provider.connection.getLatestBlockhash()).blockhash;
864
+ const { blockhash: createBlockhash, lastValidBlockHeight: createLastValidBlockHeight } =
865
+ await provider.connection.getLatestBlockhash('confirmed');
866
+ createTx.recentBlockhash = createBlockhash;
814
867
  createTx.feePayer = creator;
815
868
  const signedTx = await provider.wallet.signTransaction(createTx);
816
869
  const sig = await provider.connection.sendRawTransaction(signedTx.serialize(), {
817
870
  skipPreflight: true,
818
871
  });
819
- await provider.connection.confirmTransaction(sig, "confirmed");
872
+ await provider.connection.confirmTransaction({
873
+ signature: sig,
874
+ blockhash: createBlockhash,
875
+ lastValidBlockHeight: createLastValidBlockHeight,
876
+ }, "confirmed");
820
877
 
821
878
  // Split addresses into chunks to avoid transaction size limits
822
879
  // Each address is 32 bytes, ~20 addresses per extend instruction is safe
@@ -832,13 +889,19 @@ export class FutarchyClient {
832
889
  addresses: chunk,
833
890
  });
834
891
  const extendTx = new Transaction().add(extendIx);
835
- extendTx.recentBlockhash = (await provider.connection.getLatestBlockhash()).blockhash;
892
+ const { blockhash: extendBlockhash, lastValidBlockHeight: extendLastValidBlockHeight } =
893
+ await provider.connection.getLatestBlockhash('confirmed');
894
+ extendTx.recentBlockhash = extendBlockhash;
836
895
  extendTx.feePayer = creator;
837
896
  const signedExtendTx = await provider.wallet.signTransaction(extendTx);
838
897
  const extendSig = await provider.connection.sendRawTransaction(signedExtendTx.serialize(), {
839
898
  skipPreflight: true,
840
899
  });
841
- await provider.connection.confirmTransaction(extendSig, "confirmed");
900
+ await provider.connection.confirmTransaction({
901
+ signature: extendSig,
902
+ blockhash: extendBlockhash,
903
+ lastValidBlockHeight: extendLastValidBlockHeight,
904
+ }, "confirmed");
842
905
  }
843
906
 
844
907
  return { altAddress };
@@ -856,11 +919,16 @@ export class FutarchyClient {
856
919
  payer: PublicKey,
857
920
  instructions: TransactionInstruction[],
858
921
  altAddress: PublicKey,
859
- ): Promise<VersionedTransaction> {
922
+ ): Promise<{
923
+ versionedTx: VersionedTransaction;
924
+ blockhash: string;
925
+ lastValidBlockHeight: number;
926
+ }> {
860
927
  const provider = this.program.provider as AnchorProvider;
861
928
  const alt = await this.fetchALT(altAddress);
862
- const { blockhash } = await provider.connection.getLatestBlockhash();
863
- return this.buildVersionedTxWithALT(payer, instructions, alt, blockhash);
929
+ const { blockhash, lastValidBlockHeight } = await provider.connection.getLatestBlockhash('confirmed');
930
+ const versionedTx = this.buildVersionedTxWithALT(payer, instructions, alt, blockhash);
931
+ return { versionedTx, blockhash, lastValidBlockHeight };
864
932
  }
865
933
 
866
934
  buildVersionedTxWithALT(
@@ -1,3 +1,4 @@
1
1
  export { default as AmmIDL } from "./amm.json";
2
2
  export { default as FutarchyIDL } from "./futarchy.json";
3
3
  export { default as VaultIDL } from "./vault.json";
4
+ export { default as SvaultIDL } from "./svault.json";