@symmetry-hq/sdk 1.0.5 → 1.0.7
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/dist/src/index.d.ts +1 -15
- package/dist/src/index.js +33 -83
- package/dist/src/instructions/management/claimFees.js +1 -1
- package/dist/src/instructions/management/edit.js +2 -2
- package/dist/src/layouts/basket.d.ts +1 -0
- package/dist/src/layouts/config.d.ts +1 -0
- package/dist/src/layouts/config.js +2 -1
- package/dist/src/layouts/intents/intent.d.ts +2 -2
- package/dist/src/states/basket.js +3 -2
- package/dist/src/states/intents/intent.js +2 -2
- package/dist/src/states/intents/rebalanceIntent.js +9 -1
- package/dist/src/states/oracles/oracle.js +6 -4
- package/dist/src/states/oracles/pythOracle.d.ts +2 -0
- package/dist/src/states/oracles/pythOracle.js +72 -0
- package/dist/test.js +15 -15
- package/package.json +1 -1
- package/src/index.ts +43 -103
- package/src/instructions/management/claimFees.ts +1 -1
- package/src/instructions/management/edit.ts +2 -2
- package/src/layouts/basket.ts +1 -0
- package/src/layouts/config.ts +3 -1
- package/src/layouts/intents/intent.ts +2 -2
- package/src/states/basket.ts +3 -2
- package/src/states/intents/intent.ts +2 -2
- package/src/states/intents/rebalanceIntent.ts +8 -2
- package/src/states/oracles/oracle.ts +6 -4
- package/src/states/oracles/pythOracle.ts +104 -2
- package/test.ts +15 -15
package/dist/src/index.d.ts
CHANGED
|
@@ -7,8 +7,7 @@ import { AuctionData, ClaimBountyData, DepositData, FormattedOraclePrice, Format
|
|
|
7
7
|
import { FormattedOracleType } from './layouts/oracle';
|
|
8
8
|
import { BasketFilter } from './states/basket';
|
|
9
9
|
import { IntentFilter } from './states/intents/intent';
|
|
10
|
-
import { getSwapPairs,
|
|
11
|
-
import { OraclePrice } from './states/oracles/oracle';
|
|
10
|
+
import { getSwapPairs, isRebalanceRequired, RebalanceIntentFilter } from './states/intents/rebalanceIntent';
|
|
12
11
|
import { WithdrawBasketFeesFilter } from './states/withdrawBasketFees';
|
|
13
12
|
import { BasketCreationTx, TxPayloadBatchSequence, VersionedTxs, Wallet } from './txUtils';
|
|
14
13
|
export declare class SymmetryCore {
|
|
@@ -91,19 +90,6 @@ export declare class SymmetryCore {
|
|
|
91
90
|
* @returns {Promise<Basket>} The basket with the price.
|
|
92
91
|
*/
|
|
93
92
|
loadBasketPrice(basket: Basket): Promise<Basket>;
|
|
94
|
-
loadBasketPriceWithPythPriceOverrides(params: {
|
|
95
|
-
basket: Basket;
|
|
96
|
-
pyth_price_overrides?: Map<string, OraclePrice>;
|
|
97
|
-
}): Promise<Basket>;
|
|
98
|
-
/**
|
|
99
|
-
* Checks whether a basket currently meets the automation rebalance trigger.
|
|
100
|
-
* Uses the existing basket pricing flow.
|
|
101
|
-
*/
|
|
102
|
-
isBasketRebalanceRequired(params: {
|
|
103
|
-
basket: string | Basket;
|
|
104
|
-
pyth_price_overrides?: Map<string, OraclePrice>;
|
|
105
|
-
}): Promise<boolean>;
|
|
106
|
-
private computeBasketRebalanceRequiredFromPricedBasket;
|
|
107
93
|
/**
|
|
108
94
|
* Fetches an intent by its public key.
|
|
109
95
|
* @param {string} intentPubkey - The public key of the intent.
|
package/dist/src/index.js
CHANGED
|
@@ -193,84 +193,6 @@ class SymmetryCore {
|
|
|
193
193
|
return yield (0, basket_1.loadBasketPrice)(basket, this.sdkParams.connection);
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
|
-
loadBasketPriceWithPythPriceOverrides(params) {
|
|
197
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
198
|
-
return yield (0, basket_1.loadBasketPriceWithPythPriceOverrides)(params.basket, this.sdkParams.connection, params.pyth_price_overrides);
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Checks whether a basket currently meets the automation rebalance trigger.
|
|
203
|
-
* Uses the existing basket pricing flow.
|
|
204
|
-
*/
|
|
205
|
-
isBasketRebalanceRequired(params) {
|
|
206
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
207
|
-
var _a;
|
|
208
|
-
let basket = typeof params.basket === 'string'
|
|
209
|
-
? yield this.fetchBasket(params.basket)
|
|
210
|
-
: params.basket;
|
|
211
|
-
if (!((_a = basket.formatted) === null || _a === void 0 ? void 0 : _a.automation_settings.enabled) && basket.settings.automation.allowAutomation !== 1) {
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
if (params.pyth_price_overrides && params.pyth_price_overrides.size > 0) {
|
|
215
|
-
basket = yield this.loadBasketPriceWithPythPriceOverrides({
|
|
216
|
-
basket,
|
|
217
|
-
pyth_price_overrides: params.pyth_price_overrides,
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
basket = yield this.loadBasketPrice(basket);
|
|
222
|
-
}
|
|
223
|
-
return this.computeBasketRebalanceRequiredFromPricedBasket(basket);
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
computeBasketRebalanceRequiredFromPricedBasket(basket) {
|
|
227
|
-
var _a, _b, _c;
|
|
228
|
-
const basketTvl = (_a = basket.tvl) !== null && _a !== void 0 ? _a : basket.composition
|
|
229
|
-
.slice(0, basket.numTokens)
|
|
230
|
-
.reduce((sum, asset) => {
|
|
231
|
-
var _a, _b, _c;
|
|
232
|
-
const value = (_c = (_a = asset.value) !== null && _a !== void 0 ? _a : (_b = asset.price) === null || _b === void 0 ? void 0 : _b.getMid().mul(new decimal_js_1.default(asset.amount.toString()))) !== null && _c !== void 0 ? _c : new decimal_js_1.default(0);
|
|
233
|
-
return sum.add(value);
|
|
234
|
-
}, new decimal_js_1.default(0));
|
|
235
|
-
if (!basketTvl.isFinite() || basketTvl.lte(0)) {
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
238
|
-
const weightSum = basket.composition
|
|
239
|
-
.slice(0, basket.numTokens)
|
|
240
|
-
.reduce((sum, asset) => sum + asset.weight, 0);
|
|
241
|
-
if (weightSum <= 0) {
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
|
-
const requiredRelBps = new decimal_js_1.default(basket.settings.automation.rebalanceActivationThresholdRelBps);
|
|
245
|
-
const requiredAbsBps = new decimal_js_1.default(basket.settings.automation.rebalanceActivationThresholdAbsBps);
|
|
246
|
-
const bountyMint = basket.settings.bountyMint;
|
|
247
|
-
const hundredPercentBps = new decimal_js_1.default(10000);
|
|
248
|
-
for (const asset of basket.composition.slice(0, basket.numTokens)) {
|
|
249
|
-
if (asset.mint.equals(bountyMint)) {
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
const tokenPrice = (_b = asset.price) === null || _b === void 0 ? void 0 : _b.getMid();
|
|
253
|
-
if (!tokenPrice || !tokenPrice.isFinite() || tokenPrice.lte(0)) {
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
const tokenValue = (_c = asset.value) !== null && _c !== void 0 ? _c : tokenPrice.mul(new decimal_js_1.default(asset.amount.toString()));
|
|
257
|
-
const targetValue = basketTvl.mul(asset.weight).div(weightSum);
|
|
258
|
-
const valueDiff = tokenValue.sub(targetValue).abs();
|
|
259
|
-
if (valueDiff.eq(0)) {
|
|
260
|
-
continue;
|
|
261
|
-
}
|
|
262
|
-
const maxValue = decimal_js_1.default.max(tokenValue, targetValue);
|
|
263
|
-
if (!maxValue.isFinite() || maxValue.lte(0)) {
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
const relBps = valueDiff.div(maxValue).mul(hundredPercentBps);
|
|
267
|
-
const absBps = valueDiff.div(basketTvl).mul(hundredPercentBps);
|
|
268
|
-
if (relBps.gte(requiredRelBps) && absBps.gte(requiredAbsBps)) {
|
|
269
|
-
return true;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return false;
|
|
273
|
-
}
|
|
274
196
|
/**
|
|
275
197
|
* Fetches an intent by its public key.
|
|
276
198
|
* @param {string} intentPubkey - The public key of the intent.
|
|
@@ -1866,13 +1788,41 @@ class SymmetryCore {
|
|
|
1866
1788
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1867
1789
|
let keeper = new web3_js_1.PublicKey(params.keeper);
|
|
1868
1790
|
let rebalanceIntent = (yield this.fetchRebalanceIntent(params.rebalance_intent)).chain_data;
|
|
1791
|
+
const tokensWithBalance = rebalanceIntent.tokens.filter(token => token.amount.gt(new bn_js_1.default(0)));
|
|
1792
|
+
const ownerIsKeeper = rebalanceIntent.owner.equals(keeper);
|
|
1793
|
+
let redeemableTokenMints = tokensWithBalance.map(token => token.mint);
|
|
1794
|
+
if (!ownerIsKeeper && tokensWithBalance.length > 0) {
|
|
1795
|
+
const mintInfos = yield this.sdkParams.connection.getMultipleAccountsInfo(tokensWithBalance.map(token => token.mint));
|
|
1796
|
+
const ataChecks = tokensWithBalance.map((token, index) => {
|
|
1797
|
+
const mintInfo = mintInfos[index];
|
|
1798
|
+
if (!mintInfo) {
|
|
1799
|
+
throw new Error(`Mint account not found for redeem token ${token.mint.toBase58()}`);
|
|
1800
|
+
}
|
|
1801
|
+
let tokenProgram;
|
|
1802
|
+
if (mintInfo.owner.equals(spl_token_1.TOKEN_PROGRAM_ID) || mintInfo.owner.equals(spl_token_1.TOKEN_2022_PROGRAM_ID)) {
|
|
1803
|
+
tokenProgram = mintInfo.owner;
|
|
1804
|
+
}
|
|
1805
|
+
else {
|
|
1806
|
+
throw new Error(`Unsupported token program for redeem token ${token.mint.toBase58()}: ${mintInfo.owner.toBase58()}`);
|
|
1807
|
+
}
|
|
1808
|
+
return {
|
|
1809
|
+
mint: token.mint,
|
|
1810
|
+
ata: (0, pda_1.getAta)(rebalanceIntent.owner, token.mint, tokenProgram),
|
|
1811
|
+
};
|
|
1812
|
+
});
|
|
1813
|
+
const ataInfos = yield this.sdkParams.connection.getMultipleAccountsInfo(ataChecks.map(item => item.ata));
|
|
1814
|
+
redeemableTokenMints = ataChecks
|
|
1815
|
+
.filter((_, index) => ataInfos[index] !== null)
|
|
1816
|
+
.map(item => item.mint);
|
|
1817
|
+
if (redeemableTokenMints.length === 0) {
|
|
1818
|
+
const blockedMints = ataChecks.map(item => item.mint.toBase58()).join(', ');
|
|
1819
|
+
throw new Error(`NoRedeemableTokens: owner ${rebalanceIntent.owner.toBase58()} has no ATA for remaining tokens [${blockedMints}]`);
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1869
1822
|
let batchSize = 7;
|
|
1870
1823
|
let ixs = [];
|
|
1871
|
-
for (let batchStart = 0; batchStart <
|
|
1872
|
-
let tokenMints =
|
|
1873
|
-
for (let i = batchStart; i < rebalanceIntent.tokens.length && i < batchStart + batchSize; i++)
|
|
1874
|
-
if (rebalanceIntent.tokens[i].amount.gt(new bn_js_1.default(0)))
|
|
1875
|
-
tokenMints.push(rebalanceIntent.tokens[i].mint);
|
|
1824
|
+
for (let batchStart = 0; batchStart < redeemableTokenMints.length; batchStart += batchSize) {
|
|
1825
|
+
let tokenMints = redeemableTokenMints.slice(batchStart, batchStart + batchSize);
|
|
1876
1826
|
if (tokenMints.length > 0) {
|
|
1877
1827
|
ixs.push((0, withdraw_1.redeemTokensIx)({
|
|
1878
1828
|
keeper: keeper,
|
|
@@ -8,7 +8,7 @@ const web3_js_1 = require("@solana/web3.js");
|
|
|
8
8
|
const constants_1 = require("../../constants");
|
|
9
9
|
const pda_1 = require("../pda");
|
|
10
10
|
const WITHDRAW_FEES_DISCRIMINATOR = Buffer.from([159, 222, 146, 66, 254, 108, 55, 51]);
|
|
11
|
-
const CLAIM_FEE_TOKENS_FROM_BASKET_DISCRIMINATOR = Buffer.from([53, 109, 220, 141,
|
|
11
|
+
const CLAIM_FEE_TOKENS_FROM_BASKET_DISCRIMINATOR = Buffer.from([53, 109, 220, 141, 110, 5, 193, 32]);
|
|
12
12
|
function withdrawFeesIx(params) {
|
|
13
13
|
let { claimer, basketTokenMint, feeType } = params;
|
|
14
14
|
let basket = (0, pda_1.getBasketState)(basketTokenMint);
|
|
@@ -268,7 +268,7 @@ function createEditBasketIntentIx(params) {
|
|
|
268
268
|
oracleSettings: {
|
|
269
269
|
oracleType: (_b = (_a = [...oracle_1.ORACLE_TYPES_STRINGS.entries()].find(([, name]) => name === addTokenData.oracles[i].oracle_type)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 255,
|
|
270
270
|
numRequiredAccounts: 0,
|
|
271
|
-
weight: addTokenData.oracles[i].
|
|
271
|
+
weight: addTokenData.oracles[i].weight_bps,
|
|
272
272
|
isRequired: addTokenData.oracles[i].is_required ? 1 : 0,
|
|
273
273
|
confThreshBps: addTokenData.oracles[i].conf_thresh_bps,
|
|
274
274
|
volatilityThreshBps: addTokenData.oracles[i].volatility_thresh_bps,
|
|
@@ -279,7 +279,7 @@ function createEditBasketIntentIx(params) {
|
|
|
279
279
|
tokenDecimals: addTokenData.oracles[i].token_decimals,
|
|
280
280
|
twapSecondsAgo: new bn_js_1.default(addTokenData.oracles[i].twap_seconds_ago),
|
|
281
281
|
twapSecondarySecondsAgo: new bn_js_1.default(addTokenData.oracles[i].twap_secondary_seconds_ago),
|
|
282
|
-
quote: (_d = (_c = [...oracle_1.QUOTES_STRINGS.entries()].find(([, name]) => name === addTokenData.oracles[i].
|
|
282
|
+
quote: (_d = (_c = [...oracle_1.QUOTES_STRINGS.entries()].find(([, name]) => name === addTokenData.oracles[i].quote_token)) === null || _c === void 0 ? void 0 : _c[0]) !== null && _d !== void 0 ? _d : oracle_1.Quote.Usd,
|
|
283
283
|
side: oracle_1.Side.Base,
|
|
284
284
|
},
|
|
285
285
|
accountsToLoadLutIds: new Array(oracle_1.MAX_ACCOUNTS_PER_ORACLE).fill(0),
|
|
@@ -107,6 +107,7 @@ export interface FormattedBasket {
|
|
|
107
107
|
active_withdraws: number;
|
|
108
108
|
active_managements: number;
|
|
109
109
|
last_automation_execution_timestamp: number;
|
|
110
|
+
creation_timestamp: number;
|
|
110
111
|
creator_settings: FormattedCreatorSettings;
|
|
111
112
|
manager_settings: FormattedManagersSettings;
|
|
112
113
|
fee_settings: FormattedFeeSettings;
|
|
@@ -190,6 +190,7 @@ export interface BasketSettings {
|
|
|
190
190
|
makeDirectSwapLastUpdateTimestamp: BN;
|
|
191
191
|
makeDirectSwapIntentAuthorityBitmask: number;
|
|
192
192
|
extraData: BN[];
|
|
193
|
+
creationTimestamp: BN;
|
|
193
194
|
}
|
|
194
195
|
export declare const BasketSettingsLayout: any;
|
|
195
196
|
export interface FormattedGlobalConfig {
|
|
@@ -190,7 +190,8 @@ exports.BasketSettingsLayout = (0, borsh_1.struct)([
|
|
|
190
190
|
(0, borsh_1.u64)('makeDirectSwapDelay'),
|
|
191
191
|
(0, borsh_1.u64)('makeDirectSwapLastUpdateTimestamp'),
|
|
192
192
|
(0, borsh_1.u16)('makeDirectSwapIntentAuthorityBitmask'),
|
|
193
|
-
(0, borsh_1.array)((0, borsh_1.u64)(),
|
|
193
|
+
(0, borsh_1.array)((0, borsh_1.u64)(), 31, 'extraData'),
|
|
194
|
+
(0, borsh_1.u64)('creationTimestamp'),
|
|
194
195
|
]);
|
|
195
196
|
exports.GlobalConfigLayout = (0, borsh_1.struct)([
|
|
196
197
|
(0, borsh_1.publicKey)('admin'),
|
|
@@ -172,7 +172,7 @@ export interface OracleInput {
|
|
|
172
172
|
account_lut_id: number;
|
|
173
173
|
account_lut_index: number;
|
|
174
174
|
account: string;
|
|
175
|
-
|
|
175
|
+
weight_bps: number;
|
|
176
176
|
is_required: boolean;
|
|
177
177
|
conf_thresh_bps: number;
|
|
178
178
|
volatility_thresh_bps: number;
|
|
@@ -183,7 +183,7 @@ export interface OracleInput {
|
|
|
183
183
|
token_decimals: number;
|
|
184
184
|
twap_seconds_ago: number;
|
|
185
185
|
twap_secondary_seconds_ago: number;
|
|
186
|
-
|
|
186
|
+
quote_token: FormattedQuote;
|
|
187
187
|
}
|
|
188
188
|
export interface AddOrEditTokenInput {
|
|
189
189
|
token_mint: string;
|
|
@@ -228,7 +228,7 @@ function addFieldsToBasket(basket) {
|
|
|
228
228
|
account_lut_index: oracle.accountsToLoadLutIndices[0],
|
|
229
229
|
account: lookup_tables.active[oracle.accountsToLoadLutIds[0]].contents[oracle.accountsToLoadLutIndices[0]],
|
|
230
230
|
num_required_accounts: oracle.oracleSettings.numRequiredAccounts,
|
|
231
|
-
|
|
231
|
+
weight_bps: oracle.oracleSettings.weight,
|
|
232
232
|
is_required: oracle.oracleSettings.isRequired == 1 ? true : false,
|
|
233
233
|
conf_thresh_bps: oracle.oracleSettings.confThreshBps,
|
|
234
234
|
volatility_thresh_bps: oracle.oracleSettings.volatilityThreshBps,
|
|
@@ -239,7 +239,7 @@ function addFieldsToBasket(basket) {
|
|
|
239
239
|
token_decimals: oracle.oracleSettings.tokenDecimals,
|
|
240
240
|
twap_seconds_ago: parseInt(oracle.oracleSettings.twapSecondsAgo.toString()),
|
|
241
241
|
twap_secondary_seconds_ago: parseInt(oracle.oracleSettings.twapSecondarySecondsAgo.toString()),
|
|
242
|
-
|
|
242
|
+
quote_token: (_b = oracle_1.QUOTES_STRINGS.get(oracle.oracleSettings.quote)) !== null && _b !== void 0 ? _b : "usd",
|
|
243
243
|
side: oracle.oracleSettings.side == 0 ? "base" : "quote",
|
|
244
244
|
},
|
|
245
245
|
accounts_to_load_lut_ids: oracle.accountsToLoadLutIds.map(id => id),
|
|
@@ -271,6 +271,7 @@ function addFieldsToBasket(basket) {
|
|
|
271
271
|
active_withdraws: parseInt(basket.settings.activeWithdraws.toString()),
|
|
272
272
|
active_managements: parseInt(basket.settings.activeManagements.toString()),
|
|
273
273
|
last_automation_execution_timestamp: parseInt(basket.settings.lastAutomationExecutionTimestamp.toString()),
|
|
274
|
+
creation_timestamp: parseInt(basket.settings.creationTimestamp.toString()),
|
|
274
275
|
creator_settings: creator_settings,
|
|
275
276
|
manager_settings: manager_settings,
|
|
276
277
|
fee_settings: fee_settings,
|
|
@@ -183,7 +183,7 @@ function decodeTaskDataForType(intent) {
|
|
|
183
183
|
account_lut_index: oracle.accountsToLoadLutIndices[0],
|
|
184
184
|
account: "",
|
|
185
185
|
num_required_accounts: oracle.oracleSettings.numRequiredAccounts,
|
|
186
|
-
|
|
186
|
+
weight_bps: oracle.oracleSettings.weight,
|
|
187
187
|
is_required: oracle.oracleSettings.isRequired == 1 ? true : false,
|
|
188
188
|
conf_thresh_bps: oracle.oracleSettings.confThreshBps,
|
|
189
189
|
volatility_thresh_bps: oracle.oracleSettings.volatilityThreshBps,
|
|
@@ -194,7 +194,7 @@ function decodeTaskDataForType(intent) {
|
|
|
194
194
|
token_decimals: oracle.oracleSettings.tokenDecimals,
|
|
195
195
|
twap_seconds_ago: parseInt(oracle.oracleSettings.twapSecondsAgo.toString()),
|
|
196
196
|
twap_secondary_seconds_ago: parseInt(oracle.oracleSettings.twapSecondarySecondsAgo.toString()),
|
|
197
|
-
|
|
197
|
+
quote_token: (_b = oracle_1.QUOTES_STRINGS.get(oracle.oracleSettings.quote)) !== null && _b !== void 0 ? _b : "usd",
|
|
198
198
|
});
|
|
199
199
|
}),
|
|
200
200
|
};
|
|
@@ -27,6 +27,7 @@ const txUtils_1 = require("../../txUtils");
|
|
|
27
27
|
const bn_js_1 = __importDefault(require("bn.js"));
|
|
28
28
|
const basket_1 = require("../basket");
|
|
29
29
|
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
30
|
+
const pythOracle_1 = require("../oracles/pythOracle");
|
|
30
31
|
function computeRebalanceIntentBountyAmount(rebalance_type, num_tokens, bounty_bond, bounty_per_task, bounty_per_price_update_task_max) {
|
|
31
32
|
let num_tasks = 0;
|
|
32
33
|
num_tasks += 1; // FinishPriceUpdates;
|
|
@@ -684,6 +685,10 @@ function isRebalanceRequired(basket, connection) {
|
|
|
684
685
|
return __awaiter(this, void 0, void 0, function* () {
|
|
685
686
|
if (basket.settings.automation.allowAutomation !== 1)
|
|
686
687
|
return false;
|
|
688
|
+
if (parseInt(basket.settings.activeRebalance.toString()) > 0)
|
|
689
|
+
return false;
|
|
690
|
+
if (parseInt(basket.settings.bountyBalance.toString()) == 0)
|
|
691
|
+
return false;
|
|
687
692
|
let cycleTimestamp = new bn_js_1.default(0);
|
|
688
693
|
let currentTimestamp = new bn_js_1.default(Math.floor(Date.now() / 1000));
|
|
689
694
|
if (basket.settings.schedule.cycleStartTime.gt(currentTimestamp))
|
|
@@ -698,7 +703,10 @@ function isRebalanceRequired(basket, connection) {
|
|
|
698
703
|
.add(basket.settings.automation.rebalanceActivationCooldown);
|
|
699
704
|
if (nextRebalanceTimestamp.gte(currentTimestamp))
|
|
700
705
|
return false;
|
|
701
|
-
|
|
706
|
+
const pythPriceOverrides = yield (0, pythOracle_1.buildFreshBasketPythPriceOverrides)(basket, connection);
|
|
707
|
+
basket = pythPriceOverrides.size > 0
|
|
708
|
+
? yield (0, basket_1.loadBasketPriceWithPythPriceOverrides)(basket, connection, pythPriceOverrides)
|
|
709
|
+
: yield (0, basket_1.loadBasketPrice)(basket, connection);
|
|
702
710
|
let basketTvl = new decimal_js_1.default(0);
|
|
703
711
|
let weightSum = 0;
|
|
704
712
|
for (let i = 0; i < basket.numTokens; i++) {
|
|
@@ -62,13 +62,15 @@ class PriceAggregator {
|
|
|
62
62
|
const oracleData = agg.oracles[i];
|
|
63
63
|
const settings = oracleData.oracleSettings;
|
|
64
64
|
let loadedAccounts = [];
|
|
65
|
-
let
|
|
65
|
+
let firstLoadedPubkey;
|
|
66
66
|
for (let j = 0; j < settings.numRequiredAccounts; j++) {
|
|
67
67
|
const lutId = oracleData.accountsToLoadLutIds[j];
|
|
68
68
|
const lutIdx = oracleData.accountsToLoadLutIndices[j];
|
|
69
69
|
const pubkey = lutAccounts[lutId].state.addresses[lutIdx];
|
|
70
70
|
const account = accountInfoMap.get(pubkey.toBase58());
|
|
71
|
-
|
|
71
|
+
if (!firstLoadedPubkey) {
|
|
72
|
+
firstLoadedPubkey = pubkey;
|
|
73
|
+
}
|
|
72
74
|
// @ts-ignore
|
|
73
75
|
loadedAccounts.push(account);
|
|
74
76
|
}
|
|
@@ -93,8 +95,8 @@ class PriceAggregator {
|
|
|
93
95
|
let result = (() => {
|
|
94
96
|
switch (settings.oracleType) {
|
|
95
97
|
case oracle_1.OracleType.Pyth:
|
|
96
|
-
if (
|
|
97
|
-
const override = pythPriceOverrides === null || pythPriceOverrides === void 0 ? void 0 : pythPriceOverrides.get(
|
|
98
|
+
if (firstLoadedPubkey) {
|
|
99
|
+
const override = pythPriceOverrides === null || pythPriceOverrides === void 0 ? void 0 : pythPriceOverrides.get(firstLoadedPubkey.toBase58());
|
|
98
100
|
if (override) {
|
|
99
101
|
return override;
|
|
100
102
|
}
|
|
@@ -4,6 +4,7 @@ import { AccountInfo, Connection, Keypair, PublicKey, TransactionInstruction } f
|
|
|
4
4
|
import { OracleSettings } from '../../layouts/oracle';
|
|
5
5
|
import { TxBatchData } from '../../txUtils';
|
|
6
6
|
import { OraclePrice } from './oracle';
|
|
7
|
+
import { Basket } from '../../layouts/basket';
|
|
7
8
|
export interface HermesPythPriceData {
|
|
8
9
|
price: string | number;
|
|
9
10
|
conf: string | number;
|
|
@@ -24,6 +25,7 @@ export declare function parseVerificationLevel(buf: Buffer, offset: number): {
|
|
|
24
25
|
level: VerificationLevel;
|
|
25
26
|
size: number;
|
|
26
27
|
};
|
|
28
|
+
export declare function buildFreshBasketPythPriceOverrides(basket: Basket, connection: Connection): Promise<Map<string, OraclePrice>>;
|
|
27
29
|
export declare const TIP_ACCOUNTS: string[];
|
|
28
30
|
export declare function getRandomTipAccount(): PublicKey;
|
|
29
31
|
export declare function buildJitoTipInstruction(payer: PublicKey, lamports: number): TransactionInstruction;
|
|
@@ -16,6 +16,7 @@ exports.PythOracle = exports.PythState = exports.PriceFeedMessage = exports.TIP_
|
|
|
16
16
|
exports.fetchHermesPythPrices = fetchHermesPythPrices;
|
|
17
17
|
exports.buildPythOraclePriceFromHermesPriceData = buildPythOraclePriceFromHermesPriceData;
|
|
18
18
|
exports.parseVerificationLevel = parseVerificationLevel;
|
|
19
|
+
exports.buildFreshBasketPythPriceOverrides = buildFreshBasketPythPriceOverrides;
|
|
19
20
|
exports.getRandomTipAccount = getRandomTipAccount;
|
|
20
21
|
exports.buildJitoTipInstruction = buildJitoTipInstruction;
|
|
21
22
|
exports.getPythPriceFeedAccountAddress = getPythPriceFeedAccountAddress;
|
|
@@ -131,6 +132,77 @@ function parseVerificationLevel(buf, offset) {
|
|
|
131
132
|
throw new Error(`Unknown verification level: ${discr}`);
|
|
132
133
|
}
|
|
133
134
|
}
|
|
135
|
+
function buildFreshBasketPythPriceOverrides(basket, connection) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
var _a, _b;
|
|
138
|
+
const uniqueAccounts = new Map();
|
|
139
|
+
const settingsByAccount = new Map();
|
|
140
|
+
const addPythAccount = (pubkey, settings) => {
|
|
141
|
+
const key = pubkey.toBase58();
|
|
142
|
+
if (!uniqueAccounts.has(key)) {
|
|
143
|
+
uniqueAccounts.set(key, pubkey);
|
|
144
|
+
}
|
|
145
|
+
if (!settingsByAccount.has(key)) {
|
|
146
|
+
settingsByAccount.set(key, settings);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
for (let i = 0; i < basket.numTokens; i++) {
|
|
150
|
+
const agg = basket.composition[i].oracleAggregator;
|
|
151
|
+
for (let j = 0; j < agg.numOracles; j++) {
|
|
152
|
+
const oracleData = agg.oracles[j];
|
|
153
|
+
if (oracleData.oracleSettings.oracleType !== oracle_1.OracleType.Pyth) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const lutId = oracleData.accountsToLoadLutIds[0];
|
|
157
|
+
const lutIdx = oracleData.accountsToLoadLutIndices[0];
|
|
158
|
+
const pubkey = (_b = (_a = basket.lutPubkeys) === null || _a === void 0 ? void 0 : _a[lutId]) === null || _b === void 0 ? void 0 : _b.state.addresses[lutIdx];
|
|
159
|
+
if (!pubkey) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
addPythAccount(pubkey, oracleData.oracleSettings);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
addPythAccount(constants_1.PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT, oracle_1.PYTH_WSOL_ORACLE_SETTINGS);
|
|
166
|
+
addPythAccount(constants_1.PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT, oracle_1.PYTH_USDC_ORACLE_SETTINGS);
|
|
167
|
+
if (uniqueAccounts.size === 0) {
|
|
168
|
+
return new Map();
|
|
169
|
+
}
|
|
170
|
+
const { feedIds, feedIdToAccount } = yield fetchFeedIdsFromAccounts(connection, Array.from(uniqueAccounts.values()));
|
|
171
|
+
const hermesPrices = yield fetchHermesPythPrices(feedIds);
|
|
172
|
+
const unitQuotePrice = new oracle_2.OraclePrice(new decimal_js_1.default(1), new decimal_js_1.default(0), 0, true);
|
|
173
|
+
const wsolAccountKey = constants_1.PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT.toBase58();
|
|
174
|
+
const usdcAccountKey = constants_1.PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT.toBase58();
|
|
175
|
+
let wsolPrice = unitQuotePrice;
|
|
176
|
+
let usdcPrice = unitQuotePrice;
|
|
177
|
+
for (const [feedId, account] of feedIdToAccount.entries()) {
|
|
178
|
+
const accountKey = account.toBase58();
|
|
179
|
+
const hermesPrice = hermesPrices.get(feedId);
|
|
180
|
+
if (!hermesPrice) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (accountKey === wsolAccountKey) {
|
|
184
|
+
wsolPrice = buildPythOraclePriceFromHermesPriceData(oracle_1.PYTH_WSOL_ORACLE_SETTINGS, hermesPrice, unitQuotePrice, unitQuotePrice);
|
|
185
|
+
}
|
|
186
|
+
else if (accountKey === usdcAccountKey) {
|
|
187
|
+
usdcPrice = buildPythOraclePriceFromHermesPriceData(oracle_1.PYTH_USDC_ORACLE_SETTINGS, hermesPrice, unitQuotePrice, unitQuotePrice);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const overrides = new Map();
|
|
191
|
+
for (const [feedId, hermesPrice] of hermesPrices.entries()) {
|
|
192
|
+
const account = feedIdToAccount.get(feedId);
|
|
193
|
+
if (!account) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const accountKey = account.toBase58();
|
|
197
|
+
const settings = settingsByAccount.get(accountKey);
|
|
198
|
+
if (!settings) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
overrides.set(accountKey, buildPythOraclePriceFromHermesPriceData(settings, hermesPrice, wsolPrice, usdcPrice));
|
|
202
|
+
}
|
|
203
|
+
return overrides;
|
|
204
|
+
});
|
|
205
|
+
}
|
|
134
206
|
// Pyth program IDs (mainnet)
|
|
135
207
|
const DEFAULT_RECEIVER_PROGRAM_ID = new web3_js_1.PublicKey("rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ");
|
|
136
208
|
const DEFAULT_PUSH_ORACLE_PROGRAM_ID = new web3_js_1.PublicKey("pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT");
|
package/dist/test.js
CHANGED
|
@@ -49,7 +49,7 @@ function testStates() {
|
|
|
49
49
|
console.log("Total intents: ", (yield sdk.fetchAllIntents()).length);
|
|
50
50
|
console.log("Total rebalance intents: ", (yield sdk.fetchAllRebalanceIntents()).length);
|
|
51
51
|
console.log("Total withdraw basket fees: ", (yield sdk.fetchAllWithdrawBasketFees()).length);
|
|
52
|
-
let basket = yield sdk.fetchBasket("
|
|
52
|
+
let basket = yield sdk.fetchBasket("C2SpNsmPB91ne4JdQRYZZdTJXkMLWyHfMSaZCS9nB33J");
|
|
53
53
|
basket = yield sdk.loadBasketPrice(basket);
|
|
54
54
|
// let ri =(await sdk.fetchAllRebalanceIntents())[0];
|
|
55
55
|
// ri = await sdk.fetchRebalanceIntent(ri.formatted_data.pubkey);
|
|
@@ -298,7 +298,7 @@ function testStates() {
|
|
|
298
298
|
account_lut_id: 0,
|
|
299
299
|
account_lut_index: 0,
|
|
300
300
|
account: constants_1.PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT.toBase58(),
|
|
301
|
-
|
|
301
|
+
weight_bps: 10000,
|
|
302
302
|
is_required: true,
|
|
303
303
|
conf_thresh_bps: 200,
|
|
304
304
|
volatility_thresh_bps: 200,
|
|
@@ -309,7 +309,7 @@ function testStates() {
|
|
|
309
309
|
token_decimals: 9,
|
|
310
310
|
twap_seconds_ago: 100,
|
|
311
311
|
twap_secondary_seconds_ago: 100,
|
|
312
|
-
|
|
312
|
+
quote_token: "usd",
|
|
313
313
|
},
|
|
314
314
|
],
|
|
315
315
|
};
|
|
@@ -480,7 +480,7 @@ function testStates() {
|
|
|
480
480
|
if (tests.claimTokenFeesFromBasket) {
|
|
481
481
|
let tx = yield sdk.claimTokenFeesFromBasketTx({
|
|
482
482
|
claimer: wallet.publicKey.toBase58(),
|
|
483
|
-
withdrawBasketFees: new web3_js_1.PublicKey("").toBase58(),
|
|
483
|
+
withdrawBasketFees: new web3_js_1.PublicKey("CiX2zEUhWRwirCwsfst49PeFoQXTthcjxj8YnFoYGQ4Y").toBase58(),
|
|
484
484
|
});
|
|
485
485
|
let res = yield sdk.signAndSendTxPayloadBatchSequence({ txPayloadBatchSequence: tx, wallet });
|
|
486
486
|
console.log(res);
|
|
@@ -506,17 +506,17 @@ function testStates() {
|
|
|
506
506
|
maxWithdrawFeeBps: 1000,
|
|
507
507
|
maxManagementFeeBps: 2000,
|
|
508
508
|
maxPerformanceFeeBps: 2000,
|
|
509
|
-
symmetryFeeCollector: new web3_js_1.PublicKey("
|
|
510
|
-
symmetryDepositFeeBps:
|
|
511
|
-
symmetryDepositFeeShareBps:
|
|
512
|
-
symmetryWithdrawFeeBps:
|
|
513
|
-
symmetryWithdrawFeeShareBps:
|
|
514
|
-
symmetryManagementFeeBps:
|
|
515
|
-
symmetryManagementFeeShareBps:
|
|
516
|
-
symmetryPerformanceFeeBps:
|
|
517
|
-
symmetryPerformanceFeeShareBps:
|
|
518
|
-
symmetryTradeFeeBps:
|
|
519
|
-
symmetryLimitOrderFeeBps:
|
|
509
|
+
symmetryFeeCollector: new web3_js_1.PublicKey("9A5V7smsUMRNNzvrawbDx3ZexZR3LY1bcEUXUiMJ2bxk"),
|
|
510
|
+
symmetryDepositFeeBps: 0,
|
|
511
|
+
symmetryDepositFeeShareBps: 0,
|
|
512
|
+
symmetryWithdrawFeeBps: 0,
|
|
513
|
+
symmetryWithdrawFeeShareBps: 0,
|
|
514
|
+
symmetryManagementFeeBps: 0,
|
|
515
|
+
symmetryManagementFeeShareBps: 0,
|
|
516
|
+
symmetryPerformanceFeeBps: 0,
|
|
517
|
+
symmetryPerformanceFeeShareBps: 0,
|
|
518
|
+
symmetryTradeFeeBps: 0,
|
|
519
|
+
symmetryLimitOrderFeeBps: 0,
|
|
520
520
|
symmetryFeesExtraData: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,],
|
|
521
521
|
bountyMint: new web3_js_1.PublicKey("So11111111111111111111111111111111111111112"),
|
|
522
522
|
minBountyForBasketAutomation: new anchor_1.BN(200 * 50 * 10 ** 3),
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -68,7 +68,7 @@ import {
|
|
|
68
68
|
import { FormattedOracleType, OracleType } from './layouts/oracle';
|
|
69
69
|
import {
|
|
70
70
|
BasketFilter, computeTokenMintsHash, fetchBasket, fetchBaskets, fetchBasketsMultiple,
|
|
71
|
-
loadBasketPrice
|
|
71
|
+
loadBasketPrice
|
|
72
72
|
} from './states/basket';
|
|
73
73
|
import { fetchGlobalConfig } from './states/config';
|
|
74
74
|
import {
|
|
@@ -76,9 +76,8 @@ import {
|
|
|
76
76
|
} from './states/intents/intent';
|
|
77
77
|
import {
|
|
78
78
|
computeRebalanceIntentBountyAmount, fetchRebalanceIntent, fetchRebalanceIntents,
|
|
79
|
-
fetchRebalanceIntentsMultiple, getSwapPairs,
|
|
79
|
+
fetchRebalanceIntentsMultiple, getSwapPairs, isRebalanceRequired, RebalanceIntentFilter
|
|
80
80
|
} from './states/intents/rebalanceIntent';
|
|
81
|
-
import { OraclePrice } from './states/oracles/oracle';
|
|
82
81
|
import { buildPythPriceFeedUpdateIxs, fetchFeedIdsFromAccounts } from './states/oracles/pythOracle';
|
|
83
82
|
import {
|
|
84
83
|
fetchWithdrawBasketFees, fetchWithdrawBasketFeesList, fetchWithdrawBasketFeesMultiple,
|
|
@@ -238,101 +237,6 @@ export class SymmetryCore {
|
|
|
238
237
|
return await loadBasketPrice(basket, this.sdkParams.connection);
|
|
239
238
|
}
|
|
240
239
|
|
|
241
|
-
async loadBasketPriceWithPythPriceOverrides(params: {
|
|
242
|
-
basket: Basket,
|
|
243
|
-
pyth_price_overrides?: Map<string, OraclePrice>,
|
|
244
|
-
}): Promise<Basket> {
|
|
245
|
-
return await loadBasketPriceWithPythPriceOverrides(
|
|
246
|
-
params.basket,
|
|
247
|
-
this.sdkParams.connection,
|
|
248
|
-
params.pyth_price_overrides,
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Checks whether a basket currently meets the automation rebalance trigger.
|
|
254
|
-
* Uses the existing basket pricing flow.
|
|
255
|
-
*/
|
|
256
|
-
async isBasketRebalanceRequired(params: {
|
|
257
|
-
basket: string | Basket,
|
|
258
|
-
pyth_price_overrides?: Map<string, OraclePrice>,
|
|
259
|
-
}): Promise<boolean> {
|
|
260
|
-
let basket = typeof params.basket === 'string'
|
|
261
|
-
? await this.fetchBasket(params.basket)
|
|
262
|
-
: params.basket;
|
|
263
|
-
|
|
264
|
-
if (!basket.formatted?.automation_settings.enabled && basket.settings.automation.allowAutomation !== 1) {
|
|
265
|
-
return false;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (params.pyth_price_overrides && params.pyth_price_overrides.size > 0) {
|
|
269
|
-
basket = await this.loadBasketPriceWithPythPriceOverrides({
|
|
270
|
-
basket,
|
|
271
|
-
pyth_price_overrides: params.pyth_price_overrides,
|
|
272
|
-
});
|
|
273
|
-
} else {
|
|
274
|
-
basket = await this.loadBasketPrice(basket);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return this.computeBasketRebalanceRequiredFromPricedBasket(basket);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
private computeBasketRebalanceRequiredFromPricedBasket(basket: Basket): boolean {
|
|
281
|
-
const basketTvl = basket.tvl ?? basket.composition
|
|
282
|
-
.slice(0, basket.numTokens)
|
|
283
|
-
.reduce((sum, asset) => {
|
|
284
|
-
const value = asset.value ?? asset.price?.getMid().mul(new Decimal(asset.amount.toString())) ?? new Decimal(0);
|
|
285
|
-
return sum.add(value);
|
|
286
|
-
}, new Decimal(0));
|
|
287
|
-
|
|
288
|
-
if (!basketTvl.isFinite() || basketTvl.lte(0)) {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const weightSum = basket.composition
|
|
293
|
-
.slice(0, basket.numTokens)
|
|
294
|
-
.reduce((sum, asset) => sum + asset.weight, 0);
|
|
295
|
-
if (weightSum <= 0) {
|
|
296
|
-
return false;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const requiredRelBps = new Decimal(basket.settings.automation.rebalanceActivationThresholdRelBps);
|
|
300
|
-
const requiredAbsBps = new Decimal(basket.settings.automation.rebalanceActivationThresholdAbsBps);
|
|
301
|
-
const bountyMint = basket.settings.bountyMint;
|
|
302
|
-
const hundredPercentBps = new Decimal(10_000);
|
|
303
|
-
|
|
304
|
-
for (const asset of basket.composition.slice(0, basket.numTokens)) {
|
|
305
|
-
if (asset.mint.equals(bountyMint)) {
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const tokenPrice = asset.price?.getMid();
|
|
310
|
-
if (!tokenPrice || !tokenPrice.isFinite() || tokenPrice.lte(0)) {
|
|
311
|
-
continue;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const tokenValue = asset.value ?? tokenPrice.mul(new Decimal(asset.amount.toString()));
|
|
315
|
-
const targetValue = basketTvl.mul(asset.weight).div(weightSum);
|
|
316
|
-
const valueDiff = tokenValue.sub(targetValue).abs();
|
|
317
|
-
if (valueDiff.eq(0)) {
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const maxValue = Decimal.max(tokenValue, targetValue);
|
|
322
|
-
if (!maxValue.isFinite() || maxValue.lte(0)) {
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
const relBps = valueDiff.div(maxValue).mul(hundredPercentBps);
|
|
327
|
-
const absBps = valueDiff.div(basketTvl).mul(hundredPercentBps);
|
|
328
|
-
if (relBps.gte(requiredRelBps) && absBps.gte(requiredAbsBps)) {
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
240
|
/**
|
|
337
241
|
* Fetches an intent by its public key.
|
|
338
242
|
* @param {string} intentPubkey - The public key of the intent.
|
|
@@ -2088,13 +1992,48 @@ export class SymmetryCore {
|
|
|
2088
1992
|
}): Promise<TxPayloadBatchSequence> {
|
|
2089
1993
|
let keeper = new PublicKey(params.keeper);
|
|
2090
1994
|
let rebalanceIntent: RebalanceIntent = (await this.fetchRebalanceIntent(params.rebalance_intent)).chain_data;
|
|
1995
|
+
const tokensWithBalance = rebalanceIntent.tokens.filter(token => token.amount.gt(new BN(0)));
|
|
1996
|
+
const ownerIsKeeper = rebalanceIntent.owner.equals(keeper);
|
|
1997
|
+
|
|
1998
|
+
let redeemableTokenMints = tokensWithBalance.map(token => token.mint);
|
|
1999
|
+
if (!ownerIsKeeper && tokensWithBalance.length > 0) {
|
|
2000
|
+
const mintInfos = await this.sdkParams.connection.getMultipleAccountsInfo(tokensWithBalance.map(token => token.mint));
|
|
2001
|
+
const ataChecks = tokensWithBalance.map((token, index) => {
|
|
2002
|
+
const mintInfo = mintInfos[index];
|
|
2003
|
+
if (!mintInfo) {
|
|
2004
|
+
throw new Error(`Mint account not found for redeem token ${token.mint.toBase58()}`);
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
let tokenProgram: PublicKey;
|
|
2008
|
+
if (mintInfo.owner.equals(TOKEN_PROGRAM_ID) || mintInfo.owner.equals(TOKEN_2022_PROGRAM_ID)) {
|
|
2009
|
+
tokenProgram = mintInfo.owner;
|
|
2010
|
+
} else {
|
|
2011
|
+
throw new Error(`Unsupported token program for redeem token ${token.mint.toBase58()}: ${mintInfo.owner.toBase58()}`);
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
return {
|
|
2015
|
+
mint: token.mint,
|
|
2016
|
+
ata: getAta(rebalanceIntent.owner, token.mint, tokenProgram),
|
|
2017
|
+
};
|
|
2018
|
+
});
|
|
2019
|
+
|
|
2020
|
+
const ataInfos = await this.sdkParams.connection.getMultipleAccountsInfo(ataChecks.map(item => item.ata));
|
|
2021
|
+
redeemableTokenMints = ataChecks
|
|
2022
|
+
.filter((_, index) => ataInfos[index] !== null)
|
|
2023
|
+
.map(item => item.mint);
|
|
2024
|
+
|
|
2025
|
+
if (redeemableTokenMints.length === 0) {
|
|
2026
|
+
const blockedMints = ataChecks.map(item => item.mint.toBase58()).join(', ');
|
|
2027
|
+
throw new Error(
|
|
2028
|
+
`NoRedeemableTokens: owner ${rebalanceIntent.owner.toBase58()} has no ATA for remaining tokens [${blockedMints}]`
|
|
2029
|
+
);
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2091
2033
|
let batchSize = 7;
|
|
2092
2034
|
let ixs: TransactionInstruction[] = [];
|
|
2093
|
-
for (let batchStart = 0; batchStart <
|
|
2094
|
-
let tokenMints
|
|
2095
|
-
for (let i = batchStart; i < rebalanceIntent.tokens.length && i < batchStart + batchSize; i++)
|
|
2096
|
-
if (rebalanceIntent.tokens[i].amount.gt(new BN(0)))
|
|
2097
|
-
tokenMints.push(rebalanceIntent.tokens[i].mint);
|
|
2035
|
+
for (let batchStart = 0; batchStart < redeemableTokenMints.length; batchStart += batchSize) {
|
|
2036
|
+
let tokenMints = redeemableTokenMints.slice(batchStart, batchStart + batchSize);
|
|
2098
2037
|
if (tokenMints.length > 0) {
|
|
2099
2038
|
ixs.push(
|
|
2100
2039
|
redeemTokensIx({
|
|
@@ -2106,6 +2045,7 @@ export class SymmetryCore {
|
|
|
2106
2045
|
);
|
|
2107
2046
|
}
|
|
2108
2047
|
}
|
|
2048
|
+
|
|
2109
2049
|
let txBatchData: TxBatchData = {batches: [ixs.map(ix => ({
|
|
2110
2050
|
payer: keeper,
|
|
2111
2051
|
instructions: [
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
|
|
11
11
|
const WITHDRAW_FEES_DISCRIMINATOR = Buffer.from([159, 222, 146, 66, 254, 108, 55, 51]);
|
|
12
12
|
|
|
13
|
-
const CLAIM_FEE_TOKENS_FROM_BASKET_DISCRIMINATOR = Buffer.from([53, 109, 220, 141,
|
|
13
|
+
const CLAIM_FEE_TOKENS_FROM_BASKET_DISCRIMINATOR = Buffer.from([53, 109, 220, 141, 110, 5, 193, 32]);
|
|
14
14
|
|
|
15
15
|
export function withdrawFeesIx(params: {
|
|
16
16
|
claimer: PublicKey,
|
|
@@ -350,7 +350,7 @@ export function createEditBasketIntentIx(params: {
|
|
|
350
350
|
oracleSettings: {
|
|
351
351
|
oracleType: [...ORACLE_TYPES_STRINGS.entries()].find(([, name]) => name === addTokenData.oracles[i].oracle_type)?.[0] ?? 255,
|
|
352
352
|
numRequiredAccounts: 0,
|
|
353
|
-
weight: addTokenData.oracles[i].
|
|
353
|
+
weight: addTokenData.oracles[i].weight_bps,
|
|
354
354
|
isRequired: addTokenData.oracles[i].is_required ? 1 : 0,
|
|
355
355
|
confThreshBps: addTokenData.oracles[i].conf_thresh_bps,
|
|
356
356
|
volatilityThreshBps: addTokenData.oracles[i].volatility_thresh_bps,
|
|
@@ -361,7 +361,7 @@ export function createEditBasketIntentIx(params: {
|
|
|
361
361
|
tokenDecimals: addTokenData.oracles[i].token_decimals,
|
|
362
362
|
twapSecondsAgo: new BN(addTokenData.oracles[i].twap_seconds_ago),
|
|
363
363
|
twapSecondarySecondsAgo: new BN(addTokenData.oracles[i].twap_secondary_seconds_ago),
|
|
364
|
-
quote: [...QUOTES_STRINGS.entries()].find(([, name]) => name === addTokenData.oracles[i].
|
|
364
|
+
quote: [...QUOTES_STRINGS.entries()].find(([, name]) => name === addTokenData.oracles[i].quote_token)?.[0] ?? Quote.Usd,
|
|
365
365
|
side: Side.Base,
|
|
366
366
|
},
|
|
367
367
|
accountsToLoadLutIds: new Array(MAX_ACCOUNTS_PER_ORACLE).fill(0),
|
package/src/layouts/basket.ts
CHANGED
|
@@ -102,6 +102,7 @@ export interface FormattedBasket {
|
|
|
102
102
|
active_withdraws: number;
|
|
103
103
|
active_managements: number;
|
|
104
104
|
last_automation_execution_timestamp: number;
|
|
105
|
+
creation_timestamp: number;
|
|
105
106
|
creator_settings: FormattedCreatorSettings;
|
|
106
107
|
manager_settings: FormattedManagersSettings;
|
|
107
108
|
fee_settings: FormattedFeeSettings;
|
package/src/layouts/config.ts
CHANGED
|
@@ -350,6 +350,7 @@ export interface BasketSettings {
|
|
|
350
350
|
makeDirectSwapIntentAuthorityBitmask: number; // u16,
|
|
351
351
|
|
|
352
352
|
extraData: BN[]; // [u64; 32],
|
|
353
|
+
creationTimestamp: BN; // u64,
|
|
353
354
|
}
|
|
354
355
|
|
|
355
356
|
export const BasketSettingsLayout = struct<BasketSettings>([
|
|
@@ -420,7 +421,8 @@ export const BasketSettingsLayout = struct<BasketSettings>([
|
|
|
420
421
|
u64('makeDirectSwapLastUpdateTimestamp'),
|
|
421
422
|
u16('makeDirectSwapIntentAuthorityBitmask'),
|
|
422
423
|
|
|
423
|
-
array(u64(),
|
|
424
|
+
array(u64(), 31, 'extraData'),
|
|
425
|
+
u64('creationTimestamp'),
|
|
424
426
|
]);
|
|
425
427
|
|
|
426
428
|
|
|
@@ -265,7 +265,7 @@ export interface OracleInput {
|
|
|
265
265
|
account_lut_id: number,
|
|
266
266
|
account_lut_index: number,
|
|
267
267
|
account: string,
|
|
268
|
-
|
|
268
|
+
weight_bps: number,
|
|
269
269
|
is_required: boolean,
|
|
270
270
|
conf_thresh_bps: number,
|
|
271
271
|
volatility_thresh_bps: number,
|
|
@@ -276,7 +276,7 @@ export interface OracleInput {
|
|
|
276
276
|
token_decimals: number,
|
|
277
277
|
twap_seconds_ago: number,
|
|
278
278
|
twap_secondary_seconds_ago: number,
|
|
279
|
-
|
|
279
|
+
quote_token: FormattedQuote,
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
export interface AddOrEditTokenInput {
|
package/src/states/basket.ts
CHANGED
|
@@ -226,7 +226,7 @@ export function addFieldsToBasket(basket: Basket): Basket {
|
|
|
226
226
|
account_lut_index: oracle.accountsToLoadLutIndices[0],
|
|
227
227
|
account: lookup_tables.active[oracle.accountsToLoadLutIds[0]].contents[oracle.accountsToLoadLutIndices[0]],
|
|
228
228
|
num_required_accounts: oracle.oracleSettings.numRequiredAccounts,
|
|
229
|
-
|
|
229
|
+
weight_bps: oracle.oracleSettings.weight,
|
|
230
230
|
is_required: oracle.oracleSettings.isRequired == 1 ? true : false,
|
|
231
231
|
conf_thresh_bps: oracle.oracleSettings.confThreshBps,
|
|
232
232
|
volatility_thresh_bps: oracle.oracleSettings.volatilityThreshBps,
|
|
@@ -237,7 +237,7 @@ export function addFieldsToBasket(basket: Basket): Basket {
|
|
|
237
237
|
token_decimals: oracle.oracleSettings.tokenDecimals,
|
|
238
238
|
twap_seconds_ago: parseInt(oracle.oracleSettings.twapSecondsAgo.toString()),
|
|
239
239
|
twap_secondary_seconds_ago: parseInt(oracle.oracleSettings.twapSecondarySecondsAgo.toString()),
|
|
240
|
-
|
|
240
|
+
quote_token: QUOTES_STRINGS.get(oracle.oracleSettings.quote) ?? "usd",
|
|
241
241
|
side: oracle.oracleSettings.side == 0 ? "base" : "quote",
|
|
242
242
|
},
|
|
243
243
|
accounts_to_load_lut_ids: oracle.accountsToLoadLutIds.map(id => id),
|
|
@@ -270,6 +270,7 @@ export function addFieldsToBasket(basket: Basket): Basket {
|
|
|
270
270
|
active_withdraws: parseInt(basket.settings.activeWithdraws.toString()),
|
|
271
271
|
active_managements: parseInt(basket.settings.activeManagements.toString()),
|
|
272
272
|
last_automation_execution_timestamp: parseInt(basket.settings.lastAutomationExecutionTimestamp.toString()),
|
|
273
|
+
creation_timestamp: parseInt(basket.settings.creationTimestamp.toString()),
|
|
273
274
|
creator_settings: creator_settings,
|
|
274
275
|
manager_settings: manager_settings,
|
|
275
276
|
fee_settings: fee_settings,
|
|
@@ -170,7 +170,7 @@ function decodeTaskDataForType(intent: Intent): Settings {
|
|
|
170
170
|
account_lut_index: oracle.accountsToLoadLutIndices[0],
|
|
171
171
|
account: "",
|
|
172
172
|
num_required_accounts: oracle.oracleSettings.numRequiredAccounts,
|
|
173
|
-
|
|
173
|
+
weight_bps: oracle.oracleSettings.weight,
|
|
174
174
|
is_required: oracle.oracleSettings.isRequired == 1 ? true : false,
|
|
175
175
|
conf_thresh_bps: oracle.oracleSettings.confThreshBps,
|
|
176
176
|
volatility_thresh_bps: oracle.oracleSettings.volatilityThreshBps,
|
|
@@ -181,7 +181,7 @@ function decodeTaskDataForType(intent: Intent): Settings {
|
|
|
181
181
|
token_decimals: oracle.oracleSettings.tokenDecimals,
|
|
182
182
|
twap_seconds_ago: parseInt(oracle.oracleSettings.twapSecondsAgo.toString()),
|
|
183
183
|
twap_secondary_seconds_ago: parseInt(oracle.oracleSettings.twapSecondarySecondsAgo.toString()),
|
|
184
|
-
|
|
184
|
+
quote_token: QUOTES_STRINGS.get(oracle.oracleSettings.quote) ?? "usd",
|
|
185
185
|
})),
|
|
186
186
|
}
|
|
187
187
|
return add_token_input;
|
|
@@ -7,8 +7,9 @@ import { getMultipleAccountsInfoBatched } from "../../txUtils";
|
|
|
7
7
|
import BN from "bn.js";
|
|
8
8
|
import { Basket, FormattedBasket } from "../../layouts/basket";
|
|
9
9
|
import { OraclePriceOnChain } from "../../layouts/oracle";
|
|
10
|
-
import { fetchBasket, loadBasketPrice } from "../basket";
|
|
10
|
+
import { fetchBasket, loadBasketPrice, loadBasketPriceWithPythPriceOverrides } from "../basket";
|
|
11
11
|
import Decimal from "decimal.js";
|
|
12
|
+
import { buildFreshBasketPythPriceOverrides } from "../oracles/pythOracle";
|
|
12
13
|
|
|
13
14
|
export function computeRebalanceIntentBountyAmount(
|
|
14
15
|
rebalance_type: RebalanceType,
|
|
@@ -756,6 +757,8 @@ export async function isRebalanceRequired(
|
|
|
756
757
|
connection: Connection,
|
|
757
758
|
): Promise<boolean> {
|
|
758
759
|
if (basket.settings.automation.allowAutomation !== 1) return false;
|
|
760
|
+
if (parseInt(basket.settings.activeRebalance.toString()) > 0) return false;
|
|
761
|
+
if (parseInt(basket.settings.bountyBalance.toString()) == 0) return false;
|
|
759
762
|
let cycleTimestamp = new BN(0);
|
|
760
763
|
let currentTimestamp = new BN(Math.floor(Date.now() / 1000));
|
|
761
764
|
if (basket.settings.schedule.cycleStartTime.gt(currentTimestamp))
|
|
@@ -773,7 +776,10 @@ export async function isRebalanceRequired(
|
|
|
773
776
|
if (nextRebalanceTimestamp.gte(currentTimestamp))
|
|
774
777
|
return false;
|
|
775
778
|
|
|
776
|
-
|
|
779
|
+
const pythPriceOverrides = await buildFreshBasketPythPriceOverrides(basket, connection);
|
|
780
|
+
basket = pythPriceOverrides.size > 0
|
|
781
|
+
? await loadBasketPriceWithPythPriceOverrides(basket, connection, pythPriceOverrides)
|
|
782
|
+
: await loadBasketPrice(basket, connection);
|
|
777
783
|
let basketTvl = new Decimal(0);
|
|
778
784
|
let weightSum = 0;
|
|
779
785
|
for (let i = 0; i < basket.numTokens; i++) {
|
|
@@ -93,13 +93,15 @@ export class PriceAggregator{
|
|
|
93
93
|
const settings = oracleData.oracleSettings;
|
|
94
94
|
|
|
95
95
|
let loadedAccounts: AccountInfo<Buffer>[] = [];
|
|
96
|
-
let
|
|
96
|
+
let firstLoadedPubkey: PublicKey | undefined;
|
|
97
97
|
for (let j = 0; j < settings.numRequiredAccounts; j++) {
|
|
98
98
|
const lutId = oracleData.accountsToLoadLutIds[j];
|
|
99
99
|
const lutIdx = oracleData.accountsToLoadLutIndices[j];
|
|
100
100
|
const pubkey = lutAccounts[lutId].state.addresses[lutIdx];
|
|
101
101
|
const account = accountInfoMap.get(pubkey.toBase58());
|
|
102
|
-
|
|
102
|
+
if (!firstLoadedPubkey) {
|
|
103
|
+
firstLoadedPubkey = pubkey;
|
|
104
|
+
}
|
|
103
105
|
// @ts-ignore
|
|
104
106
|
loadedAccounts.push(account);
|
|
105
107
|
}
|
|
@@ -125,8 +127,8 @@ export class PriceAggregator{
|
|
|
125
127
|
let result = (() => {
|
|
126
128
|
switch (settings.oracleType) {
|
|
127
129
|
case OracleType.Pyth:
|
|
128
|
-
if (
|
|
129
|
-
const override = pythPriceOverrides?.get(
|
|
130
|
+
if (firstLoadedPubkey) {
|
|
131
|
+
const override = pythPriceOverrides?.get(firstLoadedPubkey.toBase58());
|
|
130
132
|
if (override) {
|
|
131
133
|
return override;
|
|
132
134
|
}
|
|
@@ -7,11 +7,12 @@ import {
|
|
|
7
7
|
SystemProgram, Transaction, TransactionInstruction, TransactionMessage, VersionedTransaction
|
|
8
8
|
} from '@solana/web3.js';
|
|
9
9
|
|
|
10
|
-
import { HUNDRED_PERCENT_BPS } from '../../constants';
|
|
11
|
-
import { OracleSettings, Quote } from '../../layouts/oracle';
|
|
10
|
+
import { HUNDRED_PERCENT_BPS, PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT, PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT } from '../../constants';
|
|
11
|
+
import { OracleSettings, OracleType, PYTH_USDC_ORACLE_SETTINGS, PYTH_WSOL_ORACLE_SETTINGS, Quote } from '../../layouts/oracle';
|
|
12
12
|
import { TxBatchData, TxData } from '../../txUtils';
|
|
13
13
|
import { HERMES_PUBLIC_ENDPOINT, SOLANA_DEVNET_ENDPOINT } from './constants';
|
|
14
14
|
import { OraclePrice } from './oracle';
|
|
15
|
+
import { Basket } from '../../layouts/basket';
|
|
15
16
|
|
|
16
17
|
export interface HermesPythPriceData {
|
|
17
18
|
price: string | number;
|
|
@@ -157,6 +158,107 @@ export function parseVerificationLevel(buf: Buffer, offset: number): { level: Ve
|
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
export async function buildFreshBasketPythPriceOverrides(
|
|
162
|
+
basket: Basket,
|
|
163
|
+
connection: Connection,
|
|
164
|
+
): Promise<Map<string, OraclePrice>> {
|
|
165
|
+
const uniqueAccounts = new Map<string, PublicKey>();
|
|
166
|
+
const settingsByAccount = new Map<string, typeof PYTH_WSOL_ORACLE_SETTINGS>();
|
|
167
|
+
|
|
168
|
+
const addPythAccount = (pubkey: PublicKey, settings: typeof PYTH_WSOL_ORACLE_SETTINGS) => {
|
|
169
|
+
const key = pubkey.toBase58();
|
|
170
|
+
if (!uniqueAccounts.has(key)) {
|
|
171
|
+
uniqueAccounts.set(key, pubkey);
|
|
172
|
+
}
|
|
173
|
+
if (!settingsByAccount.has(key)) {
|
|
174
|
+
settingsByAccount.set(key, settings);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
for (let i = 0; i < basket.numTokens; i++) {
|
|
179
|
+
const agg = basket.composition[i].oracleAggregator;
|
|
180
|
+
for (let j = 0; j < agg.numOracles; j++) {
|
|
181
|
+
const oracleData = agg.oracles[j];
|
|
182
|
+
if (oracleData.oracleSettings.oracleType !== OracleType.Pyth) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const lutId = oracleData.accountsToLoadLutIds[0];
|
|
187
|
+
const lutIdx = oracleData.accountsToLoadLutIndices[0];
|
|
188
|
+
const pubkey = basket.lutPubkeys?.[lutId]?.state.addresses[lutIdx];
|
|
189
|
+
if (!pubkey) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
addPythAccount(pubkey, oracleData.oracleSettings);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
addPythAccount(PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT, PYTH_WSOL_ORACLE_SETTINGS);
|
|
198
|
+
addPythAccount(PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT, PYTH_USDC_ORACLE_SETTINGS);
|
|
199
|
+
|
|
200
|
+
if (uniqueAccounts.size === 0) {
|
|
201
|
+
return new Map();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const { feedIds, feedIdToAccount } = await fetchFeedIdsFromAccounts(
|
|
205
|
+
connection,
|
|
206
|
+
Array.from(uniqueAccounts.values()),
|
|
207
|
+
);
|
|
208
|
+
const hermesPrices = await fetchHermesPythPrices(feedIds);
|
|
209
|
+
|
|
210
|
+
const unitQuotePrice = new OraclePrice(new Decimal(1), new Decimal(0), 0, true);
|
|
211
|
+
const wsolAccountKey = PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT.toBase58();
|
|
212
|
+
const usdcAccountKey = PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT.toBase58();
|
|
213
|
+
let wsolPrice = unitQuotePrice;
|
|
214
|
+
let usdcPrice = unitQuotePrice;
|
|
215
|
+
|
|
216
|
+
for (const [feedId, account] of feedIdToAccount.entries()) {
|
|
217
|
+
const accountKey = account.toBase58();
|
|
218
|
+
const hermesPrice = hermesPrices.get(feedId);
|
|
219
|
+
if (!hermesPrice) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (accountKey === wsolAccountKey) {
|
|
224
|
+
wsolPrice = buildPythOraclePriceFromHermesPriceData(
|
|
225
|
+
PYTH_WSOL_ORACLE_SETTINGS,
|
|
226
|
+
hermesPrice,
|
|
227
|
+
unitQuotePrice,
|
|
228
|
+
unitQuotePrice,
|
|
229
|
+
);
|
|
230
|
+
} else if (accountKey === usdcAccountKey) {
|
|
231
|
+
usdcPrice = buildPythOraclePriceFromHermesPriceData(
|
|
232
|
+
PYTH_USDC_ORACLE_SETTINGS,
|
|
233
|
+
hermesPrice,
|
|
234
|
+
unitQuotePrice,
|
|
235
|
+
unitQuotePrice,
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const overrides = new Map<string, OraclePrice>();
|
|
241
|
+
for (const [feedId, hermesPrice] of hermesPrices.entries()) {
|
|
242
|
+
const account = feedIdToAccount.get(feedId);
|
|
243
|
+
if (!account) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const accountKey = account.toBase58();
|
|
248
|
+
const settings = settingsByAccount.get(accountKey);
|
|
249
|
+
if (!settings) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
overrides.set(
|
|
254
|
+
accountKey,
|
|
255
|
+
buildPythOraclePriceFromHermesPriceData(settings, hermesPrice, wsolPrice, usdcPrice),
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return overrides;
|
|
260
|
+
}
|
|
261
|
+
|
|
160
262
|
// Pyth program IDs (mainnet)
|
|
161
263
|
const DEFAULT_RECEIVER_PROGRAM_ID = new PublicKey("rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ");
|
|
162
264
|
const DEFAULT_PUSH_ORACLE_PROGRAM_ID = new PublicKey("pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT");
|
package/test.ts
CHANGED
|
@@ -47,7 +47,7 @@ async function testStates() {
|
|
|
47
47
|
console.log("Total rebalance intents: ", (await sdk.fetchAllRebalanceIntents()).length);
|
|
48
48
|
console.log("Total withdraw basket fees: ", (await sdk.fetchAllWithdrawBasketFees()).length);
|
|
49
49
|
|
|
50
|
-
let basket = await sdk.fetchBasket("
|
|
50
|
+
let basket = await sdk.fetchBasket("C2SpNsmPB91ne4JdQRYZZdTJXkMLWyHfMSaZCS9nB33J");
|
|
51
51
|
basket = await sdk.loadBasketPrice(basket);
|
|
52
52
|
// let ri =(await sdk.fetchAllRebalanceIntents())[0];
|
|
53
53
|
// ri = await sdk.fetchRebalanceIntent(ri.formatted_data.pubkey);
|
|
@@ -327,7 +327,7 @@ async function testStates() {
|
|
|
327
327
|
account_lut_id: 0,
|
|
328
328
|
account_lut_index: 0,
|
|
329
329
|
account: PYTHNET_CUSTODY_PRICE_WSOL_ACCOUNT.toBase58(),
|
|
330
|
-
|
|
330
|
+
weight_bps: 10000,
|
|
331
331
|
is_required: true,
|
|
332
332
|
conf_thresh_bps: 200,
|
|
333
333
|
volatility_thresh_bps: 200,
|
|
@@ -338,7 +338,7 @@ async function testStates() {
|
|
|
338
338
|
token_decimals: 9,
|
|
339
339
|
twap_seconds_ago: 100,
|
|
340
340
|
twap_secondary_seconds_ago: 100,
|
|
341
|
-
|
|
341
|
+
quote_token: "usd",
|
|
342
342
|
},
|
|
343
343
|
],
|
|
344
344
|
};
|
|
@@ -518,7 +518,7 @@ async function testStates() {
|
|
|
518
518
|
if (tests.claimTokenFeesFromBasket) {
|
|
519
519
|
let tx = await sdk.claimTokenFeesFromBasketTx({
|
|
520
520
|
claimer: wallet.publicKey.toBase58(),
|
|
521
|
-
withdrawBasketFees: new PublicKey("").toBase58(),
|
|
521
|
+
withdrawBasketFees: new PublicKey("CiX2zEUhWRwirCwsfst49PeFoQXTthcjxj8YnFoYGQ4Y").toBase58(),
|
|
522
522
|
});
|
|
523
523
|
let res = await sdk.signAndSendTxPayloadBatchSequence({txPayloadBatchSequence: tx, wallet});
|
|
524
524
|
console.log(res);
|
|
@@ -549,17 +549,17 @@ async function testStates() {
|
|
|
549
549
|
maxManagementFeeBps: 2000,
|
|
550
550
|
maxPerformanceFeeBps: 2000,
|
|
551
551
|
|
|
552
|
-
symmetryFeeCollector: new PublicKey("
|
|
553
|
-
symmetryDepositFeeBps:
|
|
554
|
-
symmetryDepositFeeShareBps:
|
|
555
|
-
symmetryWithdrawFeeBps:
|
|
556
|
-
symmetryWithdrawFeeShareBps:
|
|
557
|
-
symmetryManagementFeeBps:
|
|
558
|
-
symmetryManagementFeeShareBps:
|
|
559
|
-
symmetryPerformanceFeeBps:
|
|
560
|
-
symmetryPerformanceFeeShareBps:
|
|
561
|
-
symmetryTradeFeeBps:
|
|
562
|
-
symmetryLimitOrderFeeBps:
|
|
552
|
+
symmetryFeeCollector: new PublicKey("9A5V7smsUMRNNzvrawbDx3ZexZR3LY1bcEUXUiMJ2bxk"),
|
|
553
|
+
symmetryDepositFeeBps: 0,
|
|
554
|
+
symmetryDepositFeeShareBps: 0,
|
|
555
|
+
symmetryWithdrawFeeBps: 0,
|
|
556
|
+
symmetryWithdrawFeeShareBps: 0,
|
|
557
|
+
symmetryManagementFeeBps: 0,
|
|
558
|
+
symmetryManagementFeeShareBps: 0,
|
|
559
|
+
symmetryPerformanceFeeBps: 0,
|
|
560
|
+
symmetryPerformanceFeeShareBps: 0,
|
|
561
|
+
symmetryTradeFeeBps: 0,
|
|
562
|
+
symmetryLimitOrderFeeBps: 0,
|
|
563
563
|
symmetryFeesExtraData: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
|
|
564
564
|
|
|
565
565
|
bountyMint: new PublicKey("So11111111111111111111111111111111111111112"),
|