Skip to content

Commit 52b6c55

Browse files
authored
Merge pull request #589 from everclearorg/feat/monitor-message-status-prod
feat: check polymer message statuses in monitor
2 parents 6f04d4a + babd6a4 commit 52b6c55

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

packages/agents/monitor/src/helpers/hyperlane.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ import {
55
createLoggingContext,
66
HyperlaneMessageResponse,
77
HyperlaneStatus,
8+
isPolymerRoute,
89
jsonifyError,
910
Message,
1011
RequestContext,
1112
SOLANA_CHAINID,
1213
} from '@chimera-monorepo/utils';
1314
import { NoDispatchEventOnMessage, NoGatewayConfigured } from '../types';
1415
import { getContext } from '../context';
15-
import { getHyperlaneMessageStatus, getHyperlaneMsgDelivered, getMailboxInterface } from '../mockable';
16+
import {
17+
getHyperlaneMessageStatus,
18+
getHyperlaneMsgDelivered,
19+
getMailboxInterface,
20+
getPolymerMsgDelivered,
21+
} from '../mockable';
1622
import { WriteTransaction } from '@chimera-monorepo/chainservice';
1723

1824
export const getMessageStatus = async (
@@ -46,6 +52,25 @@ export const getMessageStatus = async (
4652
return { status: 'none' };
4753
}
4854

55+
// For Polymer-routed messages, query the Polymer relayer API instead of on-chain mailbox
56+
if (
57+
message.originDomain &&
58+
message.destinationDomain &&
59+
isPolymerRoute(message.originDomain, message.destinationDomain)
60+
) {
61+
try {
62+
const status = await getPolymerMsgDelivered(id);
63+
return { status };
64+
} catch (e) {
65+
logger.error('Failed to get Polymer message status', requestContext, methodContext, jsonifyError(e as Error), {
66+
id,
67+
originDomain: message.originDomain,
68+
destinationDomain: message.destinationDomain,
69+
});
70+
return { status: 'pending' };
71+
}
72+
}
73+
4974
// If the message is pending, check to see if it has been delivered onchain.
5075
// NOTE: graphql api returns `pending` if the message has been self-relayed.
5176
// Get the mailbox from the destination gateway contract and query directly.

packages/agents/monitor/src/mockable.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
getTokenPriceFromUniV3 as _getTokenPriceFromUniV3,
1010
getHyperlaneMessageStatus as _getHyperlaneMessageStatus,
1111
getHyperlaneMsgDelivered as _getHyperlaneMsgDelivered,
12+
getPolymerMsgDelivered as _getPolymerMsgDelivered,
1213
sendAlerts as _sendAlerts,
1314
resolveAlerts as _resolveAlerts,
1415
getSsmParameter as _getSsmParameter,
@@ -68,6 +69,7 @@ export const getTokenPriceFromChainlink = _getTokenPriceFromChainlink;
6869
export const getTokenPriceFromUniV2 = _getTokenPriceFromUniV2;
6970
export const getTokenPriceFromUniV3 = _getTokenPriceFromUniV3;
7071
export const getHyperlaneMsgDelivered = _getHyperlaneMsgDelivered;
72+
export const getPolymerMsgDelivered = _getPolymerMsgDelivered;
7173
export const sendAlerts = _sendAlerts;
7274
export const resolveAlerts = _resolveAlerts;
7375
export const getSsmParameter = _getSsmParameter;

packages/agents/monitor/test/helpers/hyperlane.spec.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { SinonStub, SinonStubbedInstance, stub } from 'sinon';
2-
import { expect, HyperlaneMessageResponse, HyperlaneStatus, Message, mkHash, chainWrapper } from '@chimera-monorepo/utils';
2+
import { expect, HyperlaneMessageResponse, HyperlaneStatus, Message, mkHash, chainWrapper, POLYMER_DOMAIN_PAIRS } from '@chimera-monorepo/utils';
33
import * as Mockable from '../../src/mockable';
44

55
import { getDispatchedMessage, getDispatchedMessageFromEvent, getMessageStatus } from '../../src/helpers';
@@ -138,6 +138,28 @@ describe('Helpers:hyperlane', () => {
138138
});
139139
});
140140

141+
it('should return delivered for polymer route when polymer API confirms delivery', async () => {
142+
const [polymerOrigin, polymerDest] = POLYMER_DOMAIN_PAIRS[0]; // e.g. ['1', '25327']
143+
database.getMessagesByIds.resolves([mock.message({ originDomain: polymerOrigin, destinationDomain: polymerDest })]);
144+
const getPolymerMsgDeliveredStub = stub(Mockable, 'getPolymerMsgDelivered').resolves(HyperlaneStatus.delivered);
145+
expect(await getMessageStatus(id)).to.be.deep.eq({ status: 'delivered' });
146+
expect(getPolymerMsgDeliveredStub.calledOnceWith(id)).to.be.true;
147+
});
148+
149+
it('should return pending for polymer route when polymer API returns pending', async () => {
150+
const [polymerOrigin, polymerDest] = POLYMER_DOMAIN_PAIRS[0];
151+
database.getMessagesByIds.resolves([mock.message({ originDomain: polymerOrigin, destinationDomain: polymerDest })]);
152+
stub(Mockable, 'getPolymerMsgDelivered').resolves(HyperlaneStatus.pending);
153+
expect(await getMessageStatus(id)).to.be.deep.eq({ status: 'pending' });
154+
});
155+
156+
it('should return pending for polymer route when polymer API throws', async () => {
157+
const [polymerOrigin, polymerDest] = POLYMER_DOMAIN_PAIRS[0];
158+
database.getMessagesByIds.resolves([mock.message({ originDomain: polymerOrigin, destinationDomain: polymerDest })]);
159+
stub(Mockable, 'getPolymerMsgDelivered').rejects(new Error('Polymer API error'));
160+
expect(await getMessageStatus(id)).to.be.deep.eq({ status: 'pending' });
161+
});
162+
141163
it('should work if hyperlane api fails (derives from chain)', async () => {
142164
getHyperlaneMessageStatusStub.resolves(undefined);
143165
database.getMessagesByIds.resolves([mock.message()]);

0 commit comments

Comments
 (0)