PHP WebShell
Текущая директория: /opt/BitGoJS/modules/bitgo/test/v2/unit
Просмотр файла: pendingApproval.ts
/**
* @prettier
*/
import 'should';
import * as nock from 'nock';
import * as sinon from 'sinon';
import { TestableBG, TestBitGo } from '@bitgo/sdk-test';
import { BitGo } from '../../../src';
import {
BaseCoin,
ECDSAUtils,
EddsaUtils,
Environments,
PendingApproval,
PendingApprovalData,
PendingApprovalInfo,
RequestTracer,
SignatureShareType,
State,
TssUtils,
TxRequest,
Type,
Wallet,
} from '@bitgo/sdk-core';
describe('Pending Approvals:', () => {
let sandbox: sinon.SinonSandbox;
let bitgo: TestableBG & BitGo;
let basecoin: BaseCoin;
let wallet: Wallet;
let bgUrl: string;
const coin = 'tbtc';
const walletId = 'wallet_id';
const pendingApprovalData: PendingApprovalData = {
id: 'pa0',
info: {
type: Type.TRANSACTION_REQUEST,
transactionRequest: {
coinSpecific: {
[coin]: {},
},
recipients: [],
buildParams: {
type: 'consolidate',
},
sourceWallet: walletId,
},
},
state: State.PENDING,
creator: 'test',
};
const walletData = {
id: walletId,
coin,
pendingApprovals: [pendingApprovalData],
};
beforeEach(function () {
sandbox = sinon.createSandbox();
nock.disableNetConnect();
});
afterEach(function () {
sandbox.restore();
});
before(async () => {
// create wallet
bitgo = TestBitGo.decorate(BitGo, { env: 'mock' });
bitgo.initializeTestVars();
basecoin = bitgo.coin(coin);
wallet = new Wallet(bitgo, basecoin, walletData);
bgUrl = Environments[bitgo.getEnv()].uri;
(pendingApprovalData as any).wallet = wallet;
});
['tsol', 'teth', 'tbtc'].forEach((coinName) => {
it(`should use correct tssUtils for ${coinName}`, () => {
const coin = bitgo.coin(coinName);
const pendingAproval = new PendingApproval(bitgo, coin, {} as unknown as PendingApprovalData);
if (coin.supportsTss()) {
if (coin.getMPCAlgorithm() === 'ecdsa') {
pendingAproval['tssUtils'].should.be.instanceOf(ECDSAUtils.EcdsaUtils);
} else if (coin.getMPCAlgorithm() === 'eddsa') {
pendingAproval['tssUtils'].should.be.instanceOf(EddsaUtils);
}
} else {
(pendingAproval['tssUtils'] === undefined).should.be.true();
}
});
});
['MPCv2', undefined].forEach((multisigTypeVersion) => {
it(`should use correct tssUtils for multisigTypeVersion: ${multisigTypeVersion}`, () => {
const coin = bitgo.coin('hteth');
const walletDataMpcV2 = {
...walletData,
multisigTypeVersion: multisigTypeVersion,
};
const walletMPCv2 = new Wallet(bitgo, basecoin, walletDataMpcV2);
const pendingAproval = new PendingApproval(bitgo, coin, {} as unknown as PendingApprovalData, walletMPCv2);
if (walletMPCv2.multisigTypeVersion() === 'MPCv2') {
pendingAproval['tssUtils'].should.be.instanceOf(ECDSAUtils.EcdsaMPCv2Utils);
} else {
pendingAproval['tssUtils'].should.be.instanceOf(ECDSAUtils.EcdsaUtils);
}
});
});
it('should call consolidate instead of build when rebuilding consolidation pending approvals', async () => {
const scope = nock(bgUrl).post(`/api/v2/${coin}/wallet/${walletId}/consolidateUnspents`).reply(200);
const pendingApprovals = wallet.pendingApprovals();
pendingApprovals.should.have.length(1);
const pendingApproval = pendingApprovals[0];
// approval will fail when attempting to resign. This is ok - we just want to make sure
// the consolidateUnspents endpoint was called already before failing
await pendingApproval.approve({ xprv: 'nonsense' }).should.be.rejected();
scope.done();
});
it('should approve for transactionRequestLite if we cannot recreate transaction', async () => {
const pendingApprovalData2 = { ...pendingApprovalData, txRequestId: '1234-4567-6789' };
const pendingApproval = new PendingApproval(bitgo, basecoin, pendingApprovalData2, wallet);
const paScope = nock(bgUrl)
.put(`/api/v2/${coin}/pendingapprovals/${pendingApprovalData.id}`, {
state: 'approved',
otp: undefined,
})
.reply(200, {
...pendingApprovalData2,
state: 'approved',
});
const recreateTransactionTssStub = sandbox.stub(PendingApproval.prototype, 'recreateAndSignTSSTransaction');
const recreateTransactionStub = sandbox.stub(PendingApproval.prototype, 'recreateAndSignTransaction');
pendingApproval.type().should.equal(Type.TRANSACTION_REQUEST);
await pendingApproval.approve({});
recreateTransactionTssStub.notCalled.should.be.true();
recreateTransactionStub.notCalled.should.be.true();
paScope.isDone().should.be.true();
});
function testRecreateTransaction(coinName: string, recreateTransaction: boolean, type: Type) {
it(`[${coinName}] should ${
recreateTransaction ? 'not ' : ''
}recreate the transaction during approving a pending approval if there are no recipients for PA type ${type}`, async () => {
const coin = bitgo.coin(coinName);
const txRequestId = coin.supportsTss() ? 'requestTxIdTest' : undefined;
const pendingApprovalInfo =
type === 'transactionRequest'
? {
type,
transactionRequest: {
coinSpecific: {
[coinName]: { txHex: 'gabagool' },
},
recipients: [],
buildParams: {},
sourceWallet: walletId,
},
}
: ({ type } as unknown as PendingApprovalInfo);
const pendingApprovalDataTemp: PendingApprovalData = {
id: 'pa0',
info: pendingApprovalInfo,
wallet: walletId,
state: State.PENDING,
creator: 'test',
txRequestId,
};
const walletDataTemp = {
id: walletId,
coinName,
pendingApprovals: [pendingApprovalDataTemp],
};
const walletTemp = new Wallet(bitgo, coin, walletDataTemp);
pendingApprovalDataTemp.wallet = walletTemp.id();
const pendingApprovals = walletTemp.pendingApprovals();
pendingApprovals.should.have.length(1);
const pendingApproval = pendingApprovals[0];
let stub: sinon.SinonStub;
if (coin.supportsTss()) {
stub = sandbox.stub(PendingApproval.prototype, 'recreateAndSignTSSTransaction').resolves({
txHex: 'gabagool',
});
} else {
stub = sandbox.stub(PendingApproval.prototype, 'recreateAndSignTransaction').resolves({
state: 'approved',
halfSigned: { txHex: 'gabagool' },
});
}
const paScope = nock(bgUrl)
.put(`/api/v2/${coinName}/pendingapprovals/${pendingApprovalDataTemp.id}`, {
state: 'approved',
halfSigned: type === Type.TRANSACTION_REQUEST ? { txHex: 'gabagool' } : undefined,
})
.reply(200, {
...pendingApprovalDataTemp,
state: 'approved',
});
await pendingApproval.approve({ xprv: 'nonsense', walletPassphrase: 'gabagoolio' });
// Should not call build and should call pa
paScope.isDone().should.be.true();
stub.calledOnce.should.equal(recreateTransaction);
});
}
testRecreateTransaction('tbtc', false, Type.TRANSACTION_REQUEST);
testRecreateTransaction('tsol', true, Type.TRANSACTION_REQUEST);
testRecreateTransaction('tsol', true, Type.TRANSACTION_REQUEST_FULL);
testRecreateTransaction('teth', true, Type.TRANSACTION_REQUEST_FULL);
describe('recreateAndSignTSSTransaction', function () {
let coin: BaseCoin;
before(() => {
coin = bitgo.coin('tsol');
});
it('should call approve and do the TSS flow and fail if the txRequestId is missing', async () => {
const pendingApproval = wallet.pendingApprovals()[0];
const reqId = new RequestTracer();
const params = { walletPassphrase: 'test' };
await pendingApproval
.recreateAndSignTSSTransaction(params, reqId)
.should.be.rejectedWith('txRequestId not found');
});
it('should call approve and do the TSS flow and fail if the walletPassphrase is missing', async () => {
const pendingApproval = wallet.pendingApprovals()[0];
pendingApprovalData['txRequestId'] = 'requestTxIdTest';
const reqId = new RequestTracer();
const params = {};
await pendingApproval
.recreateAndSignTSSTransaction(params, reqId)
.should.be.rejectedWith('walletPassphrase not found');
});
it('should call approve and do the TSS flow and fail if the wallet is missing', async () => {
const pendingApproval = new PendingApproval(bitgo, coin, pendingApprovalData);
const reqId = new RequestTracer();
const params = { walletPassphrase: 'test' };
await pendingApproval.recreateAndSignTSSTransaction(params, reqId).should.be.rejectedWith('Wallet not found');
});
it('should get txHex for transactionRequestLite', async () => {
pendingApprovalData['txRequestId'] = 'requestTxIdTest';
const pendingApproval = new PendingApproval(bitgo, coin, pendingApprovalData, wallet);
const reqId = new RequestTracer();
const txRequestId = 'test';
const walletPassphrase = 'test';
const decryptedPrvResponse = 'decryptedPrv';
const params = { txRequestId, walletPassphrase };
const txRequest: TxRequest = {
apiVersion: 'lite',
txRequestId: txRequestId,
unsignedTxs: [{ signableHex: 'randomhex', serializedTxHex: 'randomhex2', derivationPath: 'm/0' }],
signatureShares: [
{
from: SignatureShareType.BITGO,
to: SignatureShareType.USER,
share: '9d7159a76700635TEST',
},
],
transactions: [],
userId: 'userId',
date: new Date().toISOString(),
intent: {
intentType: 'payment',
},
latest: true,
walletId: 'walletId',
version: 1,
policiesChecked: false,
walletType: 'hot',
state: 'pendingUserSignature',
};
const decryptedPrv = sandbox.stub(Wallet.prototype, 'getPrv');
decryptedPrv.calledOnceWithExactly({ walletPassphrase });
decryptedPrv.resolves(decryptedPrvResponse);
const recreateTxRequest = sandbox.stub(TssUtils.prototype, 'recreateTxRequest');
recreateTxRequest.calledOnceWithExactly(txRequest.txRequestId, decryptedPrvResponse, reqId);
recreateTxRequest.resolves(txRequest);
const recreatedTx = await pendingApproval.recreateAndSignTSSTransaction(params, reqId);
recreatedTx.should.be.deepEqual({ txHex: txRequest.unsignedTxs[0].serializedTxHex });
sandbox.verify();
});
it('should get txHex for transactionRequestFull ', async () => {
pendingApprovalData['txRequestId'] = 'requestTxIdTest';
const pendingApproval = new PendingApproval(bitgo, coin, pendingApprovalData, wallet);
const reqId = new RequestTracer();
const txRequestId = 'test';
const walletPassphrase = 'test';
const decryptedPrvResponse = 'decryptedPrv';
const params = { txRequestId, walletPassphrase };
const txRequest: TxRequest = {
txRequestId: txRequestId,
apiVersion: 'full',
unsignedTxs: [],
transactions: [
{
unsignedTx: { signableHex: 'randomhex', serializedTxHex: 'randomhex2', derivationPath: 'm/0' },
signatureShares: [
{
from: SignatureShareType.BITGO,
to: SignatureShareType.USER,
share: '9d7159a76700635TEST',
},
],
state: 'initialized',
},
],
userId: 'userId',
date: new Date().toISOString(),
intent: {
intentType: 'payment',
},
latest: true,
walletId: 'walletId',
version: 1,
policiesChecked: false,
walletType: 'hot',
state: 'pendingDelivery',
};
const decryptedPrv = sandbox.stub(Wallet.prototype, 'getPrv');
decryptedPrv.calledOnceWithExactly({ walletPassphrase });
decryptedPrv.resolves(decryptedPrvResponse);
const recreateTxRequest = sandbox.stub(TssUtils.prototype, 'recreateTxRequest');
recreateTxRequest.calledOnceWithExactly(txRequest.txRequestId, decryptedPrvResponse, reqId);
recreateTxRequest.resolves(txRequest);
const recreatedTx = await pendingApproval.recreateAndSignTSSTransaction(params, reqId);
recreatedTx.should.be.deepEqual({ txHex: txRequest.transactions![0].unsignedTx.serializedTxHex });
sandbox.verify();
});
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!