From fffd4a12d70745df22df5dd9975c69f50117f773 Mon Sep 17 00:00:00 2001 From: Paul Noel Date: Mon, 8 Apr 2024 17:17:38 -0500 Subject: [PATCH] watcher: add mainnet NTT networks --- common/src/consts.ts | 5 ++- watcher/src/NTTConsts.ts | 57 +++++++++++++++++++++--------- watcher/src/watchers/NTTWatcher.ts | 37 +++++++++++++------ watcher/src/watchers/utils.ts | 18 ++++++++-- 4 files changed, 86 insertions(+), 31 deletions(-) diff --git a/common/src/consts.ts b/common/src/consts.ts index e310be47..9aec4f32 100644 --- a/common/src/consts.ts +++ b/common/src/consts.ts @@ -69,7 +69,10 @@ export const INITIAL_DEPLOYMENT_BLOCK_BY_NETWORK_AND_CHAIN: { export const INITIAL_NTT_DEPLOYMENT_BLOCK_BY_NETWORK_AND_CHAIN: { [key in Network]: { [key in Chain]?: string }; } = { - ['Mainnet']: {}, + ['Mainnet']: { + Ethereum: '19583505', + Fantom: '78727372', + }, ['Testnet']: { Solana: '285100152', Sepolia: '5472203', diff --git a/watcher/src/NTTConsts.ts b/watcher/src/NTTConsts.ts index f96eb21f..0d4d101f 100644 --- a/watcher/src/NTTConsts.ts +++ b/watcher/src/NTTConsts.ts @@ -24,13 +24,13 @@ export const OutboundTransferQueuedTopic = /// @notice Emitted when an outbound transfer is rate limited. /// @dev Topic0 -/// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. +/// 0xf33512b84e24a49905c26c6991942fc5a9652411769fc1e448f967cdb049f08a. /// @param sender The initial sender of the transfer. /// @param amount The amount to be transferred. /// @param currentCapacity The capacity left for transfers within the 24-hour window.:w -/// event OutboundTransferRateLimited( address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity); +/// OutboundTransferRateLimited(address,uint64,uint256,uint256) export const OutboundTransferRateLimitedTopic = - '0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b'; + '0xf33512b84e24a49905c26c6991942fc5a9652411769fc1e448f967cdb049f08a'; // // The following are from INttManagerEvents.sol @@ -38,25 +38,27 @@ export const OutboundTransferRateLimitedTopic = /// @notice Emitted when a message is sent from the nttManager. /// @dev Topic0 -/// 0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf +/// 0x9cc8ade41ef46b98ba8bcad8c6bfa643934e6b84d3ce066cd38b5f0813bb2ae5. /// @param recipient The recipient of the message. +/// @param refundAddress The address on the destination chain to which the +/// refund of unused gas will be paid /// @param amount The amount transferred. /// @param fee The amount of ether sent along with the tx to cover the delivery fee. /// @param recipientChain The chain ID of the recipient. /// @param msgSequence The unique sequence ID of the message. -/// event TransferSent( bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence); export const TransferSentTopic = - '0x9716fe52fe4e02cf924ae28f19f5748ef59877c6496041b986fbad3dae6a8ecf'; + '0xe54e51e42099622516fa3b48e9733581c9dbdcb771cafb093f745a0532a35982'; /// @notice Emitted when the peer contract is updated. /// @dev Topic0 -/// 0x51b8437a7e22240c473f4cbdb4ed3a4f4bf5a9e7b3c511d7cfe0197325735700. +/// 0x1456404e7f41f35c3daac941bb50bad417a66275c3040061b4287d787719599d. /// @param chainId_ The chain ID of the peer contract. /// @param oldPeerContract The old peer contract address. +/// @param oldPeerDecimals The old peer contract decimals. /// @param peerContract The new peer contract address. -/// event PeerUpdated(uint16 indexed chainId_, bytes32 oldPeerContract, bytes32 peerContract); +/// @param peerDecimals The new peer contract decimals. export const PeerUpdatedTopic = - '0x51b8437a7e22240c473f4cbdb4ed3a4f4bf5a9e7b3c511d7cfe0197325735700'; + '0x1456404e7f41f35c3daac941bb50bad417a66275c3040061b4287d787719599d'; /// @notice Emitted when a message has been attested to. /// @dev Topic0 @@ -79,22 +81,22 @@ export const ThresholdChangedTopic = /// @notice Emitted when an transceiver is removed from the nttManager. /// @dev Topic0 -/// 0xc6289e62021fd0421276d06677862d6b328d9764cdd4490ca5ac78b173f25883. +/// 0xf05962b5774c658e85ed80c91a75af9d66d2af2253dda480f90bce78aff5eda5. /// @param transceiver The address of the transceiver. /// @param transceiversNum The current number of transceivers. /// @param threshold The current threshold of transceivers. -/// event TransceiverAdded(address transceiver, uint256 transceiversNum, uint8 threshold); +/// Event | TransceiverAdded(address,uint256,uint8) | 0xf05962b5774c658e85ed80c91a75af9d66d2af2253dda480f90bce78aff5eda5 export const TransceiverAddedTopic = - '0xc6289e62021fd0421276d06677862d6b328d9764cdd4490ca5ac78b173f25883'; + '0xf05962b5774c658e85ed80c91a75af9d66d2af2253dda480f90bce78aff5eda5'; /// @notice Emitted when an transceiver is removed from the nttManager. /// @dev Topic0 -/// 0x638e631f34d9501a3ff0295873b29f50d0207b5400bf0e48b9b34719e6b1a39e. +/// 0x697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f. /// @param transceiver The address of the transceiver. /// @param threshold The current threshold of transceivers. -/// event TransceiverRemoved(address transceiver, uint8 threshold); +/// Event | TransceiverRemoved(address,uint8) | 0x697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f export const TransceiverRemovedTopic = - '0x638e631f34d9501a3ff0295873b29f50d0207b5400bf0e48b9b34719e6b1a39e'; + '0x697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f'; /// @notice Emitted when a message has already been executed to /// notify client of against retries. @@ -116,6 +118,16 @@ export const MessageAlreadyExecutedTopic = export const TransferRedeemedTopic = '0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91'; +/// @notice Emitted when an outbound transfer has been cancelled +/// @dev Topic0 +/// 0xf80e572ae1b63e2449629b6c7d783add85c36473926f216077f17ee002bcfd07. +/// @param sequence The sequence number being cancelled +/// @param recipient The canceller and recipient of the funds +/// @param amount The amount of the transfer being cancelled +// event OutboundTransferCancelled(uint256 sequence, address recipient, uint256 amount); +export const OutboundTransferCancelledTopic = + '0xf80e572ae1b63e2449629b6c7d783add85c36473926f216077f17ee002bcfd07'; + // All topics: export const NTT_TOPICS = [ InboundTransferQueuedTopic, @@ -129,6 +141,16 @@ export const NTT_TOPICS = [ TransceiverRemovedTopic, MessageAlreadyExecutedTopic, TransferRedeemedTopic, + OutboundTransferCancelledTopic, +]; + +// Lifecycle topics: +export const NTT_LIFECYCLE_TOPICS = [ + InboundTransferQueuedTopic, + OutboundTransferQueuedTopic, + OutboundTransferRateLimitedTopic, + TransferSentTopic, + TransferRedeemedTopic, ]; export const TransferLockIx = 'transferLock'; @@ -156,7 +178,10 @@ export const NTT_SOLANA_IXS = [ export const NTT_CONTRACT: { [key in Network]: { [key in Chain]?: string[] } } = { ['Mainnet']: { Ethereum: ['0xeBdCe9a913d9400EE75ef31Ce8bd34462D01a1c1'], - Fantom: ['0x68dB2f05Aa2d77DEf981fd2be32661340c9222FB'], + Fantom: [ + '0x68dB2f05Aa2d77DEf981fd2be32661340c9222FB', + '0x2F733095B80A04b38b0D10cC884524a3d09b836a', + ], }, ['Testnet']: { Solana: ['nTTh3bZ5Aer6xboWZe39RDEft4MeVxSQ8D1EYAVLZw9'], diff --git a/watcher/src/watchers/NTTWatcher.ts b/watcher/src/watchers/NTTWatcher.ts index 52cff374..1202eae9 100644 --- a/watcher/src/watchers/NTTWatcher.ts +++ b/watcher/src/watchers/NTTWatcher.ts @@ -17,7 +17,7 @@ import { LifeCycle, NTT_CONTRACT, NTT_DECIMALS, - NTT_TOPICS, + NTT_LIFECYCLE_TOPICS, OutboundTransferQueuedTopic, OutboundTransferRateLimitedTopic, TransferRedeemedTopic, @@ -253,7 +253,7 @@ export class NTTWatcher extends Watcher { for (const nttAddress of nttAddresses) { // Get and filter logs const logs: Log[] = (await this.getLogs(fromBlock, toBlock, nttAddress, [])).filter( - isNTTEvent + isNttLifecycleEvent ); const timestampsByBlock: { [block: number]: string } = {}; // fetch timestamps for each block @@ -265,7 +265,7 @@ export class NTTWatcher extends Watcher { } this.logger.info(`processing ${logs.length} logs`); for (const log of logs) { - this.logger.debug('log:', log); + this.logger.debug(`log topic: ${log.topics[0]}`); const blockNumber = log.blockNumber; const txhash = log.transactionHash; this.logger.debug(`blockNumber: ${blockNumber}, txhash: ${txhash}`); @@ -411,6 +411,8 @@ export class NTTWatcher extends Watcher { lc.digest = digest; lc.outboundTransferReleasableTime = timestampsByBlock[blockNumber]; await saveToPG(this.pg, lc, OutboundTransferRateLimitedTopic, this.logger); + } else { + this.logger.warn(`Unhandled log topic: ${log.topics[0]}`); } } @@ -426,6 +428,7 @@ export class NTTWatcher extends Watcher { type decodedTransferSent = { recipient: string; + refundAddr: string; amount: string; fee: string; recipientChain: number; @@ -434,24 +437,36 @@ type decodedTransferSent = { /// event TransferSent( bytes32 recipient, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence); function decodeNttTransferSent(data: string): decodedTransferSent { - // There are 5 fields in this message. Each is 32 bytes long (64 characters) + // event TransferSent( + // bytes32 recipient, + // bytes32 refundAddress, + // uint256 amount, + // uint256 fee, + // uint16 recipientChain, + // uint64 msgSequence + // ); + // There are 6 fields in this message. All of them are 32 bytes (64 characters in hex) // If data starts with '0x', we need to remove it if (data.startsWith('0x')) { data = data.slice(2); } let retVal: decodedTransferSent = { recipient: '', + refundAddr: '', amount: '', fee: '', recipientChain: 0, msgSequence: 0, }; - if (data.length === 320) { + if (data.length === 384) { retVal.recipient = data.slice(0, 64); - retVal.amount = '0x' + data.slice(64, 128); - retVal.fee = '0x' + data.slice(128, 192); - retVal.recipientChain = Number('0x' + data.slice(192, 256)); - retVal.msgSequence = Number('0x' + data.slice(256, 320)); + retVal.refundAddr = '0x' + data.slice(64, 128); + retVal.amount = '0x' + data.slice(128, 192); + retVal.fee = '0x' + data.slice(192, 256); + retVal.recipientChain = Number('0x' + data.slice(256, 320)); + retVal.msgSequence = Number('0x' + data.slice(320, 384)); + } else { + throw new Error('Invalid data length. Expected 384 characters. Got ' + data.length); } return retVal; } @@ -469,8 +484,8 @@ function makeNttTransferKey(mgrAddress: string, recipient: string, seq: number): export const makeVaaId = (chainId: number, emitter: string, seq: number): string => `${chainId}/${emitter}/${seq}`; -function isNTTEvent(log: Log): boolean { - return NTT_TOPICS.some((topic) => log.topics[0].includes(topic)); +function isNttLifecycleEvent(log: Log): boolean { + return NTT_LIFECYCLE_TOPICS.some((topic) => log.topics[0].includes(topic)); } async function saveToPG(pg: Knex, lc: LifeCycle, initiatingEvent: string, logger: WormholeLogger) { diff --git a/watcher/src/watchers/utils.ts b/watcher/src/watchers/utils.ts index 5bb1a2a5..dd04c091 100644 --- a/watcher/src/watchers/utils.ts +++ b/watcher/src/watchers/utils.ts @@ -81,7 +81,17 @@ export function makeFinalizedWatcher(network: Network, chainName: Chain): Watche } export function makeFinalizedNTTWatcher(network: Network, chainName: Chain): Watcher { - if (network === 'Testnet') { + if (network === 'Mainnet') { + if (chainName === 'Ethereum') { + return new NTTWatcher(network, chainName, 'finalized'); + } else if (chainName === 'Fantom') { + return new NTTWatcher(network, chainName); + } else { + throw new Error( + `Attempted to create finalized NTT watcher for unsupported mainnet chain ${chainName}` + ); + } + } else if ('Testnet') { // These are testnet only chains if (chainName === 'Sepolia' || chainName === 'Holesky') { return new NTTWatcher(network, chainName, 'finalized'); @@ -93,10 +103,12 @@ export function makeFinalizedNTTWatcher(network: Network, chainName: Chain): Wat return new NTTSolanaWatcher(network); } else { throw new Error( - `Attempted to create finalized watcher for unsupported testnet chain ${chainName}` + `Attempted to create finalized NTT watcher for unsupported testnet chain ${chainName}` ); } } else { - throw new Error(`Attempted to create finalized watcher for unsupported chain ${chainName}`); + throw new Error( + `Attempted to create finalized NTT watcher for unsupported network ${network}, ${chainName}` + ); } }