From 5cb8403c8d595cde6e0e49e62cd8c3a9a88ef4b7 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Thu, 6 Feb 2025 18:46:32 +0000 Subject: [PATCH 1/6] fix metadata too big error messages --- .../components/tabs/General.tsx | 58 +++++++++++++------ .../packages/xc_admin_frontend/next.config.js | 3 - .../sdk/js/solana_utils/src/transaction.ts | 5 ++ 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx index f4dad62a7e..a2119cdb41 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx +++ b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx @@ -36,6 +36,22 @@ import PermissionDepermissionKey from '../PermissionDepermissionKey' import { PriceRawConfig } from '../../hooks/usePyth' import { Wallet } from '@coral-xyz/anchor/dist/cjs/provider' +const MAX_SIZE_ADD_PRODUCT_INSTRUCTION_DATA = 369 +const MAX_SIZE_UPD_PRODUCT_INSTRUCTION_DATA = 403 // upd product has one account less + +const checkSizeOfProductInstruction = ( + instruction: TransactionInstruction, + maxSize: number, + symbol: string +) => { + const size = instruction.data.length + if (size > maxSize) { + throw new Error( + `A symbol metadata is too big to be sent in a transaction (${size} > ${maxSize} bytes). Please reduce the size of the symbol metadata for ${symbol}.` + ) + } +} + const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { const [data, setData] = useState({}) const [dataChanges, setDataChanges] = useState>() @@ -340,16 +356,20 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { ) )[0] // create add product account instruction - instructions.push( - await pythProgramClient.methods - .addProduct({ ...newChanges.metadata }) - .accounts({ - fundingAccount, - tailMappingAccount: rawConfig.mappingAccounts[0].address, - productAccount: productAccountKey, - }) - .instruction() + const instruction = await pythProgramClient.methods + .addProduct({ ...newChanges.metadata }) + .accounts({ + fundingAccount, + tailMappingAccount: rawConfig.mappingAccounts[0].address, + productAccount: productAccountKey, + }) + .instruction() + checkSizeOfProductInstruction( + instruction, + MAX_SIZE_ADD_PRODUCT_INSTRUCTION_DATA, + symbol ) + instructions.push(instruction) // deterministically generate price account key const priceAccountKey: PublicKey = ( @@ -478,15 +498,19 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { JSON.stringify(prev.metadata) !== JSON.stringify(newChanges.metadata) ) { + const instruction = await pythProgramClient.methods + .updProduct({ symbol, ...newChanges.metadata }) // If there's a symbol in newChanges.metadata, it will overwrite the current symbol + .accounts({ + fundingAccount, + productAccount: new PublicKey(prev.address), + }) + .instruction() // create update product account instruction - instructions.push( - await pythProgramClient.methods - .updProduct({ symbol, ...newChanges.metadata }) // If there's a symbol in newChanges.metadata, it will overwrite the current symbol - .accounts({ - fundingAccount, - productAccount: new PublicKey(prev.address), - }) - .instruction() + instructions.push(instruction) + checkSizeOfProductInstruction( + instruction, + MAX_SIZE_UPD_PRODUCT_INSTRUCTION_DATA, + symbol ) } diff --git a/governance/xc_admin/packages/xc_admin_frontend/next.config.js b/governance/xc_admin/packages/xc_admin_frontend/next.config.js index 816be34776..c92c49ee6a 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/next.config.js +++ b/governance/xc_admin/packages/xc_admin_frontend/next.config.js @@ -4,9 +4,6 @@ const path = require('path') const nextConfig = { reactStrictMode: true, output: process.env.BUILD_STANDALONE === 'true' ? 'standalone' : undefined, - experimental: { - externalDir: true, - }, webpack(config, { isServer }) { config.experiments = { asyncWebAssembly: true } config.resolve.fallback = { fs: false } diff --git a/target_chains/solana/sdk/js/solana_utils/src/transaction.ts b/target_chains/solana/sdk/js/solana_utils/src/transaction.ts index 3eacc4cf74..3caac0d28c 100644 --- a/target_chains/solana/sdk/js/solana_utils/src/transaction.ts +++ b/target_chains/solana/sdk/js/solana_utils/src/transaction.ts @@ -332,6 +332,11 @@ export class TransactionBuilder { false ); if (sizeWithInstruction > PACKET_DATA_SIZE) { + if (instructionsToSend.length == 0) { + throw new Error( + `An instruction is too big to be sent in a transaction (${sizeWithInstruction} > ${PACKET_DATA_SIZE} bytes)` + ); + } break; } instructionsToSend.push(instruction); From 1acf62fea86fcb2718e0e5913de31daffc6bdd98 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Thu, 6 Feb 2025 18:48:45 +0000 Subject: [PATCH 2/6] go --- target_chains/solana/sdk/js/solana_utils/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target_chains/solana/sdk/js/solana_utils/package.json b/target_chains/solana/sdk/js/solana_utils/package.json index 202ad72b52..e2754ab9d6 100644 --- a/target_chains/solana/sdk/js/solana_utils/package.json +++ b/target_chains/solana/sdk/js/solana_utils/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/solana-utils", - "version": "0.4.3", + "version": "0.4.4", "description": "Utility functions for Solana", "homepage": "https://pyth.network", "main": "lib/index.js", From b2a874232d79c276019bda99b58668cd875a7eba Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Thu, 6 Feb 2025 18:51:08 +0000 Subject: [PATCH 3/6] clean --- .../packages/xc_admin_frontend/components/tabs/General.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx index a2119cdb41..9357704260 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx +++ b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx @@ -505,13 +505,12 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { productAccount: new PublicKey(prev.address), }) .instruction() - // create update product account instruction - instructions.push(instruction) checkSizeOfProductInstruction( instruction, MAX_SIZE_UPD_PRODUCT_INSTRUCTION_DATA, symbol ) + instructions.push(instruction) } if ( From 5491954f7302ea0d254b9958d1c27eac51e637af Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Thu, 6 Feb 2025 19:02:28 +0000 Subject: [PATCH 4/6] catch --- .../components/tabs/General.tsx | 530 +++++++++--------- 1 file changed, 268 insertions(+), 262 deletions(-) diff --git a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx index 9357704260..40dba72e43 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx +++ b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx @@ -303,313 +303,317 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { } const handleSendProposalButtonClick = async () => { - if (pythProgramClient && dataChanges && !isMultisigLoading) { - const instructions: TransactionInstruction[] = [] - const publisherInPriceStoreInitializationsVerified: PublicKey[] = [] - - for (const symbol of Object.keys(dataChanges)) { - const multisigAuthority = readOnlySquads.getAuthorityPDA( - PRICE_FEED_MULTISIG[getMultisigCluster(cluster)], - 1 - ) - const fundingAccount = isRemote - ? mapKey(multisigAuthority) - : multisigAuthority - - const initPublisherInPriceStore = async (publisherKey: PublicKey) => { - // Ignore this step if Price Store is not initialized (or not deployed) - if (!connection || !(await isPriceStoreInitialized(connection))) { - return - } + const handleSendProposalButtonClickAsync = async () => { + if (pythProgramClient && dataChanges && !isMultisigLoading) { + const instructions: TransactionInstruction[] = [] + const publisherInPriceStoreInitializationsVerified: PublicKey[] = [] + + for (const symbol of Object.keys(dataChanges)) { + const multisigAuthority = readOnlySquads.getAuthorityPDA( + PRICE_FEED_MULTISIG[getMultisigCluster(cluster)], + 1 + ) + const fundingAccount = isRemote + ? mapKey(multisigAuthority) + : multisigAuthority + + const initPublisherInPriceStore = async (publisherKey: PublicKey) => { + // Ignore this step if Price Store is not initialized (or not deployed) + if (!connection || !(await isPriceStoreInitialized(connection))) { + return + } - if ( - publisherInPriceStoreInitializationsVerified.every( - (el) => !el.equals(publisherKey) - ) - ) { if ( - !connection || - !(await isPriceStorePublisherInitialized( - connection, - publisherKey - )) + publisherInPriceStoreInitializationsVerified.every( + (el) => !el.equals(publisherKey) + ) ) { - instructions.push( - await createDetermisticPriceStoreInitializePublisherInstruction( - fundingAccount, + if ( + !connection || + !(await isPriceStorePublisherInitialized( + connection, publisherKey + )) + ) { + instructions.push( + await createDetermisticPriceStoreInitializePublisherInstruction( + fundingAccount, + publisherKey + ) ) - ) + } + publisherInPriceStoreInitializationsVerified.push(publisherKey) } - publisherInPriceStoreInitializationsVerified.push(publisherKey) - } - } - const { prev, new: newChanges } = dataChanges[symbol] - // if prev is undefined, it means that the symbol is new - if (!prev) { - // deterministically generate product account key - const productAccountKey: PublicKey = ( - await findDetermisticAccountAddress( - AccountType.Product, - symbol, - cluster - ) - )[0] - // create add product account instruction - const instruction = await pythProgramClient.methods - .addProduct({ ...newChanges.metadata }) - .accounts({ - fundingAccount, - tailMappingAccount: rawConfig.mappingAccounts[0].address, - productAccount: productAccountKey, - }) - .instruction() - checkSizeOfProductInstruction( - instruction, - MAX_SIZE_ADD_PRODUCT_INSTRUCTION_DATA, - symbol - ) - instructions.push(instruction) - - // deterministically generate price account key - const priceAccountKey: PublicKey = ( - await findDetermisticAccountAddress( - AccountType.Price, - symbol, - cluster - ) - )[0] - // create add price account instruction - instructions.push( - await pythProgramClient.methods - .addPrice(newChanges.priceAccounts[0].expo, 1) - .accounts({ - fundingAccount, - productAccount: productAccountKey, - priceAccount: priceAccountKey, - }) - .instruction() - ) - - if (isMessageBufferAvailable(cluster) && messageBufferClient) { - // create create buffer instruction for the price account - instructions.push( - await messageBufferClient.methods - .createBuffer( - getPythOracleMessageBufferCpiAuth(cluster), - priceAccountKey, - MESSAGE_BUFFER_BUFFER_SIZE - ) - .accounts({ - admin: fundingAccount, - payer: PRICE_FEED_OPS_KEY, - }) - .remainingAccounts([ - { - pubkey: getMessageBufferAddressForPrice( - cluster, - priceAccountKey - ), - isSigner: false, - isWritable: true, - }, - ]) - .instruction() - ) } - - // create add publisher instruction if there are any publishers - for (const publisherKey of newChanges.priceAccounts[0].publishers) { - const publisherPubKey = new PublicKey(publisherKey) - instructions.push( - await pythProgramClient.methods - .addPublisher(publisherPubKey) - .accounts({ - fundingAccount, - priceAccount: priceAccountKey, - }) - .instruction() - ) - await initPublisherInPriceStore(publisherPubKey) - } - - // create set min publisher instruction if there are any publishers - if (newChanges.priceAccounts[0].minPub !== undefined) { - instructions.push( - await pythProgramClient.methods - .setMinPub(newChanges.priceAccounts[0].minPub, [0, 0, 0]) - .accounts({ - priceAccount: priceAccountKey, - fundingAccount, - }) - .instruction() - ) - } - } else if (!newChanges) { - const priceAccount = new PublicKey(prev.priceAccounts[0].address) - - // if new is undefined, it means that the symbol is deleted - // create delete price account instruction - instructions.push( - await pythProgramClient.methods - .delPrice() - .accounts({ - fundingAccount, - productAccount: new PublicKey(prev.address), - priceAccount, - }) - .instruction() - ) - - // create delete product account instruction - instructions.push( - await pythProgramClient.methods - .delProduct() - .accounts({ - fundingAccount, - mappingAccount: rawConfig.mappingAccounts[0].address, - productAccount: new PublicKey(prev.address), - }) - .instruction() - ) - - if (isMessageBufferAvailable(cluster) && messageBufferClient) { - // create delete buffer instruction for the price buffer - instructions.push( - await messageBufferClient.methods - .deleteBuffer( - getPythOracleMessageBufferCpiAuth(cluster), - priceAccount - ) - .accounts({ - admin: fundingAccount, - payer: PRICE_FEED_OPS_KEY, - messageBuffer: getMessageBufferAddressForPrice( - cluster, - priceAccount - ), - }) - .instruction() - ) - } - } else { - // check if metadata has changed - if ( - JSON.stringify(prev.metadata) !== - JSON.stringify(newChanges.metadata) - ) { + const { prev, new: newChanges } = dataChanges[symbol] + // if prev is undefined, it means that the symbol is new + if (!prev) { + // deterministically generate product account key + const productAccountKey: PublicKey = ( + await findDetermisticAccountAddress( + AccountType.Product, + symbol, + cluster + ) + )[0] + // create add product account instruction const instruction = await pythProgramClient.methods - .updProduct({ symbol, ...newChanges.metadata }) // If there's a symbol in newChanges.metadata, it will overwrite the current symbol + .addProduct({ ...newChanges.metadata }) .accounts({ fundingAccount, - productAccount: new PublicKey(prev.address), + tailMappingAccount: rawConfig.mappingAccounts[0].address, + productAccount: productAccountKey, }) .instruction() checkSizeOfProductInstruction( instruction, - MAX_SIZE_UPD_PRODUCT_INSTRUCTION_DATA, + MAX_SIZE_ADD_PRODUCT_INSTRUCTION_DATA, symbol ) instructions.push(instruction) - } - if ( - JSON.stringify(prev.priceAccounts[0].expo) !== - JSON.stringify(newChanges.priceAccounts[0].expo) - ) { - // create update exponent instruction + // deterministically generate price account key + const priceAccountKey: PublicKey = ( + await findDetermisticAccountAddress( + AccountType.Price, + symbol, + cluster + ) + )[0] + // create add price account instruction instructions.push( await pythProgramClient.methods - .setExponent(newChanges.priceAccounts[0].expo, 1) + .addPrice(newChanges.priceAccounts[0].expo, 1) .accounts({ fundingAccount, - priceAccount: new PublicKey(prev.priceAccounts[0].address), + productAccount: productAccountKey, + priceAccount: priceAccountKey, }) .instruction() ) - } - // check if maxLatency has changed - if ( - prev.priceAccounts[0].maxLatency !== - newChanges.priceAccounts[0].maxLatency - ) { - // create update product account instruction - instructions.push( - await pythProgramClient.methods - .setMaxLatency( - newChanges.priceAccounts[0].maxLatency, - [0, 0, 0] - ) - .accounts({ - priceAccount: new PublicKey(prev.priceAccounts[0].address), - fundingAccount, - }) - .instruction() - ) - } + if (isMessageBufferAvailable(cluster) && messageBufferClient) { + // create create buffer instruction for the price account + instructions.push( + await messageBufferClient.methods + .createBuffer( + getPythOracleMessageBufferCpiAuth(cluster), + priceAccountKey, + MESSAGE_BUFFER_BUFFER_SIZE + ) + .accounts({ + admin: fundingAccount, + payer: PRICE_FEED_OPS_KEY, + }) + .remainingAccounts([ + { + pubkey: getMessageBufferAddressForPrice( + cluster, + priceAccountKey + ), + isSigner: false, + isWritable: true, + }, + ]) + .instruction() + ) + } - // check if publishers have changed - const publisherKeysToAdd = - newChanges.priceAccounts[0].publishers.filter( - (newPublisher: string) => - !prev.priceAccounts[0].publishers.includes(newPublisher) - ) - // check if there are any publishers to remove by comparing prev and new - const publisherKeysToRemove = prev.priceAccounts[0].publishers.filter( - (prevPublisher: string) => - !newChanges.priceAccounts[0].publishers.includes(prevPublisher) - ) + // create add publisher instruction if there are any publishers + for (const publisherKey of newChanges.priceAccounts[0].publishers) { + const publisherPubKey = new PublicKey(publisherKey) + instructions.push( + await pythProgramClient.methods + .addPublisher(publisherPubKey) + .accounts({ + fundingAccount, + priceAccount: priceAccountKey, + }) + .instruction() + ) + await initPublisherInPriceStore(publisherPubKey) + } - // add instructions to remove publishers + // create set min publisher instruction if there are any publishers + if (newChanges.priceAccounts[0].minPub !== undefined) { + instructions.push( + await pythProgramClient.methods + .setMinPub(newChanges.priceAccounts[0].minPub, [0, 0, 0]) + .accounts({ + priceAccount: priceAccountKey, + fundingAccount, + }) + .instruction() + ) + } + } else if (!newChanges) { + const priceAccount = new PublicKey(prev.priceAccounts[0].address) - for (const publisherKey of publisherKeysToRemove) { + // if new is undefined, it means that the symbol is deleted + // create delete price account instruction instructions.push( await pythProgramClient.methods - .delPublisher(new PublicKey(publisherKey)) + .delPrice() .accounts({ fundingAccount, - priceAccount: new PublicKey(prev.priceAccounts[0].address), + productAccount: new PublicKey(prev.address), + priceAccount, }) .instruction() ) - } - // add instructions to add new publishers - for (const publisherKey of publisherKeysToAdd) { - const publisherPubKey = new PublicKey(publisherKey) + // create delete product account instruction instructions.push( await pythProgramClient.methods - .addPublisher(publisherPubKey) + .delProduct() .accounts({ fundingAccount, - priceAccount: new PublicKey(prev.priceAccounts[0].address), + mappingAccount: rawConfig.mappingAccounts[0].address, + productAccount: new PublicKey(prev.address), }) .instruction() ) - await initPublisherInPriceStore(publisherPubKey) - } - // check if minPub has changed - if ( - prev.priceAccounts[0].minPub !== newChanges.priceAccounts[0].minPub - ) { - // create update product account instruction - instructions.push( - await pythProgramClient.methods - .setMinPub(newChanges.priceAccounts[0].minPub, [0, 0, 0]) + if (isMessageBufferAvailable(cluster) && messageBufferClient) { + // create delete buffer instruction for the price buffer + instructions.push( + await messageBufferClient.methods + .deleteBuffer( + getPythOracleMessageBufferCpiAuth(cluster), + priceAccount + ) + .accounts({ + admin: fundingAccount, + payer: PRICE_FEED_OPS_KEY, + messageBuffer: getMessageBufferAddressForPrice( + cluster, + priceAccount + ), + }) + .instruction() + ) + } + } else { + // check if metadata has changed + if ( + JSON.stringify(prev.metadata) !== + JSON.stringify(newChanges.metadata) + ) { + const instruction = await pythProgramClient.methods + .updProduct({ symbol, ...newChanges.metadata }) // If there's a symbol in newChanges.metadata, it will overwrite the current symbol .accounts({ - priceAccount: new PublicKey(prev.priceAccounts[0].address), fundingAccount, + productAccount: new PublicKey(prev.address), }) .instruction() - ) + checkSizeOfProductInstruction( + instruction, + MAX_SIZE_UPD_PRODUCT_INSTRUCTION_DATA, + symbol + ) + instructions.push(instruction) + } + + if ( + JSON.stringify(prev.priceAccounts[0].expo) !== + JSON.stringify(newChanges.priceAccounts[0].expo) + ) { + // create update exponent instruction + instructions.push( + await pythProgramClient.methods + .setExponent(newChanges.priceAccounts[0].expo, 1) + .accounts({ + fundingAccount, + priceAccount: new PublicKey(prev.priceAccounts[0].address), + }) + .instruction() + ) + } + + // check if maxLatency has changed + if ( + prev.priceAccounts[0].maxLatency !== + newChanges.priceAccounts[0].maxLatency + ) { + // create update product account instruction + instructions.push( + await pythProgramClient.methods + .setMaxLatency( + newChanges.priceAccounts[0].maxLatency, + [0, 0, 0] + ) + .accounts({ + priceAccount: new PublicKey(prev.priceAccounts[0].address), + fundingAccount, + }) + .instruction() + ) + } + + // check if publishers have changed + const publisherKeysToAdd = + newChanges.priceAccounts[0].publishers.filter( + (newPublisher: string) => + !prev.priceAccounts[0].publishers.includes(newPublisher) + ) + // check if there are any publishers to remove by comparing prev and new + const publisherKeysToRemove = + prev.priceAccounts[0].publishers.filter( + (prevPublisher: string) => + !newChanges.priceAccounts[0].publishers.includes( + prevPublisher + ) + ) + + // add instructions to remove publishers + + for (const publisherKey of publisherKeysToRemove) { + instructions.push( + await pythProgramClient.methods + .delPublisher(new PublicKey(publisherKey)) + .accounts({ + fundingAccount, + priceAccount: new PublicKey(prev.priceAccounts[0].address), + }) + .instruction() + ) + } + + // add instructions to add new publishers + for (const publisherKey of publisherKeysToAdd) { + const publisherPubKey = new PublicKey(publisherKey) + instructions.push( + await pythProgramClient.methods + .addPublisher(publisherPubKey) + .accounts({ + fundingAccount, + priceAccount: new PublicKey(prev.priceAccounts[0].address), + }) + .instruction() + ) + await initPublisherInPriceStore(publisherPubKey) + } + + // check if minPub has changed + if ( + prev.priceAccounts[0].minPub !== + newChanges.priceAccounts[0].minPub + ) { + // create update product account instruction + instructions.push( + await pythProgramClient.methods + .setMinPub(newChanges.priceAccounts[0].minPub, [0, 0, 0]) + .accounts({ + priceAccount: new PublicKey(prev.priceAccounts[0].address), + fundingAccount, + }) + .instruction() + ) + } } } - } - setIsSendProposalButtonLoading(true) - try { + setIsSendProposalButtonLoading(true) const response = await axios.post(proposerServerUrl + '/api/propose', { instructions, cluster, @@ -618,15 +622,17 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { toast.success(`Proposal sent! 🚀 Proposal Pubkey: ${proposalPubkey}`) setIsSendProposalButtonLoading(false) closeModal() - } catch (error: any) { - if (error.response) { - toast.error(capitalizeFirstLetter(error.response.data)) - } else { - toast.error(capitalizeFirstLetter(error.message)) - } - setIsSendProposalButtonLoading(false) } } + + handleSendProposalButtonClickAsync().catch((error) => { + if (error.response) { + toast.error(capitalizeFirstLetter(error.response.data)) + } else { + toast.error(capitalizeFirstLetter(error.message)) + } + setIsSendProposalButtonLoading(false) + }) } const MetadataChangesRows = ({ changes }: { changes: any }) => { From f5760706047a06e23ca9831cb2cd29dc9ce6a112 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Thu, 6 Feb 2025 19:10:28 +0000 Subject: [PATCH 5/6] move loading --- .../packages/xc_admin_frontend/components/tabs/General.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx index 40dba72e43..e94c24ad91 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx +++ b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx @@ -304,6 +304,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { const handleSendProposalButtonClick = async () => { const handleSendProposalButtonClickAsync = async () => { + setIsSendProposalButtonLoading(true) if (pythProgramClient && dataChanges && !isMultisigLoading) { const instructions: TransactionInstruction[] = [] const publisherInPriceStoreInitializationsVerified: PublicKey[] = [] @@ -613,7 +614,6 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { } } - setIsSendProposalButtonLoading(true) const response = await axios.post(proposerServerUrl + '/api/propose', { instructions, cluster, From d66f35fb53f35eb89d7553f118dff7782be7714f Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Wed, 12 Feb 2025 01:41:22 +0000 Subject: [PATCH 6/6] address pr comments --- .../packages/xc_admin_frontend/components/tabs/General.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx index e94c24ad91..5a12ed8aa6 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx +++ b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx @@ -36,6 +36,7 @@ import PermissionDepermissionKey from '../PermissionDepermissionKey' import { PriceRawConfig } from '../../hooks/usePyth' import { Wallet } from '@coral-xyz/anchor/dist/cjs/provider' +// These are the values such that a transaction adding a remote addProduct or updProduct instruction to a proposal are exactly 1232 bytes const MAX_SIZE_ADD_PRODUCT_INSTRUCTION_DATA = 369 const MAX_SIZE_UPD_PRODUCT_INSTRUCTION_DATA = 403 // upd product has one account less @@ -302,7 +303,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => { return isValid } - const handleSendProposalButtonClick = async () => { + const handleSendProposalButtonClick = () => { const handleSendProposalButtonClickAsync = async () => { setIsSendProposalButtonLoading(true) if (pythProgramClient && dataChanges && !isMultisigLoading) {