Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 46 additions & 15 deletions src/__tests__/api/master/musigRecovery.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import 'should';
import sinon from 'sinon';

import { AbstractEthLikeNewCoins } from '@bitgo-beta/abstract-eth';
import nock from 'nock';
import * as request from 'supertest';
import { app as expressApp } from '../../../masterBitGoExpressApp';
import { AppMode, MasterExpressConfig, TlsMode } from '../../../shared/types';
import { data as ethRecoveryData } from '../../mocks/ethRecoveryMusigMockData';
import { BitGoAPITestHarness } from './testUtils';

describe('POST /api/v1/:coin/advancedwallet/recovery', () => {
let agent: request.SuperAgentTest;
Expand Down Expand Up @@ -41,23 +41,51 @@ describe('POST /api/v1/:coin/advancedwallet/recovery', () => {
afterEach(() => {
nock.cleanAll();
sinon.restore();
BitGoAPITestHarness.clearConstantsCache();
});

it('should get the tx hex for broadcasting from eve on musig recovery ', async () => {
// sdk call mock on mbe
const recoverStub = sinon
.stub(AbstractEthLikeNewCoins.prototype, 'recover')
.resolves(ethRecoveryData.unsignedSweepPrebuildTx);
const backupKeyAddress = '0x30edc88a77598833f58947638b2ac3d5713d9845';
const apiKey = 'etherscan-api-token';
const etherscanBase = 'https://api.etherscan.io';
const chainid = '560048';

// Etherscan calls to get the nonce, balance, and sequence ID for the backup key and wallet contract
const txlistNock = nock(etherscanBase)
.get(
`/v2/api?chainid=${chainid}&module=account&action=txlist&address=${backupKeyAddress}&apikey=${apiKey}`,
)
.twice()
.reply(200, { result: [] });

const backupBalanceNock = nock(etherscanBase)
.get(
`/v2/api?chainid=${chainid}&module=account&action=balance&address=${backupKeyAddress}&apikey=${apiKey}`,
)
.reply(200, { result: '10000000000000000' });

const walletBalanceNock = nock(etherscanBase)
.get(
`/v2/api?chainid=${chainid}&module=account&action=balance&address=${ethRecoveryData.walletContractAddress}&apikey=${apiKey}`,
)
.reply(200, { result: '1000000000000000000' });

const sequenceIdNock = nock(etherscanBase)
.get(
`/v2/api?chainid=${chainid}&module=proxy&action=eth_call&to=${ethRecoveryData.walletContractAddress}&data=a0b7967b&tag=latest&apikey=${apiKey}`,
)
.reply(200, {
result: '0x0000000000000000000000000000000000000000000000000000000000000001',
});

// the call to eve.recoverWallet(...)
// that contains the calls to sdk.signTransaction
const eveRecoverWalletNock = nock(advancedWalletManagerUrl)
.post(`/api/${coin}/multisig/recovery`, {
userPub: ethRecoveryData.userKey,
backupPub: ethRecoveryData.backupKey,
unsignedSweepPrebuildTx: ethRecoveryData.unsignedSweepPrebuildTx,
coinSpecificParams: undefined,
walletContractAddress: ethRecoveryData.walletContractAddress,
.post(`/api/${coin}/multisig/recovery`, (body) => {
return (
body.userPub === ethRecoveryData.userKey &&
body.backupPub === ethRecoveryData.backupKey &&
body.walletContractAddress === ethRecoveryData.walletContractAddress &&
body.unsignedSweepPrebuildTx !== undefined
);
})
.reply(200, {
txHex: ethRecoveryData.txHexFullSigned,
Expand All @@ -74,13 +102,16 @@ describe('POST /api/v1/:coin/advancedwallet/recovery', () => {
walletContractAddress: ethRecoveryData.walletContractAddress,
bitgoPub: '',
},
apiKey: 'etherscan-api-token',
apiKey,
recoveryDestinationAddress: ethRecoveryData.recoveryDestinationAddress,
});

response.status.should.equal(200);
response.body.should.have.property('txHex', ethRecoveryData.txHexFullSigned);
sinon.assert.calledOnce(recoverStub);
txlistNock.isDone().should.be.true();
backupBalanceNock.isDone().should.be.true();
walletBalanceNock.isDone().should.be.true();
sequenceIdNock.isDone().should.be.true();
eveRecoverWalletNock.done();
});

Expand Down
37 changes: 4 additions & 33 deletions src/__tests__/api/master/nonRecovery.test.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import 'should';
import * as request from 'supertest';
import nock from 'nock';
import sinon from 'sinon';
import { app as expressApp } from '../../../masterBitGoExpressApp';
import { AppMode, MasterExpressConfig, TlsMode } from '../../../shared/types';
import sinon from 'sinon';
import * as middleware from '../../../shared/middleware';
import * as masterMiddleware from '../../../masterBitgoExpress/middleware/middleware';
import { BitGoRequest } from '../../../types/request';
import { BitGoAPI } from '@bitgo-beta/sdk-api';
import { AdvancedWalletManagerClient } from '../../../masterBitgoExpress/clients/advancedWalletManagerClient';
import { BitGoAPITestHarness } from './testUtils';

describe('Non Recovery Tests', () => {
let agent: request.SuperAgentTest;
let mockBitgo: BitGoAPI;
const advancedWalletManagerUrl = 'http://advancedwalletmanager.invalid';
const accessToken = 'test-token';
const config: MasterExpressConfig = {
Expand All @@ -31,45 +26,21 @@ describe('Non Recovery Tests', () => {
recoveryMode: false,
};

beforeEach(() => {
before(() => {
nock.disableNetConnect();
nock.enableNetConnect('127.0.0.1');

// Create mock BitGo instance with base functionality
mockBitgo = new BitGoAPI({ env: 'test' });

// Setup middleware stubs before creating app
sinon.stub(middleware, 'prepareBitGo').callsFake(() => (req, res, next) => {
(req as BitGoRequest<MasterExpressConfig>).bitgo = mockBitgo;
(req as BitGoRequest<MasterExpressConfig>).config = config;
next();
});

// Create app after middleware is stubbed
const app = expressApp(config);
agent = request.agent(app);
});

afterEach(() => {
nock.cleanAll();
sinon.restore();
BitGoAPITestHarness.clearConstantsCache();
});

describe('Recovery', () => {
const coin = 'tbtc';

beforeEach(() => {
sinon.stub(masterMiddleware, 'validateMasterExpressConfig').callsFake((req, res, next) => {
(req as BitGoRequest<MasterExpressConfig>).params = { coin };
(req as BitGoRequest<MasterExpressConfig>).awmUserClient = new AdvancedWalletManagerClient(
config,
coin,
);
next();
return undefined;
});
});

it('should fail to run mbe recovery if not in recovery mode', async () => {
const coin = 'tbtc';
const userPub = 'xpub_user';
Expand Down
Loading
Loading