Skip to content

Commit

Permalink
Add error handling to eth_call handler
Browse files Browse the repository at this point in the history
  • Loading branch information
prathamesh0 committed Sep 12, 2024
1 parent 8b70c22 commit fb7e179
Showing 1 changed file with 64 additions and 29 deletions.
93 changes: 64 additions & 29 deletions packages/util/src/eth-rpc-handlers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
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 (
indexer: IndexerInterface
): Promise<any> => {
Expand All @@ -13,48 +32,64 @@ export const createEthRPCHandlers = async (
},

eth_call: async (args: any, callback: any) => {
// TODO: Handle empty args
// TODO: Set errors in response
// 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 latestBlock = await indexer.getLatestCanonicalBlock();
const blockHash = latestBlock?.blockHash;
const { to, data, blockTag } = args[0];

const watchedContract = indexer.getWatchedContracts().find(contract => contract.address === to);
if (!watchedContract) {
throw new Error('Contract not recognized');
}
if (!indexer.contractMap) {
throw new ErrorWithCode(CODE_INTERNAL_ERROR, ERROR_CONTRACT_MAP_NOT_SET);
}

if (!indexer.contractMap) {
throw new Error('Contract map not found');
}
// For values other than blockHash, resolve value from block_progress table
const latestBlock = await indexer.getLatestCanonicalBlock();
const blockHash = latestBlock?.blockHash;

const contractInterface = indexer.contractMap.get(watchedContract.kind);
if (!contractInterface) {
throw new Error('Contract ABI not found');
}
const watchedContract = indexer.getWatchedContracts().find(contract => contract.address === to);
if (!watchedContract) {
throw new ErrorWithCode(CODE_INVALID_PARAMS, ERROR_CONTRACT_NOT_RECOGNIZED);
}

// Slice out method signature
const functionSelector = data.slice(0, 10);
const contractInterface = indexer.contractMap.get(watchedContract.kind);
if (!contractInterface) {
throw new ErrorWithCode(CODE_INTERNAL_ERROR, ERROR_CONTRACT_ABI_NOT_FOUND);
}

// Find the matching function from the ABI
const functionFragment = contractInterface.getFunction(functionSelector);
if (!functionFragment) {
throw new Error('Method not found');
}
// Slice out method signature from data
const functionSelector = data.slice(0, 10);

// Find the matching function from the ABI
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);

// 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 encodedResult = contractInterface.encodeFunctionResult(functionFragment, [result.value]);

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);
}
},

Expand Down

0 comments on commit fb7e179

Please sign in to comment.