Skip to content

Commit 81a1f68

Browse files
Merge pull request #6212 from BitGo/WIN-5158
refactor(sdk-coin-icp): replace Utils class usage with direct utils import in transaction-related files
2 parents 76dd8c7 + 7923d9c commit 81a1f68

File tree

8 files changed

+129
-177
lines changed

8 files changed

+129
-177
lines changed

modules/sdk-coin-icp/src/lib/icpAgent.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
import { Principal } from '@dfinity/principal';
22
import { HttpAgent, replica, AgentCanister } from 'ic0';
3-
import { Utils } from './utils';
3+
import utils from './utils';
44
import { ACCOUNT_BALANCE_CALL, LEDGER_CANISTER_ID, ICRC1_FEE_KEY, METADATA_CALL, DEFAULT_SUBACCOUNT } from './iface';
55
import BigNumber from 'bignumber.js';
66

77
export class IcpAgent {
8-
private readonly utils: Utils;
98
private readonly host: string;
109

1110
constructor(host: string) {
1211
this.host = host;
13-
this.utils = new Utils();
1412
}
1513

1614
/**
@@ -54,7 +52,7 @@ export class IcpAgent {
5452
const ledger = this.getLedger();
5553
const account = {
5654
owner: Principal.fromText(principalId),
57-
subaccount: [this.utils.hexToBytes(DEFAULT_SUBACCOUNT)],
55+
subaccount: [utils.hexToBytes(DEFAULT_SUBACCOUNT)],
5856
};
5957

6058
const balance = await ledger.call(ACCOUNT_BALANCE_CALL, account);

modules/sdk-coin-icp/src/lib/transaction.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
PERMITTED_DRIFT,
2626
RawTransaction,
2727
} from './iface';
28-
import { Utils } from './utils';
28+
import utils from './utils';
2929

3030
export class Transaction extends BaseTransaction {
3131
protected _icpTransactionData: IcpTransactionData;
@@ -34,11 +34,9 @@ export class Transaction extends BaseTransaction {
3434
protected _signedTransaction: string;
3535
protected _signaturePayload: Signatures[];
3636
protected _createdTimestamp: number | bigint | undefined;
37-
protected _utils: Utils;
3837

39-
constructor(_coinConfig: Readonly<CoinConfig>, utils: Utils) {
38+
constructor(_coinConfig: Readonly<CoinConfig>) {
4039
super(_coinConfig);
41-
this._utils = utils;
4240
}
4341

4442
get icpTransactionData(): IcpTransactionData {
@@ -112,7 +110,7 @@ export class Transaction extends BaseTransaction {
112110
memo: parsedTx.metadata.memo,
113111
};
114112

115-
this._utils.validateRawTransaction(this._icpTransactionData);
113+
utils.validateRawTransaction(this._icpTransactionData);
116114
this._id = this.generateTransactionId();
117115
break;
118116
default:
@@ -195,7 +193,7 @@ export class Transaction extends BaseTransaction {
195193
*/
196194
explainTransferTransaction(explanationResult: IcpTransactionExplanation): IcpTransactionExplanation {
197195
explanationResult.fee = { fee: this.icpTransactionData.fee };
198-
const recipients = this._utils.getRecipients(this.icpTransactionData);
196+
const recipients = utils.getRecipients(this.icpTransactionData);
199197
const outputs: TransactionRecipient[] = [recipients];
200198
const outputAmountBN = recipients.amount;
201199
const outputAmount = outputAmountBN.toString();
@@ -220,9 +218,7 @@ export class Transaction extends BaseTransaction {
220218
}
221219

222220
async parseUnsignedTransaction(rawTransaction: string): Promise<ParsedTransaction> {
223-
const unsignedTransaction = this._utils.cborDecode(
224-
this._utils.blobFromHex(rawTransaction)
225-
) as CborUnsignedTransaction;
221+
const unsignedTransaction = utils.cborDecode(utils.blobFromHex(rawTransaction)) as CborUnsignedTransaction;
226222
const update = unsignedTransaction.updates[0];
227223
const httpCanisterUpdate = (update as unknown as [string, HttpCanisterUpdate])[1];
228224
httpCanisterUpdate.ingress_expiry = BigInt(unsignedTransaction.ingress_expiries[0]);
@@ -233,15 +229,15 @@ export class Transaction extends BaseTransaction {
233229
httpCanisterUpdate: HttpCanisterUpdate,
234230
isSigned: boolean
235231
): Promise<ParsedTransaction> {
236-
const senderPrincipal = this._utils.convertSenderBlobToPrincipal(httpCanisterUpdate.sender);
237-
const ACCOUNT_ID_PREFIX = this._utils.getAccountIdPrefix();
232+
const senderPrincipal = utils.convertSenderBlobToPrincipal(httpCanisterUpdate.sender);
233+
const ACCOUNT_ID_PREFIX = utils.getAccountIdPrefix();
238234
const subAccount = new Uint8Array(32);
239-
const senderAccount = this._utils.getAccountIdFromPrincipalBytes(
235+
const senderAccount = utils.getAccountIdFromPrincipalBytes(
240236
ACCOUNT_ID_PREFIX,
241237
Buffer.from(senderPrincipal.buffer),
242238
subAccount
243239
);
244-
const args = await this._utils.fromArgs(httpCanisterUpdate.arg);
240+
const args = await utils.fromArgs(httpCanisterUpdate.arg);
245241
const senderOperation: IcpOperation = {
246242
type: OperationType.TRANSACTION,
247243
account: { address: senderAccount },
@@ -294,7 +290,7 @@ export class Transaction extends BaseTransaction {
294290
}
295291

296292
async parseSignedTransaction(rawTransaction: string): Promise<ParsedTransaction> {
297-
const signedTransaction = this._utils.cborDecode(this._utils.blobFromHex(rawTransaction));
293+
const signedTransaction = utils.cborDecode(utils.blobFromHex(rawTransaction));
298294
const httpCanisterUpdate = (signedTransaction as UpdateEnvelope).content as HttpCanisterUpdate;
299295
httpCanisterUpdate.ingress_expiry = BigInt((signedTransaction as UpdateEnvelope).content.ingress_expiry);
300296
return await this.getParsedTransactionFromUpdate(httpCanisterUpdate, true);
@@ -313,7 +309,7 @@ export class Transaction extends BaseTransaction {
313309
* @returns {string} The generated transaction ID.
314310
*/
315311
private generateTransactionId(): string {
316-
const id = this._utils.getTransactionId(
312+
const id = utils.getTransactionId(
317313
this.unsignedTransaction,
318314
this.icpTransactionData.senderAddress,
319315
this.icpTransactionData.receiverAddress

modules/sdk-coin-icp/src/lib/transactionBuilder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
1717

1818
constructor(_coinConfig: Readonly<CoinConfig>) {
1919
super(_coinConfig);
20-
this._transaction = new Transaction(_coinConfig, utils);
20+
this._transaction = new Transaction(_coinConfig);
2121
}
2222

2323
public signaturePayload(): Signatures[] {

modules/sdk-coin-icp/src/lib/transactionBuilderFactory.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { BaseCoin as CoinConfig } from '@bitgo/statics';
33
import { Transaction } from './transaction';
44
import { TransactionBuilder } from './transactionBuilder';
55
import { TransferBuilder } from './transferBuilder';
6-
import { Utils } from './utils';
76
import { OperationType, ParsedTransaction } from './iface';
87

98
export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
@@ -13,7 +12,7 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
1312

1413
/** @inheritdoc */
1514
async from(rawTransaction: string): Promise<TransactionBuilder> {
16-
const transaction = new Transaction(this._coinConfig, new Utils());
15+
const transaction = new Transaction(this._coinConfig);
1716
await transaction.fromRawTransaction(rawTransaction);
1817
try {
1918
switch (transaction.icpTransactionData.transactionType) {
@@ -43,14 +42,14 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
4342

4443
/** @inheritdoc */
4544
getTransferBuilder(tx?: Transaction): TransferBuilder {
46-
return TransactionBuilderFactory.initializeBuilder(tx, new TransferBuilder(this._coinConfig, new Utils()));
45+
return TransactionBuilderFactory.initializeBuilder(tx, new TransferBuilder(this._coinConfig));
4746
}
4847

4948
parseTransaction(rawTransaction: string, isSigned: boolean): Promise<ParsedTransaction> {
5049
if (!rawTransaction) {
5150
throw new InvalidTransactionError('Transaction is empty');
5251
}
53-
const transaction = new Transaction(this._coinConfig, new Utils());
52+
const transaction = new Transaction(this._coinConfig);
5453
if (isSigned) {
5554
return transaction.parseSignedTransaction(rawTransaction);
5655
}

modules/sdk-coin-icp/src/lib/transferBuilder.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BaseCoin as CoinConfig } from '@bitgo/statics';
22
import { TransactionBuilder } from './transactionBuilder';
33
import { BaseTransaction, BuildTransactionError, BaseKey } from '@bitgo/sdk-core';
4-
import { Utils } from './utils';
4+
import utils from './utils';
55
import { Transaction } from './transaction';
66
import { UnsignedTransactionBuilder } from './unsignedTransactionBuilder';
77
import {
@@ -16,11 +16,8 @@ import {
1616
import assert from 'assert';
1717

1818
export class TransferBuilder extends TransactionBuilder {
19-
protected _utils: Utils;
20-
21-
constructor(_coinConfig: Readonly<CoinConfig>, utils: Utils) {
19+
constructor(_coinConfig: Readonly<CoinConfig>) {
2220
super(_coinConfig);
23-
this._utils = utils;
2421
}
2522

2623
/**
@@ -86,7 +83,7 @@ export class TransferBuilder extends TransactionBuilder {
8683
type: OperationType.FEE,
8784
account: { address: this._sender },
8885
amount: {
89-
value: this._utils.feeData(),
86+
value: utils.feeData(),
9087
currency: {
9188
symbol: this._coinConfig.family,
9289
decimals: this._coinConfig.decimalPlaces,
@@ -95,7 +92,7 @@ export class TransferBuilder extends TransactionBuilder {
9592
};
9693

9794
const createdTimestamp = this._transaction.createdTimestamp;
98-
const { metaData, ingressEndTime } = this._utils.getMetaData(this._memo, createdTimestamp, this._ingressEnd);
95+
const { metaData, ingressEndTime } = utils.getMetaData(this._memo, createdTimestamp, this._ingressEnd);
9996

10097
const icpTransaction: IcpTransaction = {
10198
public_keys: [publicKey],
@@ -106,7 +103,7 @@ export class TransferBuilder extends TransactionBuilder {
106103
senderAddress: this._sender,
107104
receiverAddress: this._receiverId,
108105
amount: this._amount,
109-
fee: this._utils.feeData(),
106+
fee: utils.feeData(),
110107
senderPublicKeyHex: this._publicKey,
111108
transactionType: OperationType.TRANSACTION,
112109
expiryTime: ingressEndTime,
@@ -119,7 +116,7 @@ export class TransferBuilder extends TransactionBuilder {
119116

120117
/** @inheritdoc */
121118
protected signImplementation(key: BaseKey): BaseTransaction {
122-
const signatures = this._utils.getSignatures(this._transaction.payloadsData, this._publicKey, key.key);
119+
const signatures = utils.getSignatures(this._transaction.payloadsData, this._publicKey, key.key);
123120
this._transaction.addSignature(signatures);
124121
return this._transaction;
125122
}

modules/sdk-coin-icp/test/unit/transaction.ts

Lines changed: 54 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,19 @@ import { Transaction } from '../../src';
22
import { coins } from '@bitgo/statics';
33
import assert from 'assert';
44
import should from 'should';
5-
import { Utils } from '../../src/lib/utils';
5+
import utils from '../../src/lib/utils';
66
import { InvalidTransactionError } from '@bitgo/sdk-core';
77
import * as testData from '../resources/icp';
88
import { getBuilderFactory } from './getBuilderFactory';
99
import sinon from 'sinon';
1010

1111
describe('ICP Transaction', () => {
1212
let tx: Transaction;
13-
let utils: Utils;
1413
let serializedTxHex: any;
1514
const config = coins.get('ticp');
1615

1716
beforeEach(() => {
18-
utils = new Utils();
19-
tx = new Transaction(config, utils);
17+
tx = new Transaction(config);
2018
const serializedTxFormat = {
2119
serializedTxHex: testData.PayloadsData,
2220
publicKey: testData.Accounts.account1.publicKey,
@@ -25,76 +23,65 @@ describe('ICP Transaction', () => {
2523
sinon.stub(utils, 'validateExpireTime').returns(true);
2624
});
2725

28-
describe('empty transaction', () => {
29-
it('should throw an empty transaction error', () => {
30-
assert.throws(
31-
() => tx.toBroadcastFormat(),
32-
(err) => err instanceof InvalidTransactionError && err.message === 'Empty transaction',
33-
'Expected an InvalidTransactionError with message "Empty transaction"'
34-
);
35-
assert.throws(
36-
() => tx.toJson(),
37-
(err) => err instanceof InvalidTransactionError && err.message === 'Empty transaction',
38-
'Expected an InvalidTransactionError with message "Empty transaction"'
39-
);
40-
});
26+
afterEach(() => {
27+
sinon.restore();
4128
});
4229

43-
describe('build a txn from init() method', () => {
44-
it('start and build a txn with builder init method', async () => {
45-
const txn = new Transaction(config, utils);
46-
txn.icpTransactionData = testData.IcpTransactionData;
47-
const factory = getBuilderFactory('ticp');
48-
const txBuilder = factory.getTransferBuilder();
49-
txBuilder.initBuilder(txn);
50-
await txBuilder.build();
30+
it('should throw an empty transaction error', () => {
31+
assert.throws(
32+
() => tx.toBroadcastFormat(),
33+
(err) => err instanceof InvalidTransactionError && err.message === 'Empty transaction',
34+
'Expected an InvalidTransactionError with message "Empty transaction"'
35+
);
36+
assert.throws(
37+
() => tx.toJson(),
38+
(err) => err instanceof InvalidTransactionError && err.message === 'Empty transaction',
39+
'Expected an InvalidTransactionError with message "Empty transaction"'
40+
);
41+
});
42+
43+
it('start and build a txn with builder init method', async () => {
44+
const txn = new Transaction(config);
45+
txn.icpTransactionData = testData.IcpTransactionData;
46+
const factory = getBuilderFactory('ticp');
47+
const txBuilder = factory.getTransferBuilder();
48+
txBuilder.initBuilder(txn);
49+
await txBuilder.build();
5150

52-
const icpTransaction = txBuilder.transaction.icpTransaction;
53-
const payloadsData = txBuilder.transaction.payloadsData;
54-
should.equal(icpTransaction.metadata.memo, testData.IcpTransactionData.memo);
55-
should.equal(icpTransaction.operations[0].account.address, testData.IcpTransactionData.senderAddress);
56-
should.equal(icpTransaction.operations[1].account.address, testData.IcpTransactionData.receiverAddress);
57-
should.equal(icpTransaction.operations[1].amount.value, testData.IcpTransactionData.amount);
58-
should.equal(icpTransaction.operations[2].amount.value, testData.IcpTransactionData.fee);
59-
should.equal(icpTransaction.public_keys[0].hex_bytes, testData.IcpTransactionData.senderPublicKeyHex);
60-
payloadsData.payloads.should.be.an.Array();
61-
payloadsData.payloads.length.should.equal(1);
62-
});
51+
const icpTransaction = txBuilder.transaction.icpTransaction;
52+
const payloadsData = txBuilder.transaction.payloadsData;
53+
should.equal(icpTransaction.metadata.memo, testData.IcpTransactionData.memo);
54+
should.equal(icpTransaction.operations[0].account.address, testData.IcpTransactionData.senderAddress);
55+
should.equal(icpTransaction.operations[1].account.address, testData.IcpTransactionData.receiverAddress);
56+
should.equal(icpTransaction.operations[1].amount.value, testData.IcpTransactionData.amount);
57+
should.equal(icpTransaction.operations[2].amount.value, testData.IcpTransactionData.fee);
58+
should.equal(icpTransaction.public_keys[0].hex_bytes, testData.IcpTransactionData.senderPublicKeyHex);
59+
payloadsData.payloads.should.be.an.Array();
60+
payloadsData.payloads.length.should.equal(1);
6361
});
6462

65-
describe('from raw transaction', () => {
66-
it('build a json transaction from raw hex', async () => {
67-
await tx.fromRawTransaction(serializedTxHex);
68-
const json = tx.toJson();
69-
should.equal(json.memo, testData.ParsedRawTransaction.metadata.memo);
70-
should.equal(json.feeAmount, testData.ParsedRawTransaction.operations[2].amount.value);
71-
should.equal(json.sender, testData.ParsedRawTransaction.operations[0].account.address);
72-
should.equal(json.recipient, testData.ParsedRawTransaction.operations[1].account.address);
73-
should.equal(json.senderPublicKey, testData.Accounts.account1.publicKey);
74-
should.equal(json.id, testData.OnChainTransactionHash);
75-
});
63+
it('build a json transaction from raw hex', async () => {
64+
await tx.fromRawTransaction(serializedTxHex);
65+
const json = tx.toJson();
66+
should.equal(json.memo, testData.ParsedRawTransaction.metadata.memo);
67+
should.equal(json.feeAmount, testData.ParsedRawTransaction.operations[2].amount.value);
68+
should.equal(json.sender, testData.ParsedRawTransaction.operations[0].account.address);
69+
should.equal(json.recipient, testData.ParsedRawTransaction.operations[1].account.address);
70+
should.equal(json.senderPublicKey, testData.Accounts.account1.publicKey);
71+
should.equal(json.id, testData.OnChainTransactionHash);
7672
});
7773

78-
describe('Explain', () => {
79-
it('explain transaction', async () => {
80-
await tx.fromRawTransaction(serializedTxHex);
81-
const explain = tx.explainTransaction();
74+
it('explain transaction', async () => {
75+
await tx.fromRawTransaction(serializedTxHex);
76+
const explain = tx.explainTransaction();
8277

83-
explain.outputAmount.should.equal('10');
84-
explain.outputs[0].amount.should.equal('10');
85-
explain.outputs[0].address.should.equal(testData.Accounts.account2.address);
86-
explain.fee.fee.should.equal('-10000');
87-
explain.changeAmount.should.equal('0');
88-
if (explain.displayOrder !== undefined) {
89-
explain.displayOrder.should.deepEqual([
90-
'id',
91-
'outputAmount',
92-
'changeAmount',
93-
'outputs',
94-
'changeOutputs',
95-
'fee',
96-
]);
97-
}
98-
});
78+
explain.outputAmount.should.equal('10');
79+
explain.outputs[0].amount.should.equal('10');
80+
explain.outputs[0].address.should.equal(testData.Accounts.account2.address);
81+
explain.fee.fee.should.equal('-10000');
82+
explain.changeAmount.should.equal('0');
83+
if (explain.displayOrder !== undefined) {
84+
explain.displayOrder.should.deepEqual(['id', 'outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee']);
85+
}
9986
});
10087
});

0 commit comments

Comments
 (0)