Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
}
}),
}
// these fields are immutable and should not be updated
delete symbolToData[product.metadata.symbol].metadata.symbol
// this field is immutable and should not be updated
delete symbolToData[product.metadata.symbol].metadata.price_account
})
setExistingSymbols(new Set(Object.keys(symbolToData)))
Expand Down Expand Up @@ -184,22 +183,50 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
if (!isValidJson(fileData as string)) return
const fileDataParsed = sortData(JSON.parse(fileData as string))
const changes: Record<string, any> = {}

const renamedSymbols: Record<string, string> = {}

// Go through existing symbols and map the product address to the symbol
const productAddressToSymbol: Record<string, string> = {}
Object.keys(data).forEach((symbol) => {
productAddressToSymbol[data[symbol].address] = symbol
})

Object.keys(fileDataParsed).forEach((symbol) => {
// remove duplicate publishers
fileDataParsed[symbol].priceAccounts[0].publishers = [
...new Set(fileDataParsed[symbol].priceAccounts[0].publishers),
]
// Set the symbol in metadata to make sure its consistent with on-chain metadata
// and sort it to make sure comparisons are easier
fileDataParsed[symbol].metadata.symbol = symbol
fileDataParsed[symbol].metadata = sortObjectByKeys(
fileDataParsed[symbol].metadata
)

if (!existingSymbols.has(symbol)) {
// if symbol is not in existing symbols, create new entry
changes[symbol] = { new: {} }
changes[symbol].new = { ...fileDataParsed[symbol] }
changes[symbol].new.metadata = {
...changes[symbol].new.metadata,
symbol,
// if symbol is not in the existing symbols, there are two cases as described below:
// 1. symbol is renamed. in this case, there is an address in
// the symbol data that matches an address in the existing data
// 2. otherwise, symbol is new
if (
fileDataParsed[symbol].address !== undefined &&
productAddressToSymbol[fileDataParsed[symbol].address] !==
undefined
) {
const oldSymbol =
productAddressToSymbol[fileDataParsed[symbol].address]
renamedSymbols[oldSymbol] = symbol
changes[symbol] = { prev: {}, new: {} }
changes[symbol].prev = { ...data[oldSymbol] }
changes[symbol].new = { ...fileDataParsed[symbol] }
} else {
changes[symbol] = { new: {} }
changes[symbol].new = { ...fileDataParsed[symbol] }
// these fields are generated deterministically and should not be updated
delete changes[symbol].new.address
delete changes[symbol].new.priceAccounts[0].address
}
// these fields are generated deterministically and should not be updated
delete changes[symbol].new.address
delete changes[symbol].new.priceAccounts[0].address
} else if (
// if symbol is in existing symbols, check if data is different
JSON.stringify(data[symbol]) !==
Expand All @@ -212,7 +239,10 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
})
// check if any existing symbols are not in uploaded json
Object.keys(data).forEach((symbol) => {
if (!fileDataParsed[symbol]) {
if (
!fileDataParsed[symbol] &&
renamedSymbols[symbol] === undefined
) {
changes[symbol] = { prev: {} }
changes[symbol].prev = { ...data[symbol] }
}
Expand Down Expand Up @@ -291,43 +321,41 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
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 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 (
publisherInPriceStoreInitializationsVerified.every(
(el) => !el.equals(publisherKey)
)
!connection ||
!(await isPriceStorePublisherInitialized(connection, publisherKey))
) {
if (
!connection ||
!(await isPriceStorePublisherInitialized(
connection,
instructions.push(
await createDetermisticPriceStoreInitializePublisherInstruction(
fundingAccount,
publisherKey
))
) {
instructions.push(
await createDetermisticPriceStoreInitializePublisherInstruction(
fundingAccount,
publisherKey
)
)
}
publisherInPriceStoreInitializationsVerified.push(publisherKey)
)
}
publisherInPriceStoreInitializationsVerified.push(publisherKey)
}
}

for (const symbol of Object.keys(dataChanges)) {
const { prev, new: newChanges } = dataChanges[symbol]
// if prev is undefined, it means that the symbol is new
if (!prev) {
Expand Down Expand Up @@ -425,6 +453,25 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
.instruction()
)
}

// If maxLatency is set and is not 0, create update maxLatency instruction
if (
newChanges.priceAccounts[0].maxLatency !== undefined &&
newChanges.priceAccounts[0].maxLatency !== 0
) {
instructions.push(
await pythProgramClient.methods
.setMaxLatency(
newChanges.priceAccounts[0].maxLatency,
[0, 0, 0]
)
.accounts({
priceAccount: priceAccountKey,
fundingAccount,
})
.instruction()
)
}
} else if (!newChanges) {
const priceAccount = new PublicKey(prev.priceAccounts[0].address)

Expand Down Expand Up @@ -481,7 +528,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
// 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
.updProduct(newChanges.metadata)
.accounts({
fundingAccount,
productAccount: new PublicKey(prev.address),
Expand Down
Loading