-
Notifications
You must be signed in to change notification settings - Fork 18
feat(svmSpokeUtils): svm relayFillStatus implementation #984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(svmSpokeUtils): svm relayFillStatus implementation #984
Conversation
… instead of fill type
// TODO: modify this to use svmEventsClient once we can instantiate it with dynamic addresses. | ||
const fillPdaSignatures = await provider | ||
.getSignaturesForAddress(fillStatusPda, { | ||
limit: 1000, | ||
commitment: "confirmed", | ||
}) | ||
.send(); | ||
|
||
const eventsWithSlots = await Promise.all( | ||
fillPdaSignatures.map(async (signatureTransaction) => { | ||
const events = await svmEventsClient.readEventsFromSignature(signatureTransaction.signature); | ||
return events.map((event) => ({ | ||
...event, | ||
confirmationStatus: signatureTransaction.confirmationStatus, | ||
blockTime: signatureTransaction.blockTime, | ||
signature: signatureTransaction.signature, | ||
slot: signatureTransaction.slot, | ||
})); | ||
}) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copied this from the SvmSpokeEventsClient
but it is temporary and doesn't cover the case where a pda has +1000 events (which should be rare though). I aim to replace it once this PR goes in and we can use the events client for other addresses besides the spoke pool: #982
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the likelihood we will be using 1000+ signatures of lookback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. We'd expect these pdas to have only a few events, I'll set a lower value.
@@ -175,7 +175,7 @@ export class SvmSpokeEventsClient { | |||
* @param txResult - The transaction result. | |||
* @returns A promise that resolves to an array of events with their data and name. | |||
*/ | |||
private processEventFromTx( | |||
public processEventFromTx( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes are also temporary and might not be needed with the new version of the svm events client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
// TODO: modify this to use svmEventsClient once we can instantiate it with dynamic addresses. | ||
const fillPdaSignatures = await provider | ||
.getSignaturesForAddress(fillStatusPda, { | ||
limit: 1000, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OOC should we allow the user to pass this value? It's possible for small ranges (like in the indexer) we want to pass a smaller value for faster read times
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add it as an optional param and I'll also set the default to a lower value since we'd expect these pdas to have only a few events. Good call.
// TODO: modify this to use svmEventsClient once we can instantiate it with dynamic addresses. | ||
const fillPdaSignatures = await provider | ||
.getSignaturesForAddress(fillStatusPda, { | ||
limit: 1000, | ||
commitment: "confirmed", | ||
}) | ||
.send(); | ||
|
||
const eventsWithSlots = await Promise.all( | ||
fillPdaSignatures.map(async (signatureTransaction) => { | ||
const events = await svmEventsClient.readEventsFromSignature(signatureTransaction.signature); | ||
return events.map((event) => ({ | ||
...event, | ||
confirmationStatus: signatureTransaction.confirmationStatus, | ||
blockTime: signatureTransaction.blockTime, | ||
signature: signatureTransaction.signature, | ||
slot: signatureTransaction.slot, | ||
})); | ||
}) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the likelihood we will be using 1000+ signatures of lookback?
export async function relayFillStatus( | ||
programId: Address, | ||
relayData: RelayData, | ||
blockTag: number | "latest", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: is latest the correct term in our case? We'd probably be looking for the most recently "processed" or "confirmed" block
// At this point we have only fill and requested slow fill events and since it's not possible to submit | ||
// a slow fill request once a fill has been submitted, we can use the last event in the sorted list to | ||
// determine the fill status at the requested block. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have corresponding tests for this?
@@ -175,7 +175,7 @@ export class SvmSpokeEventsClient { | |||
* @param txResult - The transaction result. | |||
* @returns A promise that resolves to an array of events with their data and name. | |||
*/ | |||
private processEventFromTx( | |||
public processEventFromTx( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
export async function getFillStatusPda( | ||
programId: Address, | ||
relayData: RelayData, | ||
destinationChainId: number | ||
): Promise<Address> { | ||
const relayDataHash = getRelayDataHash(relayData, destinationChainId); | ||
const uint8RelayDataHash = new Uint8Array(Buffer.from(relayDataHash.slice(2), "hex")); | ||
const [fillStatusPda] = await getProgramDerivedAddress({ | ||
programAddress: programId, | ||
seeds: ["fills", uint8RelayDataHash], | ||
}); | ||
return fillStatusPda; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OOC is there a way we can use the function you created to derive the address? I.e. could this just be a wrapper over getStatePda
with the specified address/extraSeed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getStatePda
and getFillStatusPda
use different labels which is the first item in the 'seeds' array. We could have a function wrapping getProgramDerivedAddress
that takes the seeds but I don't think there's much value on it.
@@ -71,6 +75,46 @@ export function getRelayHashFromEvent(e: RelayData & { destinationChainId: numbe | |||
return getRelayDataHash(e, e.destinationChainId); | |||
} | |||
|
|||
function _getRelayDataHashSvm(relayData: RelayData, destinationChainId: number): string { | |||
const uint8ArrayFromHexString = (hex: string, littleEndian: boolean = false): Uint8Array => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OOC - the endianness of the data feels very low level for TS. How often will endianness be a consideration and an we abstract this away from the caller?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to set the endianness to replicate the relay hash calculation doing in the Solana program itself but it is already abstracted from the caller. I mean, these helper functions are intended to be used exclusively within _getRelayDataHashSvm
so the caller has to provide only the relayData.
Closing this in favor of #990 |
This PR introduces the SVM implementation for relayFillStatus, which reconstructs the fill status of a given relay based on historical events up to a specific block.
The steps to reconstruct fill status are:
NOTE: This is still a draft since the event fetching logic will change to use the new version of the svm events client from this pr: #982