Skip to content

Commit 2ef8732

Browse files
committed
refactor: simplify object sorting and enhance price/product account mapping logic
1 parent 5b5ebb6 commit 2ef8732

File tree

3 files changed

+456
-384
lines changed

3 files changed

+456
-384
lines changed

governance/xc_admin/packages/xc_admin_common/src/programs/core/core_functions.ts

Lines changed: 63 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,7 @@ function checkSizeOfProductInstruction(
8686
/**
8787
* Sort object by keys
8888
*/
89-
const sortObjectByKeys = <T extends Record<string, unknown>>(
90-
obj: T,
91-
): Array<[string, unknown]> =>
89+
const sortObjectByKeys = <U>(obj: Record<string, U>): Array<[string, U]> =>
9290
Object.entries(obj).sort(([a], [b]) => a.localeCompare(b));
9391

9492
/**
@@ -133,7 +131,6 @@ function sortData(data: DownloadableConfig): DownloadableConfig {
133131
export function getConfig(
134132
params: CoreConfigParams & { programType: ProgramType.PYTH_CORE },
135133
): RawConfig {
136-
// No need for runtime check since it's enforced by the type system
137134
const accounts = params.accounts;
138135

139136
// Create a map of parsed base data for each account to avoid repeated parsing
@@ -145,72 +142,72 @@ export function getConfig(
145142
);
146143

147144
// First pass: Extract price accounts
148-
const priceAccounts = accounts.filter(
149-
(account) =>
150-
parsedBaseDataMap.get(account.pubkey.toBase58())?.type ===
151-
AccountType.Price,
152-
);
153-
154-
const priceRawConfigs = mapValues(
155-
Object.fromEntries(
156-
priceAccounts.map((account) => [account.pubkey.toBase58(), account]),
157-
),
158-
(account) => {
159-
const parsed = parsePriceData(account.account.data);
160-
return {
161-
next: parsed.nextPriceAccountKey,
162-
address: account.pubkey,
163-
publishers: parsed.priceComponents
164-
.filter((x) => x.publisher !== null && x.publisher !== undefined)
165-
.map((x) => x.publisher),
166-
expo: parsed.exponent,
167-
minPub: parsed.minPublishers,
168-
maxLatency: parsed.maxLatency,
169-
};
170-
},
145+
const priceRawConfigs = Object.fromEntries(
146+
accounts
147+
.filter(
148+
({ pubkey }) =>
149+
parsedBaseDataMap.get(pubkey.toBase58())?.type === AccountType.Price,
150+
)
151+
.map(({ account, pubkey }) => {
152+
const parsed = parsePriceData(account.data);
153+
return [
154+
pubkey.toBase58(),
155+
{
156+
next: parsed.nextPriceAccountKey,
157+
address: pubkey,
158+
publishers: parsed.priceComponents
159+
.filter((x) => x.publisher !== null && x.publisher !== undefined)
160+
.map((x) => x.publisher),
161+
expo: parsed.exponent,
162+
minPub: parsed.minPublishers,
163+
maxLatency: parsed.maxLatency,
164+
},
165+
];
166+
}),
171167
);
172168

173169
// Second pass: Extract product accounts and link to price accounts
174-
const productAccounts = accounts.filter(
175-
(account) =>
176-
parsedBaseDataMap.get(account.pubkey.toBase58())?.type ===
177-
AccountType.Product,
178-
);
179-
180-
const productRawConfigs = mapValues(
181-
Object.fromEntries(
182-
productAccounts.map((account) => [account.pubkey.toBase58(), account]),
183-
),
184-
(account) => {
185-
const parsed = parseProductData(account.account.data);
186-
const priceAccounts: PriceRawConfig[] = [];
187-
188-
// Follow the linked list of price accounts
189-
if (parsed.priceAccountKey) {
190-
let priceAccountKey: string | undefined =
191-
parsed.priceAccountKey.toBase58();
192-
const processedPriceKeys = new Set<string>();
193-
194-
while (
195-
priceAccountKey &&
196-
!processedPriceKeys.has(priceAccountKey) &&
197-
priceRawConfigs[priceAccountKey]
198-
) {
199-
processedPriceKeys.add(priceAccountKey);
200-
const priceConfig: PriceRawConfig = priceRawConfigs[priceAccountKey];
201-
priceAccounts.push(priceConfig);
202-
priceAccountKey = priceConfig.next
203-
? priceConfig.next.toBase58()
204-
: undefined;
170+
const productRawConfigs = Object.fromEntries(
171+
accounts
172+
.filter(
173+
({ pubkey }) =>
174+
parsedBaseDataMap.get(pubkey.toBase58())?.type ===
175+
AccountType.Product,
176+
)
177+
.map(({ account, pubkey }) => {
178+
const parsed = parseProductData(account.data);
179+
const priceAccounts: PriceRawConfig[] = [];
180+
181+
// Follow the linked list of price accounts
182+
if (parsed.priceAccountKey) {
183+
let priceAccountKey: string | undefined =
184+
parsed.priceAccountKey.toBase58();
185+
const processedPriceKeys = new Set<string>();
186+
187+
while (
188+
priceAccountKey &&
189+
!processedPriceKeys.has(priceAccountKey) &&
190+
priceRawConfigs[priceAccountKey]
191+
) {
192+
processedPriceKeys.add(priceAccountKey);
193+
const priceConfig: PriceRawConfig =
194+
priceRawConfigs[priceAccountKey];
195+
priceAccounts.push(priceConfig);
196+
priceAccountKey = priceConfig.next
197+
? priceConfig.next.toBase58()
198+
: undefined;
199+
}
205200
}
206-
}
207201

208-
return {
209-
priceAccounts,
210-
metadata: parsed.product,
211-
address: account.pubkey,
212-
};
213-
},
202+
return [
203+
pubkey.toBase58(),
204+
{
205+
priceAccounts,
206+
metadata: parsed.product,
207+
address: pubkey,
208+
},
209+
];
210+
}),
214211
);
215212

216213
// Third pass: Extract mapping accounts and permission data
@@ -282,9 +279,7 @@ export function getDownloadableConfig(
282279
product.metadata.symbol,
283280
{
284281
address: product.address.toBase58(),
285-
metadata: {
286-
...metadataWithoutPriceAccount,
287-
},
282+
metadata: metadataWithoutPriceAccount,
288283
priceAccounts: product.priceAccounts.map((p: PriceRawConfig) => {
289284
return {
290285
address: p.address.toBase58(),
@@ -314,11 +309,6 @@ export function validateUploadedConfig(
314309
cluster: PythCluster,
315310
): ValidationResult {
316311
try {
317-
// Validate that the uploaded data is valid JSON
318-
if (typeof uploadedConfig !== "object" || uploadedConfig === null) {
319-
return { isValid: false, error: "Invalid JSON format" };
320-
}
321-
322312
const existingSymbols = new Set(Object.keys(existingConfig));
323313
const changes: Record<
324314
string,

governance/xc_admin/packages/xc_admin_frontend/components/ProgramSwitch.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const ProgramSwitch = ({ light = false }: { light?: boolean }) => {
4848
>
4949
<span className="mr-3">
5050
{programOptions.find((option) => option.value === programType)
51-
?.label || PROGRAM_TYPE_NAMES[programType]}
51+
?.label ?? PROGRAM_TYPE_NAMES[programType]}
5252
</span>
5353
<Arrow className={`${open ? 'rotate-180' : ''}`} />
5454
</Menu.Button>

0 commit comments

Comments
 (0)