blockchain-api
Version:
API utilities for interacting with the Exatechl2 blockchain
220 lines (218 loc) • 8.79 kB
JavaScript
;
/**
* Contract Operations
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getContractInfo = getContractInfo;
exports.isContractVerified = isContractVerified;
exports.getContractAbi = getContractAbi;
exports.findValidContracts = findValidContracts;
const rpc_1 = require("../../core/rpc");
const explorerApi_1 = require("../../core/explorerApi");
const transactions_1 = require("../transactions/transactions");
const blocks_1 = require("../blocks/blocks");
const formatters_1 = require("../../utils/formatters");
const registry_1 = require("../../utils/registry");
const contract_utils_1 = require("./contract-utils");
const logger_1 = require("../../utils/logger");
const initializeSystemContracts = () => {
const systemContracts = [
{ address: '0x00000000000000000000000000000000000a4b05', name: 'Core System Contract' }
];
systemContracts.forEach(contract => {
(0, registry_1.registerSystemContract)(contract.address, contract.name);
});
};
initializeSystemContracts();
/**
* @param {string} address
* @returns {Promise<ContractInfo>}
*/
async function getContractInfo(address) {
try {
const isContractAddress = await (0, contract_utils_1.checkIsContract)(address);
if (!isContractAddress) {
throw new Error(`Address ${address} is not a contract`);
}
const bytecode = await (0, contract_utils_1.getContractBytecode)(address);
const balance = await (0, rpc_1.callRpc)('eth_getBalance', [address, 'latest']);
if ((0, contract_utils_1.isSystemContract)(address.toLowerCase())) {
return {
address,
bytecode,
creator: "System Contract",
creationTx: null,
creationTimestamp: null,
balance,
isVerified: false
};
}
let creator = null;
let creationTx = null;
let creationTimestamp = null;
let isVerified = false;
try {
const contractFromExplorer = await (0, explorerApi_1.callExplorerApi)(`contracts/${address}`);
if (contractFromExplorer && contractFromExplorer.data) {
const contractData = contractFromExplorer.data;
creator = contractData.creator_address || null;
creationTx = contractData.creation_transaction || null;
creationTimestamp = contractData.creation_timestamp || null;
isVerified = contractData.is_verified || false;
logger_1.logger.debug(`Got contract info from Explorer DB for ${address}`);
}
}
catch (e) {
logger_1.logger.warn(`Could not fetch contract info from Explorer DB: ${e.message}`);
}
return {
address,
bytecode,
creator,
creationTx,
creationTimestamp,
balance,
isVerified
};
}
catch (error) {
logger_1.logger.error('Error getting contract info:', error);
throw error;
}
}
/**
*
* @param {string} address
* @returns {Promise<boolean>}
*/
async function isContractVerified(address) {
try {
const isContractAddress = await (0, contract_utils_1.checkIsContract)(address);
if (!isContractAddress) {
return false;
}
try {
const contractFromExplorer = await (0, explorerApi_1.callExplorerApi)(`contracts/${address}`);
if (contractFromExplorer && contractFromExplorer.data) {
return contractFromExplorer.data.is_verified || false;
}
}
catch (e) {
logger_1.logger.warn(`Could not fetch verification status from Explorer DB: ${e}`);
}
return false;
}
catch (error) {
logger_1.logger.error('Error checking contract verification:', error);
return false;
}
}
/**
*
* @param {string} address
* @returns {Promise<object | null>}
*/
async function getContractAbi(address) {
try {
const isVerified = await isContractVerified(address);
if (!isVerified) {
return null;
}
try {
const abiFromExplorer = await (0, explorerApi_1.callExplorerApi)(`contracts/${address}/abi`);
if (abiFromExplorer && abiFromExplorer.data && abiFromExplorer.data.abi) {
return JSON.parse(abiFromExplorer.data.abi);
}
}
catch (e) {
logger_1.logger.warn(`Could not fetch ABI from Explorer DB: ${e}`);
}
return null;
}
catch (error) {
logger_1.logger.error('Error getting contract ABI:', error);
return null;
}
}
/**
*
* @param {number} maxResults
* @param {number} maxBlocks
* @returns {Promise<string[]>}
*/
async function findValidContracts(maxResults = 5, maxBlocks = 10) {
try {
const latestBlockHex = await (0, blocks_1.getLatestBlockNumber)();
const latestBlock = (0, formatters_1.parseHexToDecimal)(latestBlockHex);
const contractAddresses = [];
const processedAddresses = new Set();
for (let i = 0; i < maxBlocks; i++) {
if (contractAddresses.length >= maxResults) {
break;
}
const blockNumber = latestBlock - i;
if (blockNumber < 0)
break;
try {
const block = await (0, blocks_1.getBlockByNumber)(blockNumber, true);
if (block && block.transactions && Array.isArray(block.transactions)) {
const contractCreations = block.transactions
.filter(tx => (0, contract_utils_1.isTransactionObject)(tx) && !tx.to);
for (const tx of contractCreations) {
if ((0, contract_utils_1.isTransactionObject)(tx)) {
try {
const receipt = await (0, transactions_1.getTransactionReceipt)(tx.hash);
if (receipt && receipt.contractAddress && !processedAddresses.has(receipt.contractAddress)) {
const isContract = await (0, contract_utils_1.checkIsContract)(receipt.contractAddress);
if (isContract) {
contractAddresses.push(receipt.contractAddress);
processedAddresses.add(receipt.contractAddress);
if (contractAddresses.length >= maxResults) {
break;
}
}
}
}
catch (e) {
logger_1.logger.warn(`Error processing transaction ${tx.hash}:`, e);
}
}
}
if (contractAddresses.length < maxResults) {
const contractInteractions = block.transactions
.filter(tx => (0, contract_utils_1.isTransactionObject)(tx) && tx.to);
for (const tx of contractInteractions) {
if ((0, contract_utils_1.isTransactionObject)(tx) && tx.to) {
if (processedAddresses.has(tx.to)) {
continue;
}
try {
const isContract = await (0, contract_utils_1.checkIsContract)(tx.to);
if (isContract) {
contractAddresses.push(tx.to);
processedAddresses.add(tx.to);
if (contractAddresses.length >= maxResults) {
break;
}
}
}
catch (e) {
logger_1.logger.warn(`Error checking if address is contract ${tx.to}:`, e);
}
}
}
}
}
}
catch (e) {
logger_1.logger.warn(`Error processing block ${blockNumber}:`, e);
continue;
}
}
return contractAddresses;
}
catch (error) {
logger_1.logger.error('Error finding valid contracts:', error);
return [];
}
}