Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
a50243d
Add CCTP v2 consts
yorhodes Oct 31, 2025
718e33f
Fix build
yorhodes Oct 31, 2025
343f322
Export new versions
yorhodes Oct 31, 2025
5460f69
Merge branch 'main' into deploy-cctp-v2
yorhodes Oct 31, 2025
b250527
Add fast and standard modes
yorhodes Oct 31, 2025
d90eaa9
Fix build
yorhodes Oct 31, 2025
f7551fd
Update owner config
yorhodes Oct 31, 2025
c349dfb
Merge branch 'main' into deploy-cctp-v2
yorhodes Nov 3, 2025
3a179af
Fix checksum
yorhodes Nov 3, 2025
c16fbe0
Fix CCTP v2 constructor args
yorhodes Nov 3, 2025
8b47c30
Merge branch 'main' into deploy-cctp-v2
yorhodes Nov 3, 2025
8868af5
Merge branch 'main' into deploy-cctp-v2
yorhodes Nov 3, 2025
dd9482d
Merge branch 'main' into deploy-cctp-v2
yorhodes Nov 5, 2025
a8252a6
Pipe delay reason through to relayer
yorhodes Nov 5, 2025
89e3515
Merge branch 'main' into deploy-cctp-v2
yorhodes Nov 5, 2025
5ef9e97
Merge branch 'deploy-cctp-v2' into cctp-v2-ccip-server
yorhodes Nov 5, 2025
272d808
Add comment with link to cctp docs
yorhodes Nov 5, 2025
81a4ad6
Improve error log
yorhodes Nov 5, 2025
87515bc
Collect error metric with explicit delay reasons
yorhodes Nov 6, 2025
92872d1
Merge branch 'main' into cctp-v2-ccip-server
yorhodes Nov 6, 2025
283f98e
chore: update agent images (#7343)
yjamin Nov 7, 2025
9f64209
feat: make validator startup more resilient (#7342)
kamiyaa Nov 7, 2025
4f16e56
chore(ci): remove windows agent release artifact (#7347)
paulbalaji Nov 7, 2025
16f83c0
fix: Check if validators is enabled for a chain in set-rpc-urls.ts (#…
ameten Nov 7, 2025
834d67a
fix: Add tests for functions identifying if messages are already subm…
ameten Nov 7, 2025
cafd990
chore: update registryrc (#7353)
paulbalaji Nov 10, 2025
bf43a25
chore: update USDC/superseed to weighted strategy (#7351)
Mo-Hussain Nov 10, 2025
846f442
chore: add TIA token configs (#7041)
christopherbrumm Nov 10, 2025
cf66593
refactor: Refactor decision on operation preparation (#7352)
ameten Nov 10, 2025
8cd18f5
chore: Update Renzo configs to correct owners (#7354)
ltyu Nov 11, 2025
60e96e3
chore: altvm interface additions (#7300)
troykessler Nov 11, 2025
1a19cf6
chore: update rebalancer image (#7355)
Mo-Hussain Nov 11, 2025
e376fc8
docs: update links to jq, foundry (#7348)
letmehateu Nov 11, 2025
c21cf5e
chore: Upgrade Relayer Testnet and Mainnet to latest (#7356)
ameten Nov 11, 2025
3ea3567
test(cli): radix warp e2e tests (#7341)
xeno097 Nov 11, 2025
0918c00
chore: release agents v1.7.0 (#7345)
github-actions[bot] Nov 11, 2025
ced2f72
feat: update PR title to pass PR title lint ci (#7358)
kamiyaa Nov 11, 2025
c44db0e
chore(ci): agent release workflow fixes (#7359)
paulbalaji Nov 11, 2025
d14497e
feat: add additional labels for hyperlane_offchain_lookup_server_unha…
Mo-Hussain Nov 11, 2025
c3c1039
refactor: Remove duplication and move tests into separate files (#7357)
ameten Nov 12, 2025
b90773d
feat: Aleo HyperlaneProvider (#7344)
yjamin Nov 12, 2025
295bf22
fix(sdk): loosen xerc20 deploy config validation (#7367)
paulbalaji Nov 12, 2025
f585030
feat(sdk): add turnkey EVM + SVM signers (#7362)
paulbalaji Nov 12, 2025
2369ff6
fix(sdk): warp read for pre everclear rebalancing deployments (#7370)
xeno097 Nov 12, 2025
d53b6c6
feat(ci): add cargo.lock check (#7371)
paulbalaji Nov 12, 2025
1f91d89
Version Packages (#7332)
github-actions[bot] Nov 13, 2025
d83a998
feat(infra): refactor turnkey usage, setup new roles (#7363)
paulbalaji Nov 13, 2025
2cb74cb
chore: update usdc/superseed rebalancer config to use minAmount strat…
Mo-Hussain Nov 13, 2025
ac6ef10
feat: install libcurl for rust docker (#7376)
kamiyaa Nov 13, 2025
b9d082b
feat(infra): rewrite igp claim script, use turnkey signer (#7364)
paulbalaji Nov 13, 2025
c270c91
feat(infra): use swapOwner instead of removing/adding safe owners (#7…
paulbalaji Nov 13, 2025
fa6c776
fix: Clear link between message and payload for manual reprocessing (…
ameten Nov 14, 2025
ddbb87c
chore: Release Relayer Mainnet and Testnet with latest (#7382)
ameten Nov 14, 2025
cbdf3d1
feat: stop RPC retries for permanent errors (#6919)
antigremlin Nov 14, 2025
d68b5ee
Version Packages (#7383)
github-actions[bot] Nov 14, 2025
1c814d4
Address pr comments
yorhodes Nov 14, 2025
d194a13
Address coderabbit comment
yorhodes Nov 14, 2025
9cbeff6
Address more coderabbit comments
yorhodes Nov 14, 2025
4caa4d0
Merge branch 'main' into cctp-v2-ccip-server
yorhodes Nov 14, 2025
0ec4364
docs(changeset): Improve CCTP offchain lookup server error handling
yorhodes Nov 14, 2025
e57b5b1
Address PR comments
yorhodes Nov 20, 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
6 changes: 6 additions & 0 deletions .changeset/fuzzy-yaks-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@hyperlane-xyz/ccip-server": patch
"@hyperlane-xyz/sdk": patch
---

Improve CCTP offchain lookup server error handling
66 changes: 65 additions & 1 deletion typescript/ccip-server/src/services/CCTPAttestationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@ import {
UnhandledErrorReason,
} from '../utils/prometheus.js';

// https://developers.circle.com/api-reference/cctp/all/get-messages-v-2
type DelayReason =
| 'insufficient_fee'
| 'amount_above_max'
| 'insufficient_allowance_available';
type Status = 'complete' | 'pending_confirmations';

interface CCTPMessageEntry {
attestation: string;
message: string;
eventNonce: string;
// CCTP v2 only
cctpVersion?: string;
status?: Status;
delayReason?: DelayReason;
}

interface CCTPData {
Expand Down Expand Up @@ -170,8 +182,60 @@ class CCTPAttestationService {
throw new Error(`CCTP attestation request failed: ${resp.statusText}`);
}

const json: CCTPData = await resp.json();
let json: CCTPData;
try {
json = await resp.json();
} catch (error) {
logger.error(
{
...context,
status: resp.status,
statusText: resp.statusText,
url,
messageId,
error_reason:
UnhandledErrorReason.CCTP_ATTESTATION_SERVICE_JSON_PARSE_ERROR,
},
'CCTP attestation response parsing failed',
);
throw new Error(`CCTP service response parsing failed: ${error}`);
}
Comment thread
yorhodes marked this conversation as resolved.

json.messages.forEach((message) => {
if (message.attestation === 'PENDING') {
const errorString = 'CCTP attestation is pending';
switch (message.delayReason) {
case 'insufficient_fee':
case 'amount_above_max':
case 'insufficient_allowance_available':
PrometheusMetrics.logUnhandledError(
this.serviceName,
UnhandledErrorReason.CCTP_ATTESTATION_SERVICE_PENDING,
);
logger.error(
{
error_reason:
UnhandledErrorReason.CCTP_ATTESTATION_SERVICE_PENDING,
...message,
...context,
},
errorString + ` due to ${message.delayReason}`,
);
break;
default:
logger.info(
{
...context,
...message,
},
errorString,
);
}
throw new Error(errorString);
Comment thread
yorhodes marked this conversation as resolved.
}
});
Comment thread
yorhodes marked this conversation as resolved.
Comment thread
yorhodes marked this conversation as resolved.
Comment thread
yorhodes marked this conversation as resolved.

// TODO: handle multiple messages in one tx hash
return [json.messages[0].message, json.messages[0].attestation];
Comment thread
yorhodes marked this conversation as resolved.
}
}
Expand Down
2 changes: 2 additions & 0 deletions typescript/ccip-server/src/utils/prometheus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export enum UnhandledErrorReason {
CCTP_UNSUPPORTED_VERSION = 'cctp_unsupported_version',
CCTP_ATTESTATION_SERVICE_500 = 'cctp_attestation_service_500',
CCTP_ATTESTATION_SERVICE_UNKNOWN_ERROR = 'cctp_attestation_service_unknown_error',
CCTP_ATTESTATION_SERVICE_JSON_PARSE_ERROR = 'cctp_attestation_service_json_parse_error',
CCTP_ATTESTATION_SERVICE_PENDING = 'cctp_attestation_service_pending',

// CallCommitments errors
CALL_COMMITMENTS_DATABASE_ERROR = 'call_commitments_database_error',
Expand Down
26 changes: 18 additions & 8 deletions typescript/sdk/src/ism/metadata/ccipread.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { utils } from 'ethers';

import { AbstractCcipReadIsm__factory } from '@hyperlane-xyz/core';
import { WithAddress } from '@hyperlane-xyz/utils';
import { WithAddress, ensure0x } from '@hyperlane-xyz/utils';

import { HyperlaneCore } from '../../core/HyperlaneCore.js';
import { IsmType, OffchainLookupIsmConfig } from '../types.js';
Expand Down Expand Up @@ -58,11 +58,11 @@ export class OffchainLookupMetadataBuilder implements MetadataBuilder {
const url = urlTemplate
.replace('{sender}', sender)
.replace('{data}', callDataHex);

let res: Response;
try {
let responseJson: any;
if (urlTemplate.includes('{data}')) {
const res = await fetch(url);
responseJson = await res.json();
res = await fetch(url);
} else {
const signature = await signer.signMessage(
utils.arrayify(
Expand All @@ -73,20 +73,30 @@ export class OffchainLookupMetadataBuilder implements MetadataBuilder {
),
),
);
const res = await fetch(url, {
res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sender, data: callDataHex, signature }),
});
responseJson = await res.json();
}
const rawHex = responseJson.data as string;
return rawHex.startsWith('0x') ? rawHex : `0x${rawHex}`;
} catch (error: any) {
this.core.logger.warn(
`CCIP-read metadata fetch failed for ${url}: ${error}`,
);
// try next URL
continue;
}

try {
const responseJson = await res.json();
if (res.ok) {
return ensure0x(responseJson.data);
}
} catch (error) {
this.core.logger.warn(
`CCIP-read metadata fetch failed for ${url}: ${error}`,
);
// try next URL
}
}

Expand Down
Loading