wormhole-explorer/blockchain-watcher/src/infrastructure/mappers/evm/evmRedeemedTransactionFound...

122 lines
3.6 KiB
TypeScript

import { EvmTransaction, TransactionFound, TransactionFoundEvent } from "../../../domain/entities";
import { methodNameByAddressMapper } from "./methodNameByAddressMapper";
import * as configData from "./contractsMapper.json";
import winston from "../../log";
const TX_STATUS_CONFIRMED = "0x1";
const TX_STATUS_FAILED = "0x0";
const TOKEN_BRIDGE_TOPIC = "0xcaf280c8cfeba144da67230d9b009c8f868a75bac9a528fa0474be1ba317c169";
const CCTP_TOPIC = "0xf02867db6908ee5f81fd178573ae9385837f0a0a72553f8c08306759a7e0f00e";
let logger: winston.Logger;
logger = winston.child({ module: "evmRedeemedTransactionFoundMapper" });
export const evmRedeemedTransactionFoundMapper = (
transaction: EvmTransaction
): TransactionFoundEvent<TransactionFound> => {
const contractsMapperConfig: ContractsMapperConfig = configData as ContractsMapperConfig;
const protocol = methodNameByAddressMapper(
transaction.chain,
transaction.environment,
transaction
);
const vaaInformation = mappedVaaInformation(transaction);
const status = mappedStatus(transaction);
const emitterAddress = vaaInformation?.emitterAddress;
const emitterChain = vaaInformation?.emitterChain;
const sequence = vaaInformation?.sequence;
logger.info(
`[${transaction.chain}][evmRedeemedTransactionFoundMapper] Transaction info: [hash: ${transaction.hash}][VAA: ${emitterChain}/${emitterAddress}/${sequence}]`
);
return {
name: "transfer-redeemed",
address: transaction.to,
chainId: transaction.chainId,
txHash: transaction.hash,
blockHeight: BigInt(transaction.blockNumber),
blockTime: transaction.timestamp,
attributes: {
from: transaction.from,
to: transaction.to,
status: status,
blockNumber: transaction.blockNumber,
input: transaction.input,
methodsByAddress: protocol?.method,
timestamp: transaction.timestamp,
blockHash: transaction.blockHash,
gas: transaction.gas,
gasPrice: transaction.gasPrice,
maxFeePerGas: transaction.maxFeePerGas,
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas,
nonce: transaction.nonce,
r: transaction.r,
s: transaction.s,
transactionIndex: transaction.transactionIndex,
type: transaction.type,
v: transaction.v,
value: transaction.value,
sequence: sequence,
emitterAddress: emitterAddress,
emitterChain: emitterChain,
},
};
};
const mappedVaaInformation = (transaction: EvmTransaction): VaaInformation | undefined => {
const logs = transaction.logs;
const log = logs.find((log) => {
if (log.topics.includes(CCTP_TOPIC) || log.topics.includes(TOKEN_BRIDGE_TOPIC)) return log;
});
const vaaInformation = log
? {
emitterChain: Number(log.topics[1]),
emitterAddress: BigInt(log.topics[2])?.toString(16)?.toUpperCase()?.padStart(64, "0"),
sequence: Number(log.topics[3]),
}
: undefined;
return vaaInformation;
};
const mappedStatus = (transaction: EvmTransaction): string => {
switch (transaction.status) {
case TX_STATUS_CONFIRMED:
return status.TxStatusConfirmed;
case TX_STATUS_FAILED:
return status.TxStatusFailed;
default:
return status.TxStatusUnkonwn;
}
};
type VaaInformation = {
emitterChain?: number;
emitterAddress?: string;
sequence?: number;
};
export enum status {
TxStatusConfirmed = "completed",
TxStatusUnkonwn = "unknown",
TxStatusFailed = "failed",
}
interface ContractsMapperConfig {
contracts: {
chain: string;
protocols: {
address: string[];
type: string;
methods: { methodId: string; method: string }[];
}[];
}[];
}