@@ -1047,3 +1047,193 @@ export async function recoveryBlockchainExplorerQuery(
10471047export function getDefaultExpireTime ( ) : number {
10481048 return Math . floor ( new Date ( ) . getTime ( ) / 1000 ) + 60 * 60 * 24 * 7 ;
10491049}
1050+
1051+ export async function recovery_HBAREVM_BlockchainExplorerQuery (
1052+ query : Record < string , string > ,
1053+ explorerUrl : string ,
1054+ token ?: string
1055+ ) : Promise < Record < string , unknown > > {
1056+ // Hedera Mirror Node API does not use API keys, but we keep this for compatibility
1057+ if ( token ) {
1058+ query . apikey = token ;
1059+ }
1060+
1061+ const { module, action } = query ;
1062+
1063+ // Remove trailing slash from explorerUrl if present
1064+ const baseUrl = explorerUrl . replace ( / \/ $ / , '' ) ;
1065+
1066+ try {
1067+ switch ( `${ module } .${ action } ` ) {
1068+ case 'account.balance' :
1069+ return await queryAddressBalanceHedera ( query , baseUrl ) ;
1070+
1071+ case 'account.txlist' :
1072+ return await getAddressNonceHedera ( query , baseUrl ) ;
1073+
1074+ case 'account.tokenbalance' :
1075+ return await queryTokenBalanceHedera ( query , baseUrl ) ;
1076+
1077+ case 'proxy.eth_gasPrice' :
1078+ return await getGasPriceHedera ( query , baseUrl ) ;
1079+
1080+ case 'proxy.eth_estimateGas' :
1081+ return await getGasLimitHedera ( query , baseUrl ) ;
1082+
1083+ case 'proxy.eth_call' :
1084+ return await querySequenceIdHedera ( query , baseUrl ) ;
1085+
1086+ default :
1087+ throw new Error ( `Unsupported API call: ${ module } .${ action } ` ) ;
1088+ }
1089+ } catch ( error ) {
1090+ throw error ;
1091+ }
1092+ }
1093+
1094+ /**
1095+ * 1. Gets address balance using Hedera Mirror Node API
1096+ */
1097+ async function queryAddressBalanceHedera (
1098+ query : Record < string , string > ,
1099+ baseUrl : string
1100+ ) : Promise < Record < string , unknown > > {
1101+ const address = query . address ;
1102+ const url = `${ baseUrl } /accounts/${ address } ` ;
1103+ const response = await request . get ( url ) . send ( ) ;
1104+
1105+ if ( ! response . ok ) {
1106+ throw new Error ( 'could not reach explorer' ) ;
1107+ }
1108+
1109+ const balance = response . body . balance ?. balance || '0' ;
1110+
1111+ return balance ;
1112+ }
1113+
1114+ /**
1115+ * 2. Gets nonce using Hedera Mirror Node API
1116+ */
1117+ async function getAddressNonceHedera ( query : Record < string , string > , baseUrl : string ) : Promise < Record < string , unknown > > {
1118+ const address = query . address ;
1119+ const accountUrl = `${ baseUrl } /accounts/${ address } ` ;
1120+ const response = await request . get ( accountUrl ) . send ( ) ;
1121+
1122+ if ( ! response . ok ) {
1123+ throw new Error ( 'could not reach explorer' ) ;
1124+ }
1125+
1126+ const nonce = response . body . ethereum_nonce || 0 ;
1127+
1128+ return { nonce } ;
1129+ }
1130+
1131+ /**
1132+ * 3. Gets token balance using Hedera Mirror Node API
1133+ */
1134+ async function queryTokenBalanceHedera (
1135+ query : Record < string , string > ,
1136+ baseUrl : string
1137+ ) : Promise < Record < string , unknown > > {
1138+ const contractAddress = query . contractaddress ;
1139+ const address = query . address ;
1140+
1141+ // Get token balances for the account
1142+ const url = `${ baseUrl } /accounts/${ address } /tokens` ;
1143+ const response = await request . get ( url ) . send ( ) ;
1144+
1145+ if ( ! response . ok ) {
1146+ throw new Error ( 'could not reach explorer' ) ;
1147+ }
1148+
1149+ // Find the specific token balance
1150+ const tokens = response . body . tokens || [ ] ;
1151+ const tokenBalance = tokens . find (
1152+ ( token : { token_id : string ; contract_address : string ; balance : number } ) =>
1153+ token . token_id === contractAddress || token . contract_address === contractAddress
1154+ ) ;
1155+
1156+ const balance = tokenBalance ? tokenBalance . balance . toString ( ) : '0' ;
1157+
1158+ return balance ;
1159+ }
1160+
1161+ /**
1162+ * 4. Gets sequence ID using Hedera Mirror Node API or rpc call
1163+ */
1164+ async function querySequenceIdHedera ( query : Record < string , string > , baseUrl : string ) : Promise < Record < string , unknown > > {
1165+ const { to, data } = query ;
1166+
1167+ const url = 'https://testnet.hashio.io/api' ;
1168+
1169+ const requestBody = {
1170+ jsonrpc : '2.0' ,
1171+ method : 'eth_call' ,
1172+ params : [
1173+ {
1174+ to : to ,
1175+ data : data ,
1176+ } ,
1177+ ] ,
1178+ id : 1 ,
1179+ } ;
1180+
1181+ const response = await request . post ( url ) . send ( requestBody ) . set ( 'Content-Type' , 'application/json' ) ;
1182+
1183+ if ( ! response . ok ) {
1184+ throw new Error ( 'could not reach explorer' ) ;
1185+ }
1186+
1187+ return response . body ;
1188+ }
1189+
1190+ /**
1191+ * 5. getGasPriceFromExternalAPI - Gets gas price using Hedera Mirror Node API
1192+ */
1193+ async function getGasPriceHedera ( query : Record < string , string > , baseUrl : string ) : Promise < Record < string , unknown > > {
1194+ const url = 'https://testnet.hashio.io/api' ;
1195+
1196+ const requestBody = {
1197+ jsonrpc : '2.0' ,
1198+ method : 'eth_gasPrice' ,
1199+ params : [ ] ,
1200+ id : 1 ,
1201+ } ;
1202+
1203+ const response = await request . post ( url ) . send ( requestBody ) . set ( 'Content-Type' , 'application/json' ) ;
1204+
1205+ if ( ! response . ok ) {
1206+ throw new Error ( 'could not reach explorer' ) ;
1207+ }
1208+
1209+ return response . body ;
1210+ }
1211+
1212+ /**
1213+ * 6. getGasLimitFromExternalAPI - Gets gas limit using Hedera Mirror Node API
1214+ */
1215+ async function getGasLimitHedera ( query : Record < string , string > , baseUrl : string ) : Promise < Record < string , unknown > > {
1216+ const url = 'https://testnet.hashio.io/api' ;
1217+
1218+ const { from, to, data } = query ;
1219+
1220+ const requestBody = {
1221+ jsonrpc : '2.0' ,
1222+ method : 'eth_estimateGas' ,
1223+ params : [
1224+ {
1225+ from,
1226+ to,
1227+ data,
1228+ } ,
1229+ ] ,
1230+ id : 1 ,
1231+ } ;
1232+ const response = await request . post ( url ) . send ( requestBody ) . set ( 'Content-Type' , 'application/json' ) ;
1233+
1234+ if ( ! response . ok ) {
1235+ throw new Error ( 'could not reach explorer' ) ;
1236+ }
1237+
1238+ return response . body ;
1239+ }
0 commit comments