diff --git a/src/__tests__/masterBitgoExpress/generateWallet.test.ts b/src/__tests__/masterBitgoExpress/generateWallet.test.ts index bed02154..552efa8b 100644 --- a/src/__tests__/masterBitgoExpress/generateWallet.test.ts +++ b/src/__tests__/masterBitgoExpress/generateWallet.test.ts @@ -41,10 +41,6 @@ describe('POST /api/:coin/wallet/generate', () => { nock.cleanAll(); }); - after(() => { - nock.restore(); - }); - it('should generate a wallet by calling the enclaved express service', async () => { const userKeychainNock = nock(enclavedExpressUrl) .post(`/api/${coin}/key/independent`) diff --git a/src/__tests__/postIndependentKey.test.ts b/src/__tests__/postIndependentKey.test.ts new file mode 100644 index 00000000..ff8073c7 --- /dev/null +++ b/src/__tests__/postIndependentKey.test.ts @@ -0,0 +1,86 @@ +import 'should'; + +import * as request from 'supertest'; +import nock from 'nock'; +import { app as enclavedApp } from '../enclavedApp'; +import { AppMode, EnclavedConfig, TlsMode } from '../types'; +import express from 'express'; + +import * as sinon from 'sinon'; +import * as configModule from '../initConfig'; + +describe('postIndependentKey', () => { + let cfg: EnclavedConfig; + let app: express.Application; + let agent: request.SuperAgentTest; + + // test cofig + const kmsUrl = 'http://kms.invalid'; + const coin = 'hteth'; + const accessToken = 'test-token'; + + // sinon stubs + let configStub: sinon.SinonStub; + + before(() => { + // nock config + nock.disableNetConnect(); + nock.enableNetConnect('127.0.0.1'); + + // app config + cfg = { + appMode: AppMode.ENCLAVED, + port: 0, // Let OS assign a free port + bind: 'localhost', + timeout: 60000, + logFile: '', + kmsUrl: kmsUrl, + tlsMode: TlsMode.DISABLED, + mtlsRequestCert: false, + allowSelfSigned: true, + }; + + configStub = sinon.stub(configModule, 'initConfig').returns(cfg); + + // app setup + app = enclavedApp(cfg); + agent = request.agent(app); + }); + + afterEach(() => { + nock.cleanAll(); + }); + + after(() => { + configStub.restore(); + }); + + // test cases + it('should post an independent key successfully', async () => { + const mockKmsResponse = { + coin: coin, + pub: 'xpub661MyMwAqRbcGAEfZmG74QD11P4dCKRkuwpsJG87QKVPcMdA1PLe76de1Ted54rZ2gyqLYhmdhBCFMrt7AoVwPZwXa3Na9aUnvndvXbvmwu', + source: 'user', + type: 'independent', + }; + + const kmsNock = nock(kmsUrl).post(`/key`).reply(200, mockKmsResponse); + + console.log(cfg.kmsUrl); + + console.warn(nock.activeMocks()); + console.warn(nock.isActive()); + + const response = await agent + .post(`/api/${coin}/key/independent`) + .set('Authorization', `Bearer ${accessToken}`) + .send({ source: 'user' }); + + response.status.should.equal(200); + response.body.should.have.property('pub', mockKmsResponse.pub); + response.body.should.have.property('coin', mockKmsResponse.coin); + response.body.should.have.property('source', mockKmsResponse.source); + + kmsNock.done(); + }); +}); diff --git a/src/__tests__/signMultisigTransaction.test.ts b/src/__tests__/signMultisigTransaction.test.ts new file mode 100644 index 00000000..f6322dff --- /dev/null +++ b/src/__tests__/signMultisigTransaction.test.ts @@ -0,0 +1,122 @@ +import 'should'; + +import * as request from 'supertest'; +import nock from 'nock'; +import { app as enclavedApp } from '../enclavedApp'; +import { AppMode, EnclavedConfig, TlsMode } from '../types'; +import express from 'express'; + +import * as sinon from 'sinon'; +import * as configModule from '../initConfig'; + +describe('signMultisigTransaction', () => { + let cfg: EnclavedConfig; + let app: express.Application; + let agent: request.SuperAgentTest; + + // test cofig + const kmsUrl = 'http://kms.invalid'; + const coin = 'hteth'; + const accessToken = 'test-token'; + + // sinon stubs + let configStub: sinon.SinonStub; + + before(() => { + // nock config + nock.disableNetConnect(); + nock.enableNetConnect('127.0.0.1'); + + // app config + cfg = { + appMode: AppMode.ENCLAVED, + port: 0, // Let OS assign a free port + bind: 'localhost', + timeout: 60000, + logFile: '', + kmsUrl: kmsUrl, + tlsMode: TlsMode.DISABLED, + mtlsRequestCert: false, + allowSelfSigned: true, + }; + + configStub = sinon.stub(configModule, 'initConfig').returns(cfg); + + // app setup + app = enclavedApp(cfg); + agent = request.agent(app); + }); + + afterEach(() => { + nock.cleanAll(); + }); + + after(() => { + configStub.restore(); + }); + + // test cases + it('should half-sign a multisig transaction successfully', async () => { + const input = { + source: 'user', + pub: 'xpub661MyMwAqRbcGAEfZmG74QD11P4dCKRkuwpsJG87QKVPcMdA1PLe76de1Ted54rZ2gyqLYhmdhBCFMrt7AoVwPZwXa3Na9aUnvndvXbvmwu', + txPrebuild: { + feeInfo: { + date: '2025-06-11T16:35:04.622Z', + gasPrice: '11610471836', + baseFee: '11478770445', + gasUsedRatio: '0.9999833170418686', + safeLowMinerTip: '521229555', + normalMinerTip: '521229555', + standardMinerTip: '521229555', + fastestMinerTip: '521229555', + ludicrousMinerTip: '550407891', + }, + eip1559: { maxPriorityFeePerGas: '599413988', maxFeePerGas: '23556954878' }, + recipients: [ + { + amount: '10000', + address: '0xe9cbfdf9e02f4ee37ec81683a4be934b4eecc295', + }, + ], + nextContractSequenceId: 5, + gasLimit: 200000, + isBatch: false, + coin: 'hteth', + walletId: '68489ecff6fb16304670b327db8eb31a', + walletContractAddress: '0xe9cbfdf9e02f4ee37ec81683a4be934b4eecc295', + reqId: {}, // modified + wallet: { + // modified + bitgo: {}, + baseCoin: {}, + _wallet: {}, + }, + buildParams: {}, + }, + }; + + const mockKmsResponse = { + prv: 'xprv9s21ZrQH143K3gACTjj6hGGGTME8nrhuYiuGVsiVqyxQjZJ1Tr2PZJKAABHLm2gMSwqRmXBXT8VcXppDy43xjwvt9xdgkDSyRPsBUekEaPq', + pub: 'xpub661MyMwAqRbcGAEfZmG74QD11P4dCKRkuwpsJG87QKVPcMdA1PLe76de1Ted54rZ2gyqLYhmdhBCFMrt7AoVwPZwXa3Na9aUnvndvXbvmwu', + source: 'user', + type: 'independent', + }; + + const kmsNock = nock(kmsUrl) + .get(`/key/${input.pub}`) + .query({ source: 'user' }) + .reply(200, mockKmsResponse); + + const response = await agent + .post(`/api/${coin}/multisig/sign`) + .set('Authorization', `Bearer ${accessToken}`) + .query({ source: input.source }) + .send(input); + + response.status.should.equal(200); + response.body.should.have.property('halfSigned'); + + kmsNock.done(); + }); +});