Skip to content

feat: finalize *tokenless* HubPool CCTP messages #2270

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

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2f9cb20
~complete getCCTPMessageEvents
grasphoper May 24, 2025
1c8a175
fix Log handling: produce *typed* logs
grasphoper May 24, 2025
835db3e
complete implementation
grasphoper May 24, 2025
09727cf
refactor progress
grasphoper May 24, 2025
38fc4d8
handle edge case
grasphoper May 24, 2025
d4cf83c
fix nuanced L2 -> L1 behavior
grasphoper May 24, 2025
1199e1a
add todo comments
grasphoper May 24, 2025
565a571
Merge branch 'master' into if/finalize-cctp-raw-messages2
grasphoper May 27, 2025
9afda58
address todos
grasphoper May 27, 2025
ec02f37
update naming
grasphoper May 27, 2025
5824574
polish logic + update v2 indexing logic
grasphoper May 27, 2025
6b9d64d
address rate-limit concern
grasphoper May 27, 2025
499a34e
fix some testing findings
grasphoper May 28, 2025
aa4808a
Merge branch 'master' into if/finalize-cctp-raw-messages2
grasphoper May 28, 2025
4f9c40b
change cctpVersion according to real API outputs, same with determini…
grasphoper May 28, 2025
8152bd7
match message to attestation by comparing the message itself, not rel…
grasphoper May 28, 2025
e7bc646
cleanup cctpMessageIndex logic
grasphoper May 28, 2025
d75dc89
adjust api <> event comparison function to match reality
grasphoper May 28, 2025
66f1b8e
handle edge case where there Circle returns 0x instead of a message f…
grasphoper May 28, 2025
636604b
remove unused fn
grasphoper May 28, 2025
5b8bda4
address PR comments
grasphoper May 28, 2025
9cc365f
change RetryProvider usage to Provider
grasphoper May 29, 2025
ab04762
change isSourceHubChain from function arg to calculated param
grasphoper May 29, 2025
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
19 changes: 19 additions & 0 deletions src/common/abi/HubPool.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,24 @@
],
"name": "TokensRelayed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "target",
"type": "address"
},
{
"indexed": false,
"internalType": "bytes",
"name": "message",
"type": "bytes"
}
],
"name": "MessageRelayed",
"type": "event"
}
]
36 changes: 24 additions & 12 deletions src/finalizer/utils/cctp/l1ToL2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import {
isEVMSpokePoolClient,
} from "../../../utils";
import {
AttestedCCTPDepositEvent,
AttestedCCTPMessage,
CCTPMessageStatus,
getAttestationsForCCTPDepositEvents,
getAttestedCCTPMessages,
getCctpMessageTransmitter,
isDepositForBurnEvent,
} from "../../../utils/CCTPUtils";
import { FinalizerPromise, CrossChainMessage } from "../../types";

Expand All @@ -36,7 +37,7 @@ export async function cctpL1toL2Finalizer(
to: l1SpokePoolClient.latestHeightSearched,
maxLookBack: l1SpokePoolClient.eventSearchConfig.maxLookBack,
};
const outstandingDeposits = await getAttestationsForCCTPDepositEvents(
const outstandingDeposits = await getAttestedCCTPMessages(
senderAddresses,
hubPoolClient.chainId,
l2SpokePoolClient.chainId,
Expand Down Expand Up @@ -77,7 +78,7 @@ export async function cctpL1toL2Finalizer(
*/
async function generateMultiCallData(
messageTransmitter: Contract,
messages: Pick<AttestedCCTPDepositEvent, "attestation" | "messageBytes">[]
messages: Pick<AttestedCCTPMessage, "attestation" | "messageBytes">[]
): Promise<Multicall2Call[]> {
assert(messages.every(({ attestation }) => isDefined(attestation) && attestation !== "PENDING"));
return Promise.all(
Expand All @@ -102,15 +103,26 @@ async function generateMultiCallData(
* @returns A list of valid withdrawals for a given list of CCTP messages.
*/
async function generateDepositData(
messages: Pick<AttestedCCTPDepositEvent, "amount">[],
messages: AttestedCCTPMessage[],
originationChainId: number,
destinationChainId: number
): Promise<CrossChainMessage[]> {
return messages.map((message) => ({
l1TokenSymbol: "USDC", // Always USDC b/c that's the only token we support on CCTP
amount: convertFromWei(message.amount, TOKEN_SYMBOLS_MAP.USDC.decimals), // Format out to 6 decimal places for USDC
type: "deposit",
originationChainId,
destinationChainId,
}));
return messages.map((message) => {
if (isDepositForBurnEvent(message)) {
return {
l1TokenSymbol: "USDC", // Always USDC b/c that's the only token we support on CCTP
amount: convertFromWei(message.amount, TOKEN_SYMBOLS_MAP.USDC.decimals), // Format out to 6 decimal places for USDC
type: "deposit",
originationChainId,
destinationChainId,
};
} else {
return {
type: "misc",
miscReason: `Finalization of CCTP crosschain message ${message.log.transactionHash} ; log index ${message.log.logIndex}`,
originationChainId,
destinationChainId,
};
}
});
}
10 changes: 5 additions & 5 deletions src/finalizer/utils/cctp/l2ToL1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import {
EventSearchConfig,
} from "../../../utils";
import {
AttestedCCTPDepositEvent,
AttestedCCTPDeposit,
CCTPMessageStatus,
getAttestationsForCCTPDepositEvents,
getAttestedCCTPDeposits,
getCctpMessageTransmitter,
} from "../../../utils/CCTPUtils";
import { FinalizerPromise, CrossChainMessage } from "../../types";
Expand All @@ -34,7 +34,7 @@ export async function cctpL2toL1Finalizer(
to: spokePoolClient.latestHeightSearched,
maxLookBack: spokePoolClient.eventSearchConfig.maxLookBack,
};
const outstandingDeposits = await getAttestationsForCCTPDepositEvents(
const outstandingDeposits = await getAttestedCCTPDeposits(
senderAddresses,
spokePoolClient.chainId,
hubPoolClient.chainId,
Expand Down Expand Up @@ -76,7 +76,7 @@ export async function cctpL2toL1Finalizer(
*/
async function generateMultiCallData(
messageTransmitter: Contract,
messages: Pick<AttestedCCTPDepositEvent, "attestation" | "messageBytes">[]
messages: Pick<AttestedCCTPDeposit, "attestation" | "messageBytes">[]
): Promise<Multicall2Call[]> {
assert(messages.every((message) => isDefined(message.attestation)));
return Promise.all(
Expand All @@ -101,7 +101,7 @@ async function generateMultiCallData(
* @returns A list of valid withdrawals for a given list of CCTP messages.
*/
async function generateWithdrawalData(
messages: Pick<AttestedCCTPDepositEvent, "amount">[],
messages: Pick<AttestedCCTPDeposit, "amount">[],
originationChainId: number,
destinationChainId: number
): Promise<CrossChainMessage[]> {
Expand Down
Loading