diff --git a/modules/sdk-coin-etc/src/etc.ts b/modules/sdk-coin-etc/src/etc.ts index 078416c7ad..fb9ecc5664 100644 --- a/modules/sdk-coin-etc/src/etc.ts +++ b/modules/sdk-coin-etc/src/etc.ts @@ -296,11 +296,11 @@ export class Etc extends AbstractEthLikeCoin { params: [address, 'latest'], id: 1, }); - if (!result || isNaN(result.result)) { + if (!result || !result.result || typeof result.result !== 'string' || !/^0x[0-9a-fA-F]*$/.test(result.result)) { throw new Error('Unable to find next nonce from etc.network, got: ' + JSON.stringify(result)); } const nonceHex = result.result; - return new optionalDeps.ethUtil.BN(nonceHex.slice(2), 16).toNumber(); + return new optionalDeps.ethUtil.BN(nonceHex.slice(2) || '0', 16).toNumber(); } /** @@ -322,13 +322,13 @@ export class Etc extends AbstractEthLikeCoin { } else if (result.error) { // throw if result.error exists throw new Error(`Could not obtain address balance for ${address} from etc.network, got: ${result.error}`); - } else if (!result.result || isNaN(result.result)) { - // throw if the result.result is not a number + } else if (!result.result || typeof result.result !== 'string' || !/^0x[0-9a-fA-F]*$/.test(result.result)) { throw new Error(`Could not obtain address balance for ${address} from etc.network, got: Incorrect Balance Hex`); } const nativeBalanceHex = result.result; - return new optionalDeps.ethUtil.BN(nativeBalanceHex.slice(2), 16); + // slice(2) strips '0x'; fall back to '0' if bare '0x' is returned for zero balance + return new optionalDeps.ethUtil.BN(nativeBalanceHex.slice(2) || '0', 16); } /** * Queries the contract (via explorer API) for the next sequence ID diff --git a/modules/sdk-coin-etc/test/unit/etc.ts b/modules/sdk-coin-etc/test/unit/etc.ts index b4a424fb11..8c31bb3b79 100644 --- a/modules/sdk-coin-etc/test/unit/etc.ts +++ b/modules/sdk-coin-etc/test/unit/etc.ts @@ -9,6 +9,61 @@ import { getBuilder } from './getBuilder'; import { FullySignedTransaction } from '@bitgo/sdk-core'; import * as should from 'should'; +describe('queryAddressBalance', function () { + let bitgo: TestBitGoAPI; + let etcCoin: Etc; + let sandbox: sinon.SinonSandbox; + + before(function () { + bitgo = TestBitGo.decorate(BitGoAPI, { env: 'mock' }); + bitgo.initializeTestVars(); + bitgo.safeRegister('etc', Etc.createInstance); + bitgo.safeRegister('tetc', Tetc.createInstance); + }); + + beforeEach(function () { + sandbox = sinon.createSandbox(); + etcCoin = bitgo.coin('etc') as Etc; + }); + + afterEach(function () { + sandbox.restore(); + }); + + it('should return the correct balance for a standard hex response', async function () { + sandbox.stub(etcCoin, 'recoveryBlockchainExplorerQuery').resolves({ result: '0x1bc16d674ec80000' }); + const balance = await etcCoin.queryAddressBalance('0x1234'); + balance.toString().should.equal('2000000000000000000'); + }); + + it('should return zero for a "0x0" response', async function () { + sandbox.stub(etcCoin, 'recoveryBlockchainExplorerQuery').resolves({ result: '0x0' }); + const balance = await etcCoin.queryAddressBalance('0x1234'); + balance.toString().should.equal('0'); + }); + + it('should return zero for a bare "0x" response (zero balance edge case)', async function () { + sandbox.stub(etcCoin, 'recoveryBlockchainExplorerQuery').resolves({ result: '0x' }); + const balance = await etcCoin.queryAddressBalance('0x1234'); + balance.toString().should.equal('0'); + }); + + it('should throw for a missing result', async function () { + sandbox.stub(etcCoin, 'recoveryBlockchainExplorerQuery').resolves(null); + await etcCoin.queryAddressBalance('0x1234').should.be.rejectedWith(/Empty object response/); + }); + + it('should throw for an error result', async function () { + sandbox.stub(etcCoin, 'recoveryBlockchainExplorerQuery').resolves({ error: 'node error' }); + await etcCoin.queryAddressBalance('0x1234').should.be.rejectedWith(/node error/); + }); + + it('should throw for a non-hex result', async function () { + sandbox.stub(etcCoin, 'recoveryBlockchainExplorerQuery').resolves({ result: 'not-a-hex' }); + await etcCoin.queryAddressBalance('0x1234').should.be.rejectedWith(/Incorrect Balance Hex/); + }); +}); + describe('Ethereum Classic', function () { let bitgo: TestBitGoAPI;