Skip to content

Commit a47724d

Browse files
test: ebe tests for musig recovery on hteth
1 parent c36ba04 commit a47724d

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import 'should';
2+
3+
import express from 'express';
4+
import nock from 'nock';
5+
import * as request from 'supertest';
6+
import { app as enclavedApp } from '../../../enclavedApp';
7+
import { AppMode, EnclavedConfig, TlsMode } from '../../../shared/types';
8+
9+
import * as sinon from 'sinon';
10+
import * as configModule from '../../../initConfig';
11+
12+
import { ebeData } from '../../mocks/ethRecoveryMusigMockData';
13+
import unsignedSweepRecJSON from '../../mocks/unsigned-sweep-prebuild-hteth-musig-recovery.json';
14+
15+
describe('recoveryMultisigTransaction', () => {
16+
let cfg: EnclavedConfig;
17+
let app: express.Application;
18+
let agent: request.SuperAgentTest;
19+
20+
// test cofig
21+
const kmsUrl = 'http://kms.invalid';
22+
const coin = 'hteth';
23+
const accessToken = 'test-token';
24+
25+
// sinon stubs
26+
let configStub: sinon.SinonStub;
27+
28+
before(() => {
29+
// nock config
30+
nock.disableNetConnect();
31+
nock.enableNetConnect('127.0.0.1');
32+
33+
// app config
34+
cfg = {
35+
appMode: AppMode.ENCLAVED,
36+
port: 0, // Let OS assign a free port
37+
bind: 'localhost',
38+
timeout: 60000,
39+
logFile: '',
40+
kmsUrl: kmsUrl,
41+
tlsMode: TlsMode.DISABLED,
42+
mtlsRequestCert: false,
43+
allowSelfSigned: true,
44+
};
45+
46+
configStub = sinon.stub(configModule, 'initConfig').returns(cfg);
47+
48+
// app setup
49+
app = enclavedApp(cfg);
50+
agent = request.agent(app);
51+
});
52+
53+
afterEach(() => {
54+
nock.cleanAll();
55+
});
56+
57+
after(() => {
58+
configStub.restore();
59+
});
60+
61+
it('should generate a successful txHex from unsigned sweep prebuild data', async () => {
62+
const { userPub, backupPub, walletContractAddress, userPrv, backupPrv, txHexResult } = ebeData;
63+
const unsignedSweepPrebuildTx = unsignedSweepRecJSON as unknown as any;
64+
65+
const mockKmsUserResponse = {
66+
prv: userPrv,
67+
pub: userPub,
68+
source: 'user',
69+
type: 'independent',
70+
};
71+
72+
const mockKmsBackupResponse = {
73+
prv: backupPrv,
74+
pub: backupPub,
75+
source: 'backup',
76+
type: 'independent',
77+
};
78+
79+
const kmsNockUser = nock(kmsUrl)
80+
.get(`/key/${userPub}`)
81+
.query({ source: 'user' })
82+
.reply(200, mockKmsUserResponse);
83+
84+
const kmsNockBackup = nock(kmsUrl)
85+
.get(`/key/${backupPub}`)
86+
.query({ source: 'backup' })
87+
.reply(200, mockKmsBackupResponse);
88+
89+
console.warn(nock.activeMocks());
90+
console.warn(nock.isActive());
91+
92+
const response = await agent
93+
.post(`/api/${coin}/multisig/recovery`)
94+
.set('Authorization', `Bearer ${accessToken}`)
95+
.send({
96+
userPub,
97+
backupPub,
98+
apiKey: 'etherscan-api-token',
99+
unsignedSweepPrebuildTx,
100+
walletContractAddress,
101+
coinSpecificParams: undefined,
102+
});
103+
104+
response.status.should.equal(200);
105+
response.body.should.have.property('txHex', txHexResult);
106+
107+
kmsNockUser.done();
108+
kmsNockBackup.done();
109+
});
110+
111+
it('should fail when prv keys non related to pub keys', async () => {
112+
const { userPub, backupPub, walletContractAddress } = ebeData;
113+
const unsignedSweepPrebuildTx = unsignedSweepRecJSON as unknown as any;
114+
115+
// Use invalid private keys
116+
const invalidUserPrv = 'invalid-prv';
117+
const invalidBackupPrv = 'invalid-prv';
118+
119+
const mockKmsUserResponse = {
120+
prv: invalidUserPrv,
121+
pub: userPub,
122+
source: 'user',
123+
type: 'independent',
124+
};
125+
126+
const mockKmsBackupResponse = {
127+
prv: invalidBackupPrv,
128+
pub: backupPub,
129+
source: 'backup',
130+
type: 'independent',
131+
};
132+
133+
const kmsNockUser = nock(kmsUrl)
134+
.get(`/key/${userPub}`)
135+
.query({ source: 'user' })
136+
.reply(200, mockKmsUserResponse);
137+
138+
const kmsNockBackup = nock(kmsUrl)
139+
.get(`/key/${backupPub}`)
140+
.query({ source: 'backup' })
141+
.reply(200, mockKmsBackupResponse);
142+
143+
const response = await agent
144+
.post(`/api/${coin}/multisig/recovery`)
145+
.set('Authorization', `Bearer ${accessToken}`)
146+
.send({
147+
userPub,
148+
backupPub,
149+
apiKey: 'etherscan-api-token',
150+
unsignedSweepPrebuildTx,
151+
walletContractAddress,
152+
coinSpecificParams: undefined,
153+
});
154+
155+
response.status.should.equal(500);
156+
response.body.should.have.property('error');
157+
158+
kmsNockUser.done();
159+
kmsNockBackup.done();
160+
});
161+
});

src/__tests__/mocks/ethRecoveryMusigMockData.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,17 @@ export const data = {
3636
'xpub661MyMwAqRbcGLBsaNVtc8bhB7dN8fzf3JTEKhviDUMDz11HkcHNXRSV6tk2jsqPhXnqLJPUHy8VMSjTr4hPFimRWdFk3eaLEM8VBUbZdQE',
3737
recoveryDestinationAddress: '0x927324f364a6fd1bf4648310a445b58063f5bb64',
3838
};
39+
40+
export const ebeData = {
41+
userPub:
42+
'xpub661MyMwAqRbcGvbtjkhDJ5uiFWb6eK9nFQmLLgW1jDwJzJ2vQPyp2uKLmUBgGZKiA9HDUFYfuDoyP1dF3tj3Ucod25tmiEG2k26UX97S3Wz',
43+
backupPub:
44+
'xpub661MyMwAqRbcF4KcM9ZR5gXg5M3z1gKerho5XqmQLBG1Yc72U9dvULLrcaX92RAjbkRqJvzYAmmj5Hcnts1Tdvhy9csZuiuMowuxvNHEgrn',
45+
walletContractAddress: '0x74ede0b3a0d6a3688b0c85d96e7297dae5d4a951',
46+
userPrv:
47+
'xprv9s21ZrQH143K4SXRdjACvwxyhUkcErRvtBqjYJ6QAtQL7VhmrrfZV6zrvBkFHG698ns5qicM1FS9jUwz1UqxQsungfaoMowPDw9HooBNZgw',
48+
backupPrv:
49+
'xprv9s21ZrQH143K2aF9F82QiYawXKDVcDboVUsUjTMnmqj2fomsvcKfvY2NmHXgSdqPZrG8vwPDJSqBSt8Bv3sjzc9WbGdBrmWr8vfgYHDqSFH',
50+
txHexResult:
51+
'02f901d5824268808502540be4008504a817c80083030d409474ede0b3a0d6a3688b0c85d96e7297dae5d4a95180b9016439125215000000000000000000000000927324f364a6fd1bf4648310a445b58063f5bb64000000000000000000000000000000000000000000000000053444835ec5800000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000006867cba3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004110b2f41b55a981d21efdfe04cff1426fd45d0061bda22f1ff01d589a54baf1b3034cfdf164410a28b0f768fe452cc1568dcc18601891fc08b3b854c7f0ddb4791b00000000000000000000000000000000000000000000000000000000000000c001a002f5ff1cc3b49dedf2cc0f8f3c811175eb2fb9d4aa4ea1422342c08604459d98a0368b6909b10c80da2b3b3ef04670c02d02f79fb63e287ba6e7e6cb4b32809f57',
52+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"tx": "02f90135824268808502540be4008504a817c80083030d409474ede0b3a0d6a3688b0c85d96e7297dae5d4a95180b9010439125215000000000000000000000000927324f364a6fd1bf4648310a445b58063f5bb64000000000000000000000000000000000000000000000000053444835ec5800000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000006867cba3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0808080",
3+
"userKey": "xpub661MyMwAqRbcGvbtjkhDJ5uiFWb6eK9nFQmLLgW1jDwJzJ2vQPyp2uKLmUBgGZKiA9HDUFYfuDoyP1dF3tj3Ucod25tmiEG2k26UX97S3Wz",
4+
"backupKey": "xpub661MyMwAqRbcF4KcM9ZR5gXg5M3z1gKerho5XqmQLBG1Yc72U9dvULLrcaX92RAjbkRqJvzYAmmj5Hcnts1Tdvhy9csZuiuMowuxvNHEgrn",
5+
"coin": "hteth",
6+
"gasPrice": "20000000000",
7+
"gasLimit": "200000",
8+
"recipients": [
9+
{
10+
"address": "0x927324f364a6fd1bf4648310a445b58063f5bb64",
11+
"amount": "375000000000000000"
12+
}
13+
],
14+
"walletContractAddress": "0x74ede0b3a0d6a3688b0c85d96e7297dae5d4a951",
15+
"amount": "375000000000000000",
16+
"backupKeyNonce": 0,
17+
"eip1559": {
18+
"maxFeePerGas": 20000000000,
19+
"maxPriorityFeePerGas": 10000000000
20+
},
21+
"replayProtectionOptions": {
22+
"chain": 17000,
23+
"hardfork": "london"
24+
},
25+
"recipient": {
26+
"address": "0x927324f364a6fd1bf4648310a445b58063f5bb64",
27+
"amount": "375000000000000000"
28+
},
29+
"expireTime": 1751632803,
30+
"contractSequenceId": 1,
31+
"nextContractSequenceId": 1
32+
}

0 commit comments

Comments
 (0)