Skip to content
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@across-protocol/sdk",
"author": "UMA Team",
"version": "4.3.32",
"version": "4.3.33",
"license": "AGPL-3.0",
"homepage": "https://docs.across.to/reference/sdk",
"files": [
Expand Down
41 changes: 32 additions & 9 deletions src/arch/svm/SpokeUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MessageTransmitterClient, SvmSpokeClient, TokenMessengerMinterClient } from "@across-protocol/contracts";
import { decodeFillStatusAccount, fetchState } from "@across-protocol/contracts/dist/src/svm/clients/SvmSpoke";
import { decodeMessageHeader, hashNonEmptyMessage } from "@across-protocol/contracts/dist/src/svm/web3-v1";
import { decodeMessageHeader } from "@across-protocol/contracts/dist/src/svm/web3-v1";
import { intToU8Array32 } from "@across-protocol/contracts/dist/src/svm/web3-v1/conversionUtils";
import { SYSTEM_PROGRAM_ADDRESS } from "@solana-program/system";
import {
Expand Down Expand Up @@ -47,6 +47,7 @@ import {
chainIsProd,
chainIsSvm,
chunk,
getMessageHash,
delay,
isUnsafeDepositId,
keccak256,
Expand Down Expand Up @@ -257,19 +258,21 @@ export async function findDeposit(
* @param provider - SVM provider instance.
* @param svmEventsClient - SVM events client for querying events.
* @param atHeight - (Optional) Specific slot number to query. Defaults to the latest confirmed slot.
* @param messageHash - (Optional) Hash of the message that will be used to create relayDataHash from fill.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be OK to drop this one now 👍

Suggested change
* @param messageHash - (Optional) Hash of the message that will be used to create relayDataHash from fill.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* @returns The fill status for the deposit at the specified or current slot.
*/
export async function relayFillStatus(
programId: Address,
relayData: RelayData,
destinationChainId: number,
svmEventsClient: SvmCpiEventsClient,
atHeight?: number
atHeight?: number,
messageHash?: string
): Promise<FillStatus> {
assert(chainIsSvm(destinationChainId), "Destination chain must be an SVM chain");
const provider = svmEventsClient.getRpc();
// Get fill status PDA using relayData
const fillStatusPda = await getFillStatusPda(programId, relayData, destinationChainId);
const fillStatusPda = await getFillStatusPda(programId, relayData, destinationChainId, messageHash);
let toSlot = BigInt(atHeight ?? 0);

// If no specific slot is requested, try fetching the current status from the PDA
Expand Down Expand Up @@ -475,7 +478,12 @@ export async function fillRelayInstruction(
`Invalid repayment address for chain ${repaymentChainId}: ${repaymentAddress.toNative()}.`
);

const _relayDataHash = getRelayDataHash(relayData, relayData.destinationChainId);
const relayDataWithMessageHash = {
...relayData,
messageHash: getMessageHash(relayData.message),
};

const _relayDataHash = getRelayDataHash(relayDataWithMessageHash, relayData.destinationChainId);
const relayDataHash = new Uint8Array(Buffer.from(_relayDataHash.slice(2), "hex"));

const relayer = SvmAddress.from(signer.address);
Expand Down Expand Up @@ -583,7 +591,13 @@ export async function getFillRelayTx(
);

const program = toAddress(spokePoolAddr);
const _relayDataHash = getRelayDataHash(relayData, destinationChainId);

const relayDataWithMessageHash = {
...relayData,
messageHash: getMessageHash(relayData.message),
};

const _relayDataHash = getRelayDataHash(relayDataWithMessageHash, destinationChainId);
const relayDataHash = new Uint8Array(Buffer.from(_relayDataHash.slice(2), "hex"));

const [state, delegate] = await Promise.all([
Expand Down Expand Up @@ -792,7 +806,13 @@ export async function getSlowFillRequestTx(
} = relayData;

const program = toAddress(spokePoolAddr);
const relayDataHash = getRelayDataHash(relayData, destinationChainId);

const relayDataWithMessageHash = {
...relayData,
messageHash: getMessageHash(relayData.message),
};

const relayDataHash = getRelayDataHash(relayDataWithMessageHash, destinationChainId);

const [state, fillStatus, eventAuthority] = await Promise.all([
getStatePda(program),
Expand Down Expand Up @@ -881,12 +901,15 @@ export async function getAssociatedTokenAddress(
return associatedToken;
}

export function getRelayDataHash(relayData: RelayData, destinationChainId: number): string {
export function getRelayDataHash(
relayData: Omit<RelayData, "message"> & { messageHash: string },
destinationChainId: number
): string {
const addressEncoder = getAddressEncoder();
const uint64Encoder = getU64Encoder();
const uint32Encoder = getU32Encoder();

assert(relayData.message.startsWith("0x"), "Message must be a hex string");
assert(relayData.messageHash.startsWith("0x"), "Message hash must be a hex string");
const encodeAddress = (data: SdkAddress) => Uint8Array.from(addressEncoder.encode(toAddress(data)));

const contentToHash = Buffer.concat([
Expand All @@ -901,7 +924,7 @@ export function getRelayDataHash(relayData: RelayData, destinationChainId: numbe
arrayify(hexZeroPad(hexlify(relayData.depositId), 32)),
Uint8Array.from(uint32Encoder.encode(relayData.fillDeadline)),
Uint8Array.from(uint32Encoder.encode(relayData.exclusivityDeadline)),
hashNonEmptyMessage(Buffer.from(arrayify(relayData.message))),
Uint8Array.from(Buffer.from(relayData.messageHash.slice(2), "hex")),
Uint8Array.from(uint64Encoder.encode(BigInt(destinationChainId))),
]);
return keccak256(contentToHash);
Expand Down
6 changes: 4 additions & 2 deletions src/arch/svm/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,16 @@ export async function getStatePda(programId: Address): Promise<Address> {
* @param programId The SpokePool program ID.
* @param relayData The relay data to get the fill status PDA for.
* @param destinationChainId The destination chain ID.
* @param messageHash Hash of the message that will be used to create relayDataHash from fill.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Suggested change
* @param messageHash Hash of the message that will be used to create relayDataHash from fill.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* @returns The PDA for the fill status.
*/
export async function getFillStatusPda(
programId: Address,
relayData: RelayData,
destinationChainId: number
destinationChainId: number,
messageHash?: string
): Promise<Address> {
const relayDataHash = getRelayDataHash(relayData, destinationChainId);
const relayDataHash = getRelayDataHash(relayData, destinationChainId, messageHash);
const uint8RelayDataHash = new Uint8Array(Buffer.from(relayDataHash.slice(2), "hex"));
const [fillStatusPda] = await getProgramDerivedAddress({
programAddress: programId,
Expand Down
4 changes: 2 additions & 2 deletions src/clients/SpokePoolClient/SVMSpokePoolClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ export class SVMSpokePoolClient extends SpokePoolClient {
/**
* Retrieves the fill status for a given relay data from the SVM chain.
*/
public override relayFillStatus(relayData: RelayData, atHeight?: number): Promise<FillStatus> {
return relayFillStatus(this.programId, relayData, this.chainId, this.svmEventsClient, atHeight);
public override relayFillStatus(relayData: RelayData, atHeight?: number, messageHash?: string): Promise<FillStatus> {
return relayFillStatus(this.programId, relayData, this.chainId, this.svmEventsClient, atHeight, messageHash);
}

/**
Expand Down
9 changes: 7 additions & 2 deletions src/utils/SpokeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ export function getSlowFillLeafLpFeePct(leaf: SlowFillLeaf): BigNumber {
* Compute the RelayData hash for a fill. This can be used to determine the fill status.
* @param relayData RelayData information that is used to complete a fill.
* @param destinationChainId Supplementary destination chain ID required by V3 hashes.
* @param messageHash Hash of the message that will be used to create relayDataHash from fill.
* @returns The corresponding RelayData hash.
*/
export function getRelayDataHash(relayData: RelayData, destinationChainId: number): string {
export function getRelayDataHash(relayData: RelayData, destinationChainId: number, messageHash?: string): string {
const abi = [
{
type: "tuple",
Expand Down Expand Up @@ -52,7 +53,11 @@ export function getRelayDataHash(relayData: RelayData, destinationChainId: numbe
exclusiveRelayer: relayData.exclusiveRelayer.toBytes32(),
};
if (chainIsSvm(destinationChainId)) {
return svm.getRelayDataHash(relayData, destinationChainId);
const relayDataWithMessageHash = {
...relayData,
messageHash: messageHash ?? getMessageHash(relayData.message),
};
return svm.getRelayDataHash(relayDataWithMessageHash, destinationChainId);
}
return keccak256(encodeAbiParameters(abi, [_relayData, destinationChainId]));
}
Expand Down