From fcb7ab47e04e9164bf33a82aa4ab8ac7d6db30fa Mon Sep 17 00:00:00 2001 From: Kashif Jamil Date: Thu, 24 Jul 2025 16:15:40 +0530 Subject: [PATCH] fix(sdk-coin-soneium): update recoveryBlockchainExplorerQuery Ticket: WIN-6372 --- modules/sdk-coin-soneium/package.json | 4 +- modules/sdk-coin-soneium/src/lib/utils.ts | 70 +++++++++++++++++++- modules/sdk-coin-soneium/src/soneium.ts | 20 ++---- modules/sdk-coin-soneium/src/soneiumToken.ts | 18 +++-- modules/sdk-core/src/bitgo/environments.ts | 2 +- 5 files changed, 86 insertions(+), 28 deletions(-) diff --git a/modules/sdk-coin-soneium/package.json b/modules/sdk-coin-soneium/package.json index fbd3e6d28b..ba409c824d 100644 --- a/modules/sdk-coin-soneium/package.json +++ b/modules/sdk-coin-soneium/package.json @@ -43,7 +43,9 @@ "@bitgo/abstract-eth": "^24.8.1", "@bitgo/sdk-core": "^35.8.0", "@bitgo/statics": "^55.2.0", - "@ethereumjs/common": "^2.6.5" + "@ethereumjs/common": "^2.6.5", + "ethereumjs-util": "^7.1.5", + "superagent": "^10.2.3" }, "devDependencies": { "@bitgo/sdk-api": "^1.65.1", diff --git a/modules/sdk-coin-soneium/src/lib/utils.ts b/modules/sdk-coin-soneium/src/lib/utils.ts index 3b68915463..cce5753217 100644 --- a/modules/sdk-coin-soneium/src/lib/utils.ts +++ b/modules/sdk-coin-soneium/src/lib/utils.ts @@ -1,7 +1,13 @@ import { NetworkType } from '@bitgo/statics'; import EthereumCommon from '@ethereumjs/common'; -import { InvalidTransactionError } from '@bitgo/sdk-core'; +import { InvalidTransactionError, common } from '@bitgo/sdk-core'; import { mainnetCommon, testnetCommon } from './resources'; +import { recoveryBlockchainExplorerQuery as abstractRecoveryQuery } from '@bitgo/abstract-eth'; +import request from 'superagent'; +import { addHexPrefix } from 'ethereumjs-util'; + +const RESPONSE_STATUS_ERROR = '0'; +const RESPONSE_MESSAGE_NOTOK = 'NOTOK'; const commons: Map = new Map([ [NetworkType.MAINNET, mainnetCommon], @@ -19,3 +25,65 @@ export function getCommon(network: NetworkType): EthereumCommon { } return common; } + +/** + * Handle standard blockchain explorer query + * @param query Query parameters + * @param bitgoEnv BitGo environment + * @returns Response from soneium.network + */ +async function handleStandardExplorerQuery(query: Record, bitgoEnv: string): Promise { + const apiToken = common.Environments[bitgoEnv].soneiumExplorerApiToken; + const explorerUrl = common.Environments[bitgoEnv].soneiumExplorerBaseUrl; + return await abstractRecoveryQuery(query, explorerUrl as string, apiToken); +} + +/** + * Handle proxy blockchain explorer query + * @param query Query parameters + * @param bitgoEnv BitGo environment + * @returns Response from soneium.network + */ +async function handleProxyExplorerQuery(query: Record, bitgoEnv: string): Promise { + const body = { + jsonrpc: '2.0', + method: query.action, + params: [ + { + to: query.to, + data: addHexPrefix(query.data), + }, + query.tag || 'latest', + ], + id: 1, + }; + + const response = await request.post(common.Environments[bitgoEnv].soneiumExplorerBaseUrl + '/api/eth-rpc').send(body); + + if (!response.ok) { + throw new Error('Could not reach soneium.network'); + } + + if (response.body.status === RESPONSE_STATUS_ERROR && response.body.message === RESPONSE_MESSAGE_NOTOK) { + throw new Error('Soneium.network rate limit reached'); + } + + return response.body; +} + +/** + * Make a query to soneium.network for information such as balance, token balance, solidity calls + * @param query Query parameters + * @param bitgoEnv BitGo environment + * @returns Response from soneium.network + */ +export async function recoveryBlockchainExplorerQuery(query: Record, bitgoEnv: string): Promise { + try { + if (query.module === 'proxy') { + return await handleProxyExplorerQuery(query, bitgoEnv); + } + return await handleStandardExplorerQuery(query, bitgoEnv); + } catch (error) { + throw new Error(`Could not query soneium explorer, error: ${error?.message || 'Unknown error'}`); + } +} diff --git a/modules/sdk-coin-soneium/src/soneium.ts b/modules/sdk-coin-soneium/src/soneium.ts index 6eeeeb87be..f4e4dd187e 100644 --- a/modules/sdk-coin-soneium/src/soneium.ts +++ b/modules/sdk-coin-soneium/src/soneium.ts @@ -7,16 +7,11 @@ * @coinWebsite https://docs.soneium.org/soneium-chain/quick-start/info */ -import { BaseCoin, BitGoBase, common, MPCAlgorithm, MultisigType, multisigTypes } from '@bitgo/sdk-core'; +import { BaseCoin, BitGoBase, MPCAlgorithm, MultisigType, multisigTypes } from '@bitgo/sdk-core'; import { BaseCoin as StaticsBaseCoin, coins, ethGasConfigs } from '@bitgo/statics'; -import { - AbstractEthLikeNewCoins, - recoveryBlockchainExplorerQuery, - UnsignedSweepTxMPCv2, - RecoverOptions, - OfflineVaultTxInfo, -} from '@bitgo/abstract-eth'; +import { AbstractEthLikeNewCoins, UnsignedSweepTxMPCv2, RecoverOptions, OfflineVaultTxInfo } from '@bitgo/abstract-eth'; import { TransactionBuilder } from './lib'; +import * as utils from './lib/utils'; export class Soneium extends AbstractEthLikeNewCoins { protected constructor(bitgo: BitGoBase, staticsCoin?: Readonly) { @@ -56,13 +51,8 @@ export class Soneium extends AbstractEthLikeNewCoins { * @param {string} apiKey optional API key to use instead of the one from the environment * @returns {Promise} response from Soneium explorer */ - async recoveryBlockchainExplorerQuery( - query: Record, - apiKey?: string - ): Promise> { - const apiToken = apiKey || common.Environments[this.bitgo.getEnv()].soneiumExplorerApiToken; - const explorerUrl = common.Environments[this.bitgo.getEnv()].soneiumExplorerBaseUrl; - return await recoveryBlockchainExplorerQuery(query, explorerUrl as string, apiToken); + async recoveryBlockchainExplorerQuery(query: Record): Promise { + return await utils.recoveryBlockchainExplorerQuery(query, this.bitgo.getEnv()); } /** diff --git a/modules/sdk-coin-soneium/src/soneiumToken.ts b/modules/sdk-coin-soneium/src/soneiumToken.ts index bd8ea80af2..80c38665ad 100644 --- a/modules/sdk-coin-soneium/src/soneiumToken.ts +++ b/modules/sdk-coin-soneium/src/soneiumToken.ts @@ -1,8 +1,8 @@ import { coins, EthLikeTokenConfig } from '@bitgo/statics'; -import { BitGoBase, CoinConstructor, common, MPCAlgorithm, NamedCoinConstructor } from '@bitgo/sdk-core'; -import { CoinNames, EthLikeToken, recoveryBlockchainExplorerQuery } from '@bitgo/abstract-eth'; - +import { BitGoBase, CoinConstructor, MPCAlgorithm, NamedCoinConstructor } from '@bitgo/sdk-core'; +import { CoinNames, EthLikeToken } from '@bitgo/abstract-eth'; import { TransactionBuilder } from './lib'; +import * as utils from './lib/utils'; export { EthLikeTokenConfig }; @@ -40,14 +40,12 @@ export class SoneiumToken extends EthLikeToken { } /** - * Make a query to Soneium blockchain explorer for information such as balance, token balance, solidity calls - * @param {Object} query key-value pairs of parameters to append after /api - * @returns {Promise} response Soneium explorer + * Make a query to soneium.network for information such as balance, token balance, solidity calls + * @param {Object} query — key-value pairs of parameters to append after /api + * @returns {Promise} response from soneium.network */ - async recoveryBlockchainExplorerQuery(query: Record): Promise> { - const apiToken = common.Environments[this.bitgo.getEnv()].soneiumExplorerApiToken; - const explorerUrl = common.Environments[this.bitgo.getEnv()].soneiumExplorerBaseUrl; - return await recoveryBlockchainExplorerQuery(query, explorerUrl as string, apiToken); + async recoveryBlockchainExplorerQuery(query: Record): Promise { + return await utils.recoveryBlockchainExplorerQuery(query, this.bitgo.getEnv()); } getFullName(): string { diff --git a/modules/sdk-core/src/bitgo/environments.ts b/modules/sdk-core/src/bitgo/environments.ts index 23532628af..6b6920d5b2 100644 --- a/modules/sdk-core/src/bitgo/environments.ts +++ b/modules/sdk-core/src/bitgo/environments.ts @@ -231,7 +231,7 @@ const mainnetBase: EnvironmentTemplate = { icpNodeUrl: 'https://ic0.app', worldExplorerBaseUrl: 'https://worldscan.org/', somniaExplorerBaseUrl: 'https://mainnet.somnia.w3us.site/', - soneiumExplorerBaseUrl: 'https://soneium-minato.blockscout.com', + soneiumExplorerBaseUrl: 'https://soneium.blockscout.com', monExplorerBaseUrl: 'https://mainnet-beta.monvision.io', stxNodeUrl: 'https://api.hiro.so', vetNodeUrl: 'https://rpc-mainnet.vechain.energy',