@streamflow/staking 7.0.0-alpha.7 → 7.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 +52 -6
- package/dist/cjs/__tests__/solana/rewards.spec.js +61 -0
- package/dist/cjs/index.js +3 -5
- package/dist/cjs/solana/client.js +76 -57
- package/dist/cjs/solana/constants.js +12 -3
- package/dist/cjs/solana/descriptor/idl/reward_pool.json +3 -5
- package/dist/cjs/solana/descriptor/idl/stake_pool.json +60 -262
- package/dist/cjs/solana/{utils.js → lib/fee-amounts.js} +5 -22
- package/dist/cjs/solana/lib/rewards.js +41 -21
- package/dist/cjs/solana/lib/stake-weight.js +19 -0
- package/dist/esm/__tests__/solana/rewards.spec.d.ts +1 -0
- package/dist/esm/__tests__/solana/rewards.spec.js +56 -0
- package/dist/esm/index.d.ts +3 -2
- package/dist/esm/index.js +3 -2
- package/dist/esm/solana/client.d.ts +14 -3
- package/dist/esm/solana/client.js +50 -32
- package/dist/esm/solana/constants.d.ts +5 -3
- package/dist/esm/solana/constants.js +13 -4
- package/dist/esm/solana/descriptor/idl/reward_pool.json +3 -5
- package/dist/esm/solana/descriptor/idl/stake_pool.json +60 -262
- package/dist/esm/solana/{utils.d.ts → lib/fee-amounts.d.ts} +0 -2
- package/dist/esm/solana/{utils.js → lib/fee-amounts.js} +2 -14
- package/dist/esm/solana/lib/rewards.d.ts +6 -4
- package/dist/esm/solana/lib/rewards.js +38 -22
- package/dist/esm/solana/lib/stake-weight.d.ts +2 -0
- package/dist/esm/solana/lib/stake-weight.js +12 -0
- package/dist/esm/solana/types.d.ts +6 -3
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Streamflow Staking
|
|
2
2
|
|
|
3
|
-
## JS SDK to interact with Streamflow Staking.
|
|
3
|
+
## JS SDK to interact with Streamflow Staking protocol.
|
|
4
4
|
|
|
5
5
|
This package allows you to
|
|
6
6
|
- `create staking pools and rewards pools`;
|
|
@@ -11,12 +11,12 @@ This package allows you to
|
|
|
11
11
|
|
|
12
12
|
with the Streamflow Staking protocol.
|
|
13
13
|
|
|
14
|
-
This protocol is the complex of several programs
|
|
14
|
+
This protocol is the complex of several programs that ensure flexibility and accountability for stakers and respective incentives for them.
|
|
15
15
|
|
|
16
|
-
aforementioned programs are:
|
|
16
|
+
aforementioned programs are:
|
|
17
17
|
- Stake Pools Program
|
|
18
18
|
- Reward Pools Program
|
|
19
|
-
- Fee Management Program (for streamflow usage, non-required and
|
|
19
|
+
- Fee Management Program (for streamflow usage, non-required and omitted from further docs)
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
## API Reference
|
|
@@ -106,7 +106,7 @@ const maxDuration = new BN(86400);
|
|
|
106
106
|
const permissionless = false;
|
|
107
107
|
/*
|
|
108
108
|
[0;256) derive stake pool PDA account address.
|
|
109
|
-
If stake pool with the same mint already exists, it is required to pick a vacant nonce
|
|
109
|
+
If stake pool with the same mint and creator/authority already exists, it is required to pick a vacant nonce
|
|
110
110
|
*/
|
|
111
111
|
const nonce = 0;
|
|
112
112
|
|
|
@@ -123,6 +123,8 @@ const { metadataId: stakePoolPda } = await client.createStakePool({
|
|
|
123
123
|
|
|
124
124
|
#### Create a rewardPool pool
|
|
125
125
|
```typescript
|
|
126
|
+
import { calculateRewardAmountFromRate } from "@streamflow/staking";
|
|
127
|
+
|
|
126
128
|
/*
|
|
127
129
|
[0;256) derive reward pool PDA account address.
|
|
128
130
|
If reward pool with the same mint already exists, it is required to pick a vacant nonce
|
|
@@ -132,6 +134,14 @@ const nonce = 0;
|
|
|
132
134
|
Amount of rewarding tokens stakers get in return for staking exactly 1 token to the staking pool
|
|
133
135
|
*/
|
|
134
136
|
const rewardAmount = new BN(100);
|
|
137
|
+
/*
|
|
138
|
+
Alternatively you may want to calculate the correct reward amount from desired reward rate taking into account stake pool and reward pools tokes decimals
|
|
139
|
+
*/
|
|
140
|
+
const rewardRate = 0.0025;
|
|
141
|
+
const stakeTokenDecimals = 9;
|
|
142
|
+
const rewardTokenDecimals = 6;
|
|
143
|
+
// For every effectively Staked 1 WHOLE token 0.0025 of Reward Token will be distributed
|
|
144
|
+
const rewardAmount = calculateRewardAmountFromRate(rewardRate, stakeTokenDecimals, rewardTokenDecimals);
|
|
135
145
|
/*
|
|
136
146
|
1 day - Unix time in seconds. Period for rewarding stakers. Period starts counting from the moment of staking
|
|
137
147
|
*/
|
|
@@ -154,6 +164,42 @@ client.createRewardPool({
|
|
|
154
164
|
```
|
|
155
165
|
|
|
156
166
|
|
|
167
|
+
#### Reward Amount configuration (in-depth)
|
|
168
|
+
|
|
169
|
+
`rewardAmount` represents a 10^9 fraction of a raw token distributed for every **effective staked raw token** - it's important to account for both reward and stake token decimals when creating staking pool because of that.
|
|
170
|
+
|
|
171
|
+
Example with only raw tokens: if `rewardAmount` is configured to be `1_000` and user staked `1_000_000_000` Raw Tokens with a weight of `2` (in the actual protocol this number will be represented as `2_000_000_000`), it means that the effective number of raw tokens staked is `2_000_000_000` and on every reward distribution user will get `2_000_000_000 * 1_000 / 10^9 = 200` Raw Tokens;
|
|
172
|
+
|
|
173
|
+
Examples with decimals:
|
|
174
|
+
|
|
175
|
+
RT - Reward Token
|
|
176
|
+
ST - Stake Pool Token
|
|
177
|
+
P - fixed `rewardAmount` precision of 9
|
|
178
|
+
|
|
179
|
+
User wants to set reward amount of `0.003` for every effective staked whole token, depending on number of decimals RT and ST have configuration may look different:
|
|
180
|
+
|
|
181
|
+
1. RT with 6 decimals, ST with 6 decimals.
|
|
182
|
+
- `0.003` of RT is `3_000` raw tokens;
|
|
183
|
+
- ST has 6 decimals while P is 9, therefore `9 - 6 = 3`;
|
|
184
|
+
- We need to add 3 decimals to the `rewardAmount` for proper distribution making it `3_000_000`;
|
|
185
|
+
2. RT with 12 decimals, ST with 12 decimals.
|
|
186
|
+
- `0.003` of RT is `3_000_000_000` raw tokens;
|
|
187
|
+
- ST has 12 decimals while P is 9, therefore `9 - 12 = -3`;
|
|
188
|
+
- We need to remove decimals from the raw token to be distributed making `rewardAmount` = `3_000_000`;
|
|
189
|
+
3. RT with 5 decimals, ST with 7 decimals.
|
|
190
|
+
- `0.003` of RT is `300` raw tokens;
|
|
191
|
+
- ST has 7 decimals while P is 9, therefore `9 - 7 = 2`;
|
|
192
|
+
- We need to add 2 decimals making `rewardAmount` = `30_000`;
|
|
193
|
+
4. RT with 9 decimals, ST with 3 decimals.
|
|
194
|
+
- `0.003` of RT is `3_000_000` raw tokens;
|
|
195
|
+
- the difference between RT and ST decimals is `9 - 3 = 6`;
|
|
196
|
+
- ST has 3 decimals while P is 9, therefore `9 - 3 = 6`;
|
|
197
|
+
- We need to add 6 decimals making `rewardAmount` = `3_000_000_000_000`;
|
|
198
|
+
|
|
199
|
+
We recommend to use the `calculateRewardAmountFromRate` function exposed by the sdk for the correct reward amount configuration.
|
|
200
|
+
|
|
201
|
+
**Also, some configurations where there is big difference between Stake Pool and Reward Pool token decimals may be unsupported, in this case the function will return 0, so be aware.**
|
|
202
|
+
|
|
157
203
|
#### Deposit/Stake to a stake pool
|
|
158
204
|
```typescript
|
|
159
205
|
/*
|
|
@@ -213,4 +259,4 @@ Streamflow Staking protocol program IDs
|
|
|
213
259
|
|
|
214
260
|
### IDLs
|
|
215
261
|
For further details you can consult with IDLs of protocols available at:
|
|
216
|
-
`@streamflow/staking/dist/esm/solana/descriptor`
|
|
262
|
+
`@streamflow/staking/dist/esm/solana/descriptor`
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const common_1 = require("@streamflow/common");
|
|
7
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
8
|
+
// eslint-disable-next-line no-restricted-imports
|
|
9
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
10
|
+
const vitest_1 = require("vitest");
|
|
11
|
+
const rewards_js_1 = require("../../solana/lib/rewards.js");
|
|
12
|
+
const constants_js_1 = require("../../solana/constants.js");
|
|
13
|
+
const populateRewardEntry = (effectiveStakedAmount, rewardAmount, rewardPeriod, periods) => {
|
|
14
|
+
const rewardEntry = new rewards_js_1.RewardEntryAccumulator(new bn_js_1.default(0), new bn_js_1.default(0), new bn_js_1.default(0), web3_js_1.PublicKey.default, web3_js_1.PublicKey.default, new bn_js_1.default(0), new bn_js_1.default(0), new bn_js_1.default(0), []);
|
|
15
|
+
if (effectiveStakedAmount && rewardAmount && rewardPeriod) {
|
|
16
|
+
rewardEntry.accountedAmount = rewardEntry.getAccountableAmount(new bn_js_1.default(0), rewardPeriod.muln(periods || 1), effectiveStakedAmount, rewardAmount, rewardPeriod);
|
|
17
|
+
}
|
|
18
|
+
return rewardEntry;
|
|
19
|
+
};
|
|
20
|
+
(0, vitest_1.describe)("RewardEntryAccumulator", () => {
|
|
21
|
+
(0, vitest_1.describe)("getClaimableAmount", () => {
|
|
22
|
+
const testCases = [
|
|
23
|
+
[9, 9, 1, 0.0025, new bn_js_1.default(2500000)],
|
|
24
|
+
[6, 9, 1, 0.0025, new bn_js_1.default(2500000000)],
|
|
25
|
+
[9, 6, 1, 0.0025, new bn_js_1.default(2500)],
|
|
26
|
+
[1, 8, 1, 0.0025, new bn_js_1.default(25000000000000)],
|
|
27
|
+
];
|
|
28
|
+
testCases.forEach(([stakeTokenDecimals, rewardTokenDecimals, periods, rewardRate, expectedRewardAmount]) => {
|
|
29
|
+
(0, vitest_1.test)(`test decimals - ${stakeTokenDecimals}/${rewardTokenDecimals}/${periods}/${rewardRate}`, () => {
|
|
30
|
+
const stakedAmount = (0, common_1.getBN)(1, stakeTokenDecimals);
|
|
31
|
+
const effectiveStakedAmount = stakedAmount.mul(constants_js_1.SCALE_PRECISION_FACTOR_BN);
|
|
32
|
+
const rewardPeriod = new bn_js_1.default(1);
|
|
33
|
+
const rewardAmount = (0, rewards_js_1.calculateRewardAmountFromRate)(rewardRate, stakeTokenDecimals, rewardTokenDecimals);
|
|
34
|
+
const rewardEntry = populateRewardEntry(effectiveStakedAmount, rewardAmount, rewardPeriod, periods);
|
|
35
|
+
const claimableAmount = rewardEntry.getClaimableAmount();
|
|
36
|
+
(0, vitest_1.expect)(rewardAmount.toString()).toEqual(expectedRewardAmount.toString());
|
|
37
|
+
(0, vitest_1.expect)(claimableAmount.toString()).toEqual((0, common_1.getBN)(rewardRate, rewardTokenDecimals).muln(periods).toString());
|
|
38
|
+
(0, vitest_1.expect)((0, rewards_js_1.calculateRewardRateFromAmount)(rewardAmount, stakeTokenDecimals, rewardTokenDecimals)).toEqual(rewardRate);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.test)(`test decimals - negative difference`, () => {
|
|
42
|
+
let rewardAmount = (0, rewards_js_1.calculateRewardAmountFromRate)(0.0025, 18, 1);
|
|
43
|
+
(0, vitest_1.expect)(rewardAmount.toString()).toEqual(new bn_js_1.default(0).toString());
|
|
44
|
+
rewardAmount = (0, rewards_js_1.calculateRewardAmountFromRate)(0.0025, 12, 4);
|
|
45
|
+
(0, vitest_1.expect)(rewardAmount.toString()).toEqual(new bn_js_1.default(0).toString());
|
|
46
|
+
});
|
|
47
|
+
(0, vitest_1.test)(`test decimals - precision loss`, () => {
|
|
48
|
+
const stakeTokenDecimals = 12;
|
|
49
|
+
const rewardTokenDecimals = 6;
|
|
50
|
+
const stakedAmount = (0, common_1.getBN)(1, stakeTokenDecimals);
|
|
51
|
+
const effectiveStakedAmount = stakedAmount.mul(constants_js_1.SCALE_PRECISION_FACTOR_BN);
|
|
52
|
+
const rewardPeriod = new bn_js_1.default(1);
|
|
53
|
+
const rewardAmount = (0, rewards_js_1.calculateRewardAmountFromRate)(0.0025, stakeTokenDecimals, rewardTokenDecimals);
|
|
54
|
+
const rewardEntry = populateRewardEntry(effectiveStakedAmount, rewardAmount, rewardPeriod);
|
|
55
|
+
const claimableAmount = rewardEntry.getClaimableAmount();
|
|
56
|
+
(0, vitest_1.expect)(rewardAmount.toString()).toEqual(new bn_js_1.default(2).toString());
|
|
57
|
+
(0, vitest_1.expect)(claimableAmount.toString()).toEqual((0, common_1.getBN)(0.002, rewardTokenDecimals).toString());
|
|
58
|
+
(0, vitest_1.expect)((0, rewards_js_1.calculateRewardRateFromAmount)(rewardAmount, stakeTokenDecimals, rewardTokenDecimals)).toEqual(0.002);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
package/dist/cjs/index.js
CHANGED
|
@@ -25,15 +25,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
__setModuleDefault(result, mod);
|
|
26
26
|
return result;
|
|
27
27
|
};
|
|
28
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
29
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
30
|
-
};
|
|
31
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
29
|
exports.constants = exports.SolanaStakingClient = void 0;
|
|
33
30
|
var client_js_1 = require("./solana/client.js");
|
|
34
|
-
Object.defineProperty(exports, "SolanaStakingClient", { enumerable: true, get: function () { return
|
|
35
|
-
__exportStar(require("./solana/utils.js"), exports);
|
|
31
|
+
Object.defineProperty(exports, "SolanaStakingClient", { enumerable: true, get: function () { return client_js_1.SolanaStakingClient; } });
|
|
36
32
|
__exportStar(require("./solana/types.js"), exports);
|
|
37
33
|
__exportStar(require("./solana/lib/derive-accounts.js"), exports);
|
|
38
34
|
__exportStar(require("./solana/lib/rewards.js"), exports);
|
|
35
|
+
__exportStar(require("./solana/lib/fee-amounts.js"), exports);
|
|
36
|
+
__exportStar(require("./solana/lib/stake-weight.js"), exports);
|
|
39
37
|
exports.constants = __importStar(require("./solana/constants.js"));
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SolanaStakingClient = void 0;
|
|
6
7
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
7
8
|
const spl_token_1 = require("@solana/spl-token");
|
|
8
9
|
const web3_js_1 = require("@solana/web3.js");
|
|
@@ -44,7 +45,7 @@ class SolanaStakingClient {
|
|
|
44
45
|
}
|
|
45
46
|
getCurrentProgramId(programKey) {
|
|
46
47
|
const program = this.programs[programKey];
|
|
47
|
-
invariant(program, `Program ${programKey} is not found`);
|
|
48
|
+
(0, common_1.invariant)(program, `Program ${programKey} is not found`);
|
|
48
49
|
return program.programId;
|
|
49
50
|
}
|
|
50
51
|
getCommitment() {
|
|
@@ -56,7 +57,7 @@ class SolanaStakingClient {
|
|
|
56
57
|
}
|
|
57
58
|
async searchStakePools(criteria = {}) {
|
|
58
59
|
const { stakePoolProgram } = this.programs;
|
|
59
|
-
return stakePoolProgram.account.stakePool.all(getFilters(criteria, constants_js_1.STAKE_POOL_BYTE_OFFSETS));
|
|
60
|
+
return stakePoolProgram.account.stakePool.all((0, solana_1.getFilters)(criteria, constants_js_1.STAKE_POOL_BYTE_OFFSETS));
|
|
60
61
|
}
|
|
61
62
|
async getStakeEntry(id) {
|
|
62
63
|
const { stakePoolProgram } = this.programs;
|
|
@@ -64,15 +65,27 @@ class SolanaStakingClient {
|
|
|
64
65
|
}
|
|
65
66
|
async searchStakeEntries(criteria = {}) {
|
|
66
67
|
const { stakePoolProgram } = this.programs;
|
|
67
|
-
return stakePoolProgram.account.stakeEntry.all(getFilters(criteria, constants_js_1.STAKE_ENTRY_BYTE_OFFSETS));
|
|
68
|
+
return stakePoolProgram.account.stakeEntry.all((0, solana_1.getFilters)(criteria, constants_js_1.STAKE_ENTRY_BYTE_OFFSETS));
|
|
68
69
|
}
|
|
69
70
|
async searchRewardPools(criteria = {}) {
|
|
70
71
|
const { rewardPoolProgram } = this.programs;
|
|
71
|
-
return rewardPoolProgram.account.rewardPool.all(getFilters(criteria, constants_js_1.REWARD_POOL_BYTE_OFFSETS));
|
|
72
|
+
return rewardPoolProgram.account.rewardPool.all((0, solana_1.getFilters)(criteria, constants_js_1.REWARD_POOL_BYTE_OFFSETS));
|
|
72
73
|
}
|
|
73
74
|
async searchRewardEntries(criteria) {
|
|
74
75
|
const { rewardPoolProgram } = this.programs;
|
|
75
|
-
return rewardPoolProgram.account.rewardEntry.all(getFilters(criteria, constants_js_1.REWARD_ENTRY_BYTE_OFFSETS));
|
|
76
|
+
return rewardPoolProgram.account.rewardEntry.all((0, solana_1.getFilters)(criteria, constants_js_1.REWARD_ENTRY_BYTE_OFFSETS));
|
|
77
|
+
}
|
|
78
|
+
async getFee(target) {
|
|
79
|
+
const perTargetFee = await this.getFeeValueIfExists(target);
|
|
80
|
+
if (perTargetFee) {
|
|
81
|
+
return perTargetFee;
|
|
82
|
+
}
|
|
83
|
+
return this.getDefaultFeeValue();
|
|
84
|
+
}
|
|
85
|
+
getDefaultFeeValue() {
|
|
86
|
+
const { feeManagerProgram } = this.programs;
|
|
87
|
+
const feeValueKey = (0, derive_accounts_js_1.deriveConfigPDA)(feeManagerProgram.programId);
|
|
88
|
+
return feeManagerProgram.account.config.fetch(feeValueKey);
|
|
76
89
|
}
|
|
77
90
|
getFeeValueIfExists(target) {
|
|
78
91
|
const { feeManagerProgram } = this.programs;
|
|
@@ -91,7 +104,7 @@ class SolanaStakingClient {
|
|
|
91
104
|
async prepareCreateStakePoolInstructions({ maxWeight, maxDuration, minDuration, mint, permissionless = false, nonce, tokenProgramId = spl_token_1.TOKEN_PROGRAM_ID, }, extParams) {
|
|
92
105
|
const { stakePoolProgram } = this.programs;
|
|
93
106
|
const creator = extParams.invoker.publicKey;
|
|
94
|
-
invariant(creator, "Undefined invoker publicKey");
|
|
107
|
+
(0, common_1.invariant)(creator, "Undefined invoker publicKey");
|
|
95
108
|
const createInstruction = await stakePoolProgram.methods
|
|
96
109
|
.createPool(nonce, maxWeight, minDuration, maxDuration, permissionless)
|
|
97
110
|
.accounts({
|
|
@@ -100,7 +113,7 @@ class SolanaStakingClient {
|
|
|
100
113
|
tokenProgram: tokenProgramId,
|
|
101
114
|
})
|
|
102
115
|
.instruction();
|
|
103
|
-
const stakePoolPDA = (0, derive_accounts_js_1.deriveStakePoolPDA)(stakePoolProgram.programId, pk(mint), creator, nonce);
|
|
116
|
+
const stakePoolPDA = (0, derive_accounts_js_1.deriveStakePoolPDA)(stakePoolProgram.programId, (0, solana_1.pk)(mint), creator, nonce);
|
|
104
117
|
return { ixs: [createInstruction], publicKey: stakePoolPDA };
|
|
105
118
|
}
|
|
106
119
|
async stake(data, extParams) {
|
|
@@ -114,10 +127,10 @@ class SolanaStakingClient {
|
|
|
114
127
|
async prepareStakeInstructions({ nonce, amount, duration, stakePool, stakePoolMint, tokenProgramId = spl_token_1.TOKEN_PROGRAM_ID }, extParams) {
|
|
115
128
|
const { stakePoolProgram } = this.programs;
|
|
116
129
|
const staker = extParams.invoker.publicKey;
|
|
117
|
-
invariant(staker, "Undefined invoker publicKey");
|
|
118
|
-
const mint = (0, derive_accounts_js_1.deriveStakeMintPDA)(stakePoolProgram.programId, pk(stakePool));
|
|
119
|
-
const stakeMintAccountKey = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, staker, false, pk(tokenProgramId));
|
|
120
|
-
const poolMintAccountKey = (0, spl_token_1.getAssociatedTokenAddressSync)(pk(stakePoolMint), staker, false, pk(tokenProgramId));
|
|
130
|
+
(0, common_1.invariant)(staker, "Undefined invoker publicKey");
|
|
131
|
+
const mint = (0, derive_accounts_js_1.deriveStakeMintPDA)(stakePoolProgram.programId, (0, solana_1.pk)(stakePool));
|
|
132
|
+
const stakeMintAccountKey = (0, spl_token_1.getAssociatedTokenAddressSync)(mint, staker, false, (0, solana_1.pk)(tokenProgramId));
|
|
133
|
+
const poolMintAccountKey = (0, spl_token_1.getAssociatedTokenAddressSync)((0, solana_1.pk)(stakePoolMint), staker, false, (0, solana_1.pk)(tokenProgramId));
|
|
121
134
|
const instruction = await stakePoolProgram.methods
|
|
122
135
|
.stake(nonce, amount, duration)
|
|
123
136
|
.accounts({
|
|
@@ -142,11 +155,11 @@ class SolanaStakingClient {
|
|
|
142
155
|
async prepareUnstakeInstructions({ stakePool, stakePoolMint, nonce, tokenProgramId = spl_token_1.TOKEN_PROGRAM_ID }, extParams) {
|
|
143
156
|
const { stakePoolProgram } = this.programs;
|
|
144
157
|
const staker = extParams.invoker.publicKey;
|
|
145
|
-
invariant(staker, "Undefined invoker publicKey");
|
|
146
|
-
const stakeMintKey = (0, derive_accounts_js_1.deriveStakeMintPDA)(stakePoolProgram.programId, pk(stakePool));
|
|
147
|
-
const stakeEntryKey = (0, derive_accounts_js_1.deriveStakeEntryPDA)(stakePoolProgram.programId, pk(stakePool), staker, nonce);
|
|
148
|
-
const poolMintAccountKey = (0, spl_token_1.getAssociatedTokenAddressSync)(pk(stakePoolMint), staker, false, pk(tokenProgramId));
|
|
149
|
-
const stakeMintAccountKey = (0, spl_token_1.getAssociatedTokenAddressSync)(stakeMintKey, staker, false, pk(tokenProgramId));
|
|
158
|
+
(0, common_1.invariant)(staker, "Undefined invoker publicKey");
|
|
159
|
+
const stakeMintKey = (0, derive_accounts_js_1.deriveStakeMintPDA)(stakePoolProgram.programId, (0, solana_1.pk)(stakePool));
|
|
160
|
+
const stakeEntryKey = (0, derive_accounts_js_1.deriveStakeEntryPDA)(stakePoolProgram.programId, (0, solana_1.pk)(stakePool), staker, nonce);
|
|
161
|
+
const poolMintAccountKey = (0, spl_token_1.getAssociatedTokenAddressSync)((0, solana_1.pk)(stakePoolMint), staker, false, (0, solana_1.pk)(tokenProgramId));
|
|
162
|
+
const stakeMintAccountKey = (0, spl_token_1.getAssociatedTokenAddressSync)(stakeMintKey, staker, false, (0, solana_1.pk)(tokenProgramId));
|
|
150
163
|
const instruction = await stakePoolProgram.methods
|
|
151
164
|
.unstake()
|
|
152
165
|
.accounts({
|
|
@@ -171,7 +184,7 @@ class SolanaStakingClient {
|
|
|
171
184
|
async prepareCreateRewardPoolInstructions({ nonce, rewardAmount, rewardPeriod, rewardMint, permissionless = false, stakePool, tokenProgramId = spl_token_1.TOKEN_PROGRAM_ID, }, extParams) {
|
|
172
185
|
const { rewardPoolProgram } = this.programs;
|
|
173
186
|
const creator = extParams.invoker.publicKey;
|
|
174
|
-
invariant(creator, "Undefined invoker publicKey");
|
|
187
|
+
(0, common_1.invariant)(creator, "Undefined invoker publicKey");
|
|
175
188
|
const instruction = await rewardPoolProgram.methods
|
|
176
189
|
.createPool(nonce, rewardAmount, rewardPeriod, permissionless)
|
|
177
190
|
.accounts({
|
|
@@ -181,7 +194,7 @@ class SolanaStakingClient {
|
|
|
181
194
|
tokenProgram: tokenProgramId,
|
|
182
195
|
})
|
|
183
196
|
.instruction();
|
|
184
|
-
const rewardPoolKey = (0, derive_accounts_js_1.deriveRewardPoolPDA)(rewardPoolProgram.programId, pk(stakePool), pk(rewardMint), nonce);
|
|
197
|
+
const rewardPoolKey = (0, derive_accounts_js_1.deriveRewardPoolPDA)(rewardPoolProgram.programId, (0, solana_1.pk)(stakePool), (0, solana_1.pk)(rewardMint), nonce);
|
|
185
198
|
return { publicKey: rewardPoolKey, ixs: [instruction] };
|
|
186
199
|
}
|
|
187
200
|
async claimRewards(data, extParams) {
|
|
@@ -195,15 +208,15 @@ class SolanaStakingClient {
|
|
|
195
208
|
async prepareClaimRewardsInstructions({ rewardPoolNonce, depositNonce, stakePool, tokenProgramId = spl_token_1.TOKEN_PROGRAM_ID, rewardMint }, extParams) {
|
|
196
209
|
const { stakePoolProgram, rewardPoolProgram } = this.programs;
|
|
197
210
|
const staker = extParams.invoker.publicKey;
|
|
198
|
-
invariant(staker, "Undefined invoker publicKey");
|
|
211
|
+
(0, common_1.invariant)(staker, "Undefined invoker publicKey");
|
|
199
212
|
const instruction = await rewardPoolProgram.methods
|
|
200
213
|
.claimRewards()
|
|
201
214
|
.accounts({
|
|
202
|
-
stakeEntry: (0, derive_accounts_js_1.deriveStakeEntryPDA)(stakePoolProgram.programId, pk(stakePool), staker, depositNonce),
|
|
203
|
-
rewardPool: (0, derive_accounts_js_1.deriveRewardPoolPDA)(rewardPoolProgram.programId, pk(stakePool), pk(rewardMint), rewardPoolNonce),
|
|
215
|
+
stakeEntry: (0, derive_accounts_js_1.deriveStakeEntryPDA)(stakePoolProgram.programId, (0, solana_1.pk)(stakePool), staker, depositNonce),
|
|
216
|
+
rewardPool: (0, derive_accounts_js_1.deriveRewardPoolPDA)(rewardPoolProgram.programId, (0, solana_1.pk)(stakePool), (0, solana_1.pk)(rewardMint), rewardPoolNonce),
|
|
204
217
|
claimant: staker,
|
|
205
218
|
tokenProgram: tokenProgramId,
|
|
206
|
-
to: (0, spl_token_1.getAssociatedTokenAddressSync)(pk(rewardMint), staker, false, pk(tokenProgramId)),
|
|
219
|
+
to: (0, spl_token_1.getAssociatedTokenAddressSync)((0, solana_1.pk)(rewardMint), staker, false, (0, solana_1.pk)(tokenProgramId)),
|
|
207
220
|
})
|
|
208
221
|
.instruction();
|
|
209
222
|
return { ixs: [instruction] };
|
|
@@ -219,14 +232,14 @@ class SolanaStakingClient {
|
|
|
219
232
|
async prepareFundPoolInstructions({ amount, tokenProgramId = spl_token_1.TOKEN_PROGRAM_ID, rewardMint, stakePool, feeValue, nonce }, extParams) {
|
|
220
233
|
const { rewardPoolProgram } = this.programs;
|
|
221
234
|
const staker = extParams.invoker.publicKey;
|
|
222
|
-
invariant(staker, "Undefined invoker publicKey");
|
|
235
|
+
(0, common_1.invariant)(staker, "Undefined invoker publicKey");
|
|
223
236
|
const existingFee = await this.getFeeValueIfExists(staker);
|
|
224
|
-
const rewardMintPk = pk(rewardMint);
|
|
225
|
-
const tokenProgramPk = pk(tokenProgramId);
|
|
237
|
+
const rewardMintPk = (0, solana_1.pk)(rewardMint);
|
|
238
|
+
const tokenProgramPk = (0, solana_1.pk)(tokenProgramId);
|
|
226
239
|
const treasuryATA = !existingFee || existingFee.streamflowFee.gtn(0)
|
|
227
240
|
? await (0, solana_1.checkOrCreateAtaBatch)(this.connection, [constants_js_1.STREAMFLOW_TREASURY_PUBLIC_KEY], rewardMintPk, extParams.invoker, tokenProgramPk)
|
|
228
241
|
: null;
|
|
229
|
-
const rewardPoolPda = (0, derive_accounts_js_1.deriveRewardPoolPDA)(rewardPoolProgram.programId, pk(stakePool), rewardMintPk, nonce);
|
|
242
|
+
const rewardPoolPda = (0, derive_accounts_js_1.deriveRewardPoolPDA)(rewardPoolProgram.programId, (0, solana_1.pk)(stakePool), rewardMintPk, nonce);
|
|
230
243
|
const instruction = await rewardPoolProgram.methods
|
|
231
244
|
.fundPool(amount)
|
|
232
245
|
.accountsPartial({
|
|
@@ -252,18 +265,51 @@ class SolanaStakingClient {
|
|
|
252
265
|
async prepareCreateRewardEntryInstructions({ stakePoolMint, stakePool, rewardPoolNonce, depositNonce }, extParams) {
|
|
253
266
|
const { stakePoolProgram, rewardPoolProgram } = this.programs;
|
|
254
267
|
const staker = extParams.invoker.publicKey;
|
|
255
|
-
invariant(staker, "Undefined invoker publicKey");
|
|
268
|
+
(0, common_1.invariant)(staker, "Undefined invoker publicKey");
|
|
256
269
|
const instruction = await rewardPoolProgram.methods
|
|
257
270
|
.createEntry()
|
|
258
271
|
.accounts({
|
|
259
272
|
payer: staker,
|
|
260
273
|
authority: staker,
|
|
261
|
-
stakeEntry: (0, derive_accounts_js_1.deriveStakeEntryPDA)(stakePoolProgram.programId, pk(stakePool), staker, depositNonce),
|
|
262
|
-
rewardPool: (0, derive_accounts_js_1.deriveRewardPoolPDA)(rewardPoolProgram.programId, pk(stakePool), pk(stakePoolMint), rewardPoolNonce),
|
|
274
|
+
stakeEntry: (0, derive_accounts_js_1.deriveStakeEntryPDA)(stakePoolProgram.programId, (0, solana_1.pk)(stakePool), staker, depositNonce),
|
|
275
|
+
rewardPool: (0, derive_accounts_js_1.deriveRewardPoolPDA)(rewardPoolProgram.programId, (0, solana_1.pk)(stakePool), (0, solana_1.pk)(stakePoolMint), rewardPoolNonce),
|
|
276
|
+
})
|
|
277
|
+
.instruction();
|
|
278
|
+
return { ixs: [instruction] };
|
|
279
|
+
}
|
|
280
|
+
async updateRewardPool(data, extParams) {
|
|
281
|
+
const { ixs } = await this.prepareUpdateRewardPoolInstructions(data, extParams);
|
|
282
|
+
const { signature } = await this.execute(ixs, extParams);
|
|
283
|
+
return {
|
|
284
|
+
ixs,
|
|
285
|
+
txId: signature,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
async prepareUpdateRewardPoolInstructions({ rewardPool, rewardAmount, rewardPeriod }, extParams) {
|
|
289
|
+
const { rewardPoolProgram } = this.programs;
|
|
290
|
+
const invoker = extParams.invoker.publicKey;
|
|
291
|
+
(0, common_1.invariant)(invoker, "Undefined invoker publicKey");
|
|
292
|
+
const instruction = await rewardPoolProgram.methods
|
|
293
|
+
.updatePool(rewardAmount, rewardPeriod)
|
|
294
|
+
.accountsPartial({
|
|
295
|
+
authority: invoker,
|
|
296
|
+
rewardPool,
|
|
263
297
|
})
|
|
264
298
|
.instruction();
|
|
265
299
|
return { ixs: [instruction] };
|
|
266
300
|
}
|
|
301
|
+
decode(programKey, accountName, accInfo) {
|
|
302
|
+
const decodingProgram = this.programs[programKey];
|
|
303
|
+
(0, common_1.invariant)(decodingProgram, `Decoding program with key ${programKey} is not available`);
|
|
304
|
+
return decodingProgram.coder.accounts.decode(accountName.toString(), accInfo);
|
|
305
|
+
}
|
|
306
|
+
getDiscriminator(programKey, accountName) {
|
|
307
|
+
const decodingProgram = this.programs[programKey];
|
|
308
|
+
(0, common_1.invariant)(decodingProgram, `Decoding program with key ${programKey} is not available`);
|
|
309
|
+
const accountEntity = decodingProgram.idl.accounts.find((acc) => acc.name === accountName);
|
|
310
|
+
(0, common_1.invariant)(accountEntity, `Decoding program with key ${programKey} doesn't specify account with name ${accountName.toString()}`);
|
|
311
|
+
return accountEntity.discriminator;
|
|
312
|
+
}
|
|
267
313
|
async execute(ixs, extParams) {
|
|
268
314
|
const { tx, hash, context } = await (0, solana_1.prepareTransaction)(this.connection, ixs, extParams.invoker.publicKey);
|
|
269
315
|
try {
|
|
@@ -285,31 +331,4 @@ class SolanaStakingClient {
|
|
|
285
331
|
}
|
|
286
332
|
}
|
|
287
333
|
}
|
|
288
|
-
exports.
|
|
289
|
-
function pk(address) {
|
|
290
|
-
return typeof address === "string" ? new web3_js_1.PublicKey(address) : address;
|
|
291
|
-
}
|
|
292
|
-
const prefix = "Assertion failed";
|
|
293
|
-
function invariant(condition, message) {
|
|
294
|
-
if (condition) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
const provided = typeof message === "function" ? message() : message;
|
|
298
|
-
const value = provided ? `${prefix}: ${provided}` : prefix;
|
|
299
|
-
throw new Error(value);
|
|
300
|
-
}
|
|
301
|
-
function getFilters(criteria, byteOffsets) {
|
|
302
|
-
return Object.entries(criteria).reduce((acc, [key, value]) => {
|
|
303
|
-
const criteriaKey = key;
|
|
304
|
-
const effectiveByteOffset = byteOffsets[criteriaKey];
|
|
305
|
-
if (criteria[criteriaKey] && effectiveByteOffset) {
|
|
306
|
-
acc.push({
|
|
307
|
-
memcmp: {
|
|
308
|
-
offset: effectiveByteOffset,
|
|
309
|
-
bytes: value.toString(),
|
|
310
|
-
},
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
return acc;
|
|
314
|
-
}, []);
|
|
315
|
-
}
|
|
334
|
+
exports.SolanaStakingClient = SolanaStakingClient;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.REWARD_POOL_PROGRAM_ID = exports.STAKE_POOL_PROGRAM_ID = exports.REWARD_ENTRY_BYTE_OFFSETS = exports.REWARD_ENTRY_STAKE_ENTRY_OFFSET = exports.REWARD_ENTRY_REWARD_POOL_OFFSET = exports.REWARD_POOL_BYTE_OFFSETS = exports.REWARD_POOL_MINT_OFFSET = exports.REWARD_POOL_STAKE_POOL_OFFSET = exports.STAKE_POOL_BYTE_OFFSETS = exports.STAKE_POOL_CREATOR_OFFSET = exports.STAKE_POOL_MINT_OFFSET = exports.STAKE_ENTRY_BYTE_OFFSETS = exports.STAKE_ENTRY_OWNER_OFFSET = exports.STAKE_ENTRY_STAKE_POOL_OFFSET = exports.ANCHOR_DISCRIMINATOR_OFFSET = exports.STREAMFLOW_TREASURY_PUBLIC_KEY = exports.FEE_VALUE_PREFIX = exports.CONFIG_PREFIX = exports.REWARD_ENTRY_PREFIX = exports.REWARD_VAULT_PREFIX = exports.REWARD_POOL_PREFIX = exports.STAKE_VAULT_PREFIX = exports.STAKE_MINT_PREFIX = exports.STAKE_POOL_PREFIX = exports.STAKE_ENTRY_PREFIX = exports.STAKE_ENTRY_DISCRIMINATOR = exports.U64_MAX = exports.SCALE_PRECISION_FACTOR_BN = exports.SCALE_PRECISION_FACTOR = exports.DEFAULT_FEE_BN = exports.DEFAULT_FEE = exports.FEE_PRECISION_FACTOR_BN = exports.FEE_PRECISION_FACTOR = void 0;
|
|
3
|
+
exports.FEE_PROGRAM_ID = exports.REWARD_POOL_PROGRAM_ID = exports.STAKE_POOL_PROGRAM_ID = exports.REWARD_ENTRY_BYTE_OFFSETS = exports.REWARD_ENTRY_STAKE_ENTRY_OFFSET = exports.REWARD_ENTRY_REWARD_POOL_OFFSET = exports.REWARD_POOL_BYTE_OFFSETS = exports.REWARD_POOL_MINT_OFFSET = exports.REWARD_POOL_STAKE_POOL_OFFSET = exports.STAKE_POOL_BYTE_OFFSETS = exports.STAKE_POOL_CREATOR_OFFSET = exports.STAKE_POOL_MINT_OFFSET = exports.STAKE_ENTRY_BYTE_OFFSETS = exports.STAKE_ENTRY_OWNER_OFFSET = exports.STAKE_ENTRY_STAKE_POOL_OFFSET = exports.ANCHOR_DISCRIMINATOR_OFFSET = exports.STREAMFLOW_TREASURY_PUBLIC_KEY = exports.FEE_VALUE_PREFIX = exports.CONFIG_PREFIX = exports.REWARD_ENTRY_PREFIX = exports.REWARD_VAULT_PREFIX = exports.REWARD_POOL_PREFIX = exports.STAKE_VAULT_PREFIX = exports.STAKE_MINT_PREFIX = exports.STAKE_POOL_PREFIX = exports.STAKE_ENTRY_PREFIX = exports.STAKE_ENTRY_DISCRIMINATOR = exports.U64_MAX = exports.REWARD_AMOUNT_PRECISION_FACTOR_BN = exports.REWARD_AMOUNT_PRECISION_FACTOR = exports.REWARD_AMOUNT_DECIMALS = exports.SCALE_PRECISION_FACTOR_BN = exports.SCALE_PRECISION_FACTOR = exports.DEFAULT_FEE_BN = exports.DEFAULT_FEE = exports.FEE_PRECISION_FACTOR_BN = exports.FEE_PRECISION_FACTOR = void 0;
|
|
4
4
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
5
5
|
const common_1 = require("@streamflow/common");
|
|
6
6
|
const web3_js_1 = require("@solana/web3.js");
|
|
7
7
|
exports.FEE_PRECISION_FACTOR = 10000;
|
|
8
8
|
exports.FEE_PRECISION_FACTOR_BN = new anchor_1.BN(exports.FEE_PRECISION_FACTOR);
|
|
9
|
-
exports.DEFAULT_FEE =
|
|
9
|
+
exports.DEFAULT_FEE = 19;
|
|
10
10
|
exports.DEFAULT_FEE_BN = new anchor_1.BN(exports.DEFAULT_FEE);
|
|
11
11
|
exports.SCALE_PRECISION_FACTOR = 1000000000;
|
|
12
12
|
exports.SCALE_PRECISION_FACTOR_BN = new anchor_1.BN(exports.SCALE_PRECISION_FACTOR);
|
|
13
|
+
exports.REWARD_AMOUNT_DECIMALS = 9;
|
|
14
|
+
exports.REWARD_AMOUNT_PRECISION_FACTOR = 1000000000;
|
|
15
|
+
exports.REWARD_AMOUNT_PRECISION_FACTOR_BN = new anchor_1.BN(exports.REWARD_AMOUNT_PRECISION_FACTOR);
|
|
13
16
|
exports.U64_MAX = 18446744073709551615n;
|
|
14
17
|
exports.STAKE_ENTRY_DISCRIMINATOR = [187, 127, 9, 35, 155, 68, 86, 40];
|
|
15
18
|
exports.STAKE_ENTRY_PREFIX = Buffer.from("stake-entry", "utf-8");
|
|
@@ -29,7 +32,7 @@ exports.STAKE_ENTRY_BYTE_OFFSETS = {
|
|
|
29
32
|
payer: exports.STAKE_ENTRY_OWNER_OFFSET,
|
|
30
33
|
stakePool: exports.STAKE_ENTRY_STAKE_POOL_OFFSET,
|
|
31
34
|
};
|
|
32
|
-
exports.STAKE_POOL_MINT_OFFSET = exports.ANCHOR_DISCRIMINATOR_OFFSET +
|
|
35
|
+
exports.STAKE_POOL_MINT_OFFSET = exports.ANCHOR_DISCRIMINATOR_OFFSET + 2;
|
|
33
36
|
exports.STAKE_POOL_CREATOR_OFFSET = exports.STAKE_POOL_MINT_OFFSET + 32;
|
|
34
37
|
exports.STAKE_POOL_BYTE_OFFSETS = {
|
|
35
38
|
mint: exports.STAKE_POOL_MINT_OFFSET,
|
|
@@ -59,3 +62,9 @@ exports.REWARD_POOL_PROGRAM_ID = {
|
|
|
59
62
|
[common_1.ICluster.Testnet]: "RWRDdfRbi3339VgKxTAXg4cjyniF7cbhNbMxZWiSKmj",
|
|
60
63
|
[common_1.ICluster.Local]: "RWRDdfRbi3339VgKxTAXg4cjyniF7cbhNbMxZWiSKmj",
|
|
61
64
|
};
|
|
65
|
+
exports.FEE_PROGRAM_ID = {
|
|
66
|
+
[common_1.ICluster.Mainnet]: "FEELzfBhsWXTNJX53zZcDVfRNoFYZQ6cZA3jLiGVL16V",
|
|
67
|
+
[common_1.ICluster.Devnet]: "FEELzfBhsWXTNJX53zZcDVfRNoFYZQ6cZA3jLiGVL16V",
|
|
68
|
+
[common_1.ICluster.Testnet]: "FEELzfBhsWXTNJX53zZcDVfRNoFYZQ6cZA3jLiGVL16V",
|
|
69
|
+
[common_1.ICluster.Local]: "FEELzfBhsWXTNJX53zZcDVfRNoFYZQ6cZA3jLiGVL16V",
|
|
70
|
+
};
|
|
@@ -338,8 +338,8 @@
|
|
|
338
338
|
"program": {
|
|
339
339
|
"kind": "const",
|
|
340
340
|
"value": [
|
|
341
|
-
140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142, 13, 131, 11, 90, 19, 153, 218,
|
|
342
|
-
|
|
341
|
+
140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142, 13, 131, 11, 90, 19, 153, 218, 255, 16,
|
|
342
|
+
132, 4, 142, 123, 216, 219, 233, 248, 89
|
|
343
343
|
]
|
|
344
344
|
}
|
|
345
345
|
}
|
|
@@ -778,9 +778,7 @@
|
|
|
778
778
|
},
|
|
779
779
|
{
|
|
780
780
|
"name": "effective_amount",
|
|
781
|
-
"docs": [
|
|
782
|
-
"Effective Amount staked, does not equal to deposited amount, accounts for Stake Weight"
|
|
783
|
-
],
|
|
781
|
+
"docs": ["Effective Amount staked, does not equal to deposited amount, accounts for Stake Weight"],
|
|
784
782
|
"type": "u128"
|
|
785
783
|
},
|
|
786
784
|
{
|