mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-07-27 10:42:06 +00:00
Add error handling to eth_call handler
This commit is contained in:
parent
8b70c22d17
commit
fb7e1790d9
@ -1,6 +1,25 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import { IndexerInterface } from './types';
|
import { IndexerInterface } from './types';
|
||||||
|
|
||||||
|
const CODE_INVALID_PARAMS = -32602;
|
||||||
|
const CODE_INTERNAL_ERROR = -32603;
|
||||||
|
const CODE_SERVER_ERROR = -32000;
|
||||||
|
|
||||||
|
const ERROR_CONTRACT_MAP_NOT_SET = 'Contract map not set';
|
||||||
|
const ERROR_CONTRACT_ABI_NOT_FOUND = 'Contract ABI not found';
|
||||||
|
const ERROR_CONTRACT_INSUFFICIENT_PARAMS = 'Insufficient params';
|
||||||
|
const ERROR_CONTRACT_NOT_RECOGNIZED = 'Contract not recognized';
|
||||||
|
const ERROR_CONTRACT_METHOD_NOT_FOUND = 'Contract method not found';
|
||||||
|
const ERROR_METHOD_NOT_IMPLEMENTED = 'Method not implemented';
|
||||||
|
|
||||||
|
class ErrorWithCode extends Error {
|
||||||
|
code: number;
|
||||||
|
constructor (code: number, message: string) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const createEthRPCHandlers = async (
|
export const createEthRPCHandlers = async (
|
||||||
indexer: IndexerInterface
|
indexer: IndexerInterface
|
||||||
): Promise<any> => {
|
): Promise<any> => {
|
||||||
@ -13,48 +32,64 @@ export const createEthRPCHandlers = async (
|
|||||||
},
|
},
|
||||||
|
|
||||||
eth_call: async (args: any, callback: any) => {
|
eth_call: async (args: any, callback: any) => {
|
||||||
// TODO: Handle empty args
|
|
||||||
// TODO: Set errors in response
|
|
||||||
// TODO: Parse blockTag
|
// TODO: Parse blockTag
|
||||||
|
|
||||||
const { to, data, blockTag } = args[0];
|
try {
|
||||||
|
if (args.length === 0) {
|
||||||
|
throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_CONTRACT_INSUFFICIENT_PARAMS);
|
||||||
|
}
|
||||||
|
|
||||||
// For values other than blockHash, resolve value from block_progress table
|
const { to, data, blockTag } = args[0];
|
||||||
const latestBlock = await indexer.getLatestCanonicalBlock();
|
|
||||||
const blockHash = latestBlock?.blockHash;
|
|
||||||
|
|
||||||
const watchedContract = indexer.getWatchedContracts().find(contract => contract.address === to);
|
if (!indexer.contractMap) {
|
||||||
if (!watchedContract) {
|
throw new ErrorWithCode(CODE_INTERNAL_ERROR, ERROR_CONTRACT_MAP_NOT_SET);
|
||||||
throw new Error('Contract not recognized');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!indexer.contractMap) {
|
// For values other than blockHash, resolve value from block_progress table
|
||||||
throw new Error('Contract map not found');
|
const latestBlock = await indexer.getLatestCanonicalBlock();
|
||||||
}
|
const blockHash = latestBlock?.blockHash;
|
||||||
|
|
||||||
const contractInterface = indexer.contractMap.get(watchedContract.kind);
|
const watchedContract = indexer.getWatchedContracts().find(contract => contract.address === to);
|
||||||
if (!contractInterface) {
|
if (!watchedContract) {
|
||||||
throw new Error('Contract ABI not found');
|
throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_CONTRACT_NOT_RECOGNIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slice out method signature
|
const contractInterface = indexer.contractMap.get(watchedContract.kind);
|
||||||
const functionSelector = data.slice(0, 10);
|
if (!contractInterface) {
|
||||||
|
throw new ErrorWithCode(CODE_INTERNAL_ERROR, ERROR_CONTRACT_ABI_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
// Find the matching function from the ABI
|
// Slice out method signature from data
|
||||||
const functionFragment = contractInterface.getFunction(functionSelector);
|
const functionSelector = data.slice(0, 10);
|
||||||
if (!functionFragment) {
|
|
||||||
throw new Error('Method not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode the data based on the matched function
|
// Find the matching function from the ABI
|
||||||
const decodedData = contractInterface.decodeFunctionData(functionFragment, data);
|
const functionFragment = contractInterface.getFunction(functionSelector);
|
||||||
|
if (!functionFragment) {
|
||||||
|
throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_CONTRACT_METHOD_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the data based on the matched function
|
||||||
|
const decodedData = contractInterface.decodeFunctionData(functionFragment, data);
|
||||||
|
|
||||||
|
const functionName = functionFragment.name;
|
||||||
|
const indexerMethod = (indexer as any)[functionName].bind(indexer);
|
||||||
|
if (!indexerMethod) {
|
||||||
|
throw new ErrorWithCode(CODE_SERVER_ERROR, ERROR_METHOD_NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
const functionName = functionFragment.name;
|
|
||||||
const indexerMethod = (indexer as any)[functionName].bind(indexer);
|
|
||||||
if (indexerMethod && typeof indexerMethod === 'function') {
|
|
||||||
const result = await indexerMethod(blockHash, to, ...decodedData);
|
const result = await indexerMethod(blockHash, to, ...decodedData);
|
||||||
const encodedResult = contractInterface.encodeFunctionResult(functionFragment, [result.value]);
|
const encodedResult = contractInterface.encodeFunctionResult(functionFragment, [result.value]);
|
||||||
|
|
||||||
callback(null, encodedResult);
|
callback(null, encodedResult);
|
||||||
|
} catch (error: any) {
|
||||||
|
let callBackError;
|
||||||
|
if (error instanceof ErrorWithCode) {
|
||||||
|
callBackError = { code: error.code, message: error.message };
|
||||||
|
} else {
|
||||||
|
callBackError = { code: CODE_SERVER_ERROR, message: error.message };
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(callBackError);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user