Skip to content

Commit 0cf8c47

Browse files
Merge remote-tracking branch 'origin/HSM-850'
2 parents cd4cbb0 + cbd4d4c commit 0cf8c47

File tree

12 files changed

+223
-54
lines changed

12 files changed

+223
-54
lines changed

modules/abstract-eth/src/lib/iface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ export interface TransferData {
113113
signature: string;
114114
tokenContractAddress?: string;
115115
data?: string;
116+
operationHashPrefix?: string;
116117
}
117118

118119
export interface TokenTransferData extends TransferData {

modules/abstract-eth/src/lib/transaction.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ export class Transaction extends BaseTransaction {
6464
*
6565
* @param {TxData} txData The transaction data to set
6666
*/
67-
setTransactionData(txData: TxData): void {
67+
setTransactionData(txData: TxData, isFirstSigner?: boolean): void {
6868
this._transactionData = EthTransactionData.fromJson(txData, this._common);
69-
this.updateFields();
69+
this.updateFields(isFirstSigner);
7070
}
7171

7272
/**
7373
* Update the internal fields based on the currently set transaction data, if there is any
7474
*/
75-
protected updateFields(): void {
75+
protected updateFields(isFirstSigner?: boolean): void {
7676
if (!this._transactionData) {
7777
return;
7878
}
@@ -98,7 +98,7 @@ export class Transaction extends BaseTransaction {
9898
this._type === TransactionType.SendERC721 ||
9999
this._type === TransactionType.SendERC1155
100100
) {
101-
const { to, amount, tokenContractAddress, signature } = decodeTransferData(txData.data);
101+
const { to, amount, tokenContractAddress, signature } = decodeTransferData(txData.data, isFirstSigner);
102102
let coinName: string;
103103
if (tokenContractAddress) {
104104
const token = getToken(tokenContractAddress, this._coinConfig.network, this._coinConfig.family);
@@ -118,8 +118,9 @@ export class Transaction extends BaseTransaction {
118118
value: amount,
119119
coin: coinName,
120120
});
121-
122-
this._signatures.push(signature);
121+
if (signature !== '0x') {
122+
this._signatures.push(signature);
123+
}
123124
}
124125
}
125126

modules/abstract-eth/src/lib/transactionBuilder.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,10 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
117117

118118
this.transaction.setTransactionType(this._type);
119119
transactionData.from = this._sourceKeyPair ? this._sourceKeyPair.getAddress() : undefined;
120-
121-
this.transaction.setTransactionData(transactionData);
120+
this.transaction.setTransactionData(
121+
transactionData,
122+
this._transfer ? this._transfer.getIsFirstSigner() : undefined
123+
);
122124
// Build and sign a new transaction based on the latest changes
123125
if (this._sourceKeyPair && this._sourceKeyPair.getKeys().prv) {
124126
await this.transaction.sign(this._sourceKeyPair);
@@ -152,11 +154,11 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
152154
}
153155

154156
/** @inheritdoc */
155-
protected fromImplementation(rawTransaction: string): Transaction {
157+
protected fromImplementation(rawTransaction: string, isFirstSigner?: boolean): Transaction {
156158
let tx: Transaction;
157159
if (/^0x?[0-9a-f]{1,}$/.test(rawTransaction.toLowerCase())) {
158160
tx = Transaction.fromSerialized(this._coinConfig, this._common, rawTransaction);
159-
this.loadBuilderInput(tx.toJson());
161+
this.loadBuilderInput(tx.toJson(), isFirstSigner);
160162
} else {
161163
const txData = JSON.parse(rawTransaction);
162164
tx = new Transaction(this._coinConfig, txData);
@@ -168,8 +170,9 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
168170
* Load the builder data using the deserialized transaction
169171
*
170172
* @param {TxData} transactionJson the deserialized transaction json
173+
* @param {boolean} isFirstSigner if the transaction is being signed by the first signer
171174
*/
172-
protected loadBuilderInput(transactionJson: TxData): void {
175+
protected loadBuilderInput(transactionJson: TxData, isFirstSigner?: boolean): void {
173176
const decodedType = classifyTransaction(transactionJson.data);
174177
this.type(decodedType);
175178
this.counter(transactionJson.nonce);
@@ -195,10 +198,14 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
195198
if (hasSignature(transactionJson)) {
196199
this._txSignature = { v: transactionJson.v!, r: transactionJson.r!, s: transactionJson.s! };
197200
}
198-
this.setTransactionTypeFields(decodedType, transactionJson);
201+
this.setTransactionTypeFields(decodedType, transactionJson, isFirstSigner);
199202
}
200203

201-
protected setTransactionTypeFields(decodedType: TransactionType, transactionJson: TxData): void {
204+
protected setTransactionTypeFields(
205+
decodedType: TransactionType,
206+
transactionJson: TxData,
207+
isFirstSigner?: boolean
208+
): void {
202209
switch (decodedType) {
203210
case TransactionType.WalletInitialization:
204211
const { owners, salt } = decodeWalletCreationData(transactionJson.data);
@@ -233,7 +240,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
233240
case TransactionType.SendERC1155:
234241
case TransactionType.SendERC721:
235242
this.setContract(transactionJson.to);
236-
this._transfer = this.transfer(transactionJson.data);
243+
this._transfer = this.transfer(transactionJson.data, isFirstSigner);
237244
break;
238245
case TransactionType.AddressInitialization:
239246
this.setContract(transactionJson.to);
@@ -614,7 +621,10 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
614621
* @param [data] transfer data to initialize the transfer builder with, empty if none given
615622
* @returns {TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder} the transfer builder
616623
*/
617-
abstract transfer(data?: string): TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder;
624+
abstract transfer(
625+
data?: string,
626+
isFirstSigner?: boolean
627+
): TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder;
618628

619629
/**
620630
* Returns the serialized sendMultiSig contract method data

modules/abstract-eth/src/lib/transferBuilder.ts

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ export class TransferBuilder {
1717
protected _signKey: string | null;
1818
protected _expirationTime: number;
1919
protected _signature: string;
20+
protected _isFirstSigner: boolean | undefined;
2021
private _data: string;
2122
private _tokenContractAddress?: string;
2223
private _coin: Readonly<BaseCoin>;
2324
private _chainId?: string;
2425
private _coinUsesNonPackedEncodingForTxData?: boolean;
2526
private _walletVersion?: number;
2627

27-
constructor(serializedData?: string) {
28+
constructor(serializedData?: string, isFirstSigner?: boolean) {
29+
this._isFirstSigner = isFirstSigner;
2830
if (serializedData) {
2931
this.decodeTransferData(serializedData);
3032
} else {
@@ -51,6 +53,10 @@ export class TransferBuilder {
5153
return this;
5254
}
5355

56+
getIsFirstSigner(): boolean {
57+
return this._isFirstSigner ? this._isFirstSigner : false;
58+
}
59+
5460
walletVersion(version: number): TransferBuilder {
5561
this._walletVersion = version;
5662
return this;
@@ -103,6 +109,11 @@ export class TransferBuilder {
103109
throw new InvalidParameterValueError('Invalid expiration time');
104110
}
105111

112+
isFirstSigner(isFirstSigner: boolean): TransferBuilder {
113+
this._isFirstSigner = isFirstSigner;
114+
return this;
115+
}
116+
106117
tokenContractAddress(tokenContractAddress: string): TransferBuilder {
107118
this._tokenContractAddress = tokenContractAddress;
108119
return this;
@@ -127,24 +138,29 @@ export class TransferBuilder {
127138
this._coinUsesNonPackedEncodingForTxData =
128139
coinUsesNonPackedEncodingForTxData && this._tokenContractAddress === undefined;
129140
if (this.hasMandatoryFields()) {
130-
if (this._tokenContractAddress !== undefined) {
131-
return sendMultiSigTokenData(
132-
this._toAddress,
133-
this._amount,
134-
this._tokenContractAddress,
135-
this._expirationTime,
136-
this._sequenceId,
137-
this.getSignature()
138-
);
141+
if (this._isFirstSigner) {
142+
// First signer signs different data than the second signer in multisig evm contracts.
143+
return ethUtil.addHexPrefix(this.getSignatureData().toString('hex'));
139144
} else {
140-
return sendMultiSigData(
141-
this._toAddress,
142-
this._amount,
143-
this._data,
144-
this._expirationTime,
145-
this._sequenceId,
146-
this.getSignature()
147-
);
145+
if (this._tokenContractAddress !== undefined) {
146+
return sendMultiSigTokenData(
147+
this._toAddress,
148+
this._amount,
149+
this._tokenContractAddress,
150+
this._expirationTime,
151+
this._sequenceId,
152+
this.getSignature()
153+
);
154+
} else {
155+
return sendMultiSigData(
156+
this._toAddress,
157+
this._amount,
158+
this._data,
159+
this._expirationTime,
160+
this._sequenceId,
161+
this.getSignature()
162+
);
163+
}
148164
}
149165
}
150166
throw new BuildTransactionError(
@@ -282,7 +298,7 @@ export class TransferBuilder {
282298
}
283299

284300
private decodeTransferData(data: string): void {
285-
const transferData = decodeTransferData(data);
301+
const transferData = decodeTransferData(data, this._isFirstSigner);
286302

287303
this._toAddress = transferData.to;
288304
this._amount = transferData.amount;

modules/abstract-eth/src/lib/transferBuilders/transferBuilderERC1155.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ export class ERC1155TransferBuilder extends BaseNFTTransferBuilder {
5353
return this;
5454
}
5555

56+
getIsFirstSigner(): boolean {
57+
return false;
58+
}
59+
5660
signAndBuild(chainId: string): string {
5761
this._chainId = chainId;
5862
const hasMandatoryFields = this.hasMandatoryFields();

modules/abstract-eth/src/lib/transferBuilders/transferBuilderERC721.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ export class ERC721TransferBuilder extends BaseNFTTransferBuilder {
4343
return this;
4444
}
4545

46+
getIsFirstSigner(): boolean {
47+
return false;
48+
}
49+
4650
build(): string {
4751
const types = ERC721SafeTransferTypes;
4852
const values = [this._fromAddress, this._toAddress, this._tokenId, this._bytes];

modules/abstract-eth/src/lib/utils.ts

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ import {
7171
v4CreateForwarderMethodId,
7272
flushTokensTypesv4,
7373
flushForwarderTokensMethodIdV4,
74+
sendMultiSigTokenTypesFirstSigner,
75+
sendMultiSigTypesFirstSigner,
7476
} from './walletUtil';
7577
import { EthTransactionData } from './types';
7678

@@ -292,11 +294,11 @@ export function decodeWalletCreationData(data: string): WalletInitializationData
292294
* @param data The data to decode
293295
* @returns parsed transfer data
294296
*/
295-
export function decodeTransferData(data: string): TransferData {
297+
export function decodeTransferData(data: string, isFirstSigner?: boolean): TransferData {
296298
if (data.startsWith(sendMultisigMethodId)) {
297-
return decodeNativeTransferData(data);
299+
return decodeNativeTransferData(data, isFirstSigner);
298300
} else if (data.startsWith(sendMultisigTokenMethodId)) {
299-
return decodeTokenTransferData(data);
301+
return decodeTokenTransferData(data, isFirstSigner);
300302
} else {
301303
throw new BuildTransactionError(`Invalid transfer bytecode: ${data}`);
302304
}
@@ -306,19 +308,34 @@ export function decodeTransferData(data: string): TransferData {
306308
* Decode the given ABI-encoded transfer data for the sendMultisigToken function and return parsed fields
307309
*
308310
* @param data The data to decode
311+
* @param isFirstSigner whether transaction is being built for a first signer
309312
* @returns parsed token transfer data
310313
*/
311-
export function decodeTokenTransferData(data: string): TokenTransferData {
314+
export function decodeTokenTransferData(data: string, isFirstSigner?: boolean): TokenTransferData {
312315
if (!data.startsWith(sendMultisigTokenMethodId)) {
313316
throw new BuildTransactionError(`Invalid transfer bytecode: ${data}`);
314317
}
315-
316-
const [to, amount, tokenContractAddress, expireTime, sequenceId, signature] = getRawDecoded(
317-
sendMultiSigTokenTypes,
318-
getBufferedByteCode(sendMultisigTokenMethodId, data)
319-
);
318+
let to: RecursiveBufferOrString | undefined;
319+
let amount: RecursiveBufferOrString | undefined;
320+
let tokenContractAddress: RecursiveBufferOrString | undefined;
321+
let expireTime: RecursiveBufferOrString | undefined;
322+
let sequenceId: RecursiveBufferOrString | undefined;
323+
let signature: RecursiveBufferOrString | undefined;
324+
let prefix: RecursiveBufferOrString | undefined;
325+
if (!isFirstSigner) {
326+
[to, amount, tokenContractAddress, expireTime, sequenceId, signature] = getRawDecoded(
327+
sendMultiSigTokenTypes,
328+
getBufferedByteCode(sendMultisigTokenMethodId, data)
329+
);
330+
} else {
331+
[prefix, to, amount, tokenContractAddress, expireTime, sequenceId] = getRawDecoded(
332+
sendMultiSigTokenTypesFirstSigner,
333+
getBufferedByteCode(sendMultisigTokenMethodId, data)
334+
);
335+
}
320336

321337
return {
338+
operationHashPrefix: isFirstSigner ? (prefix as string) : undefined,
322339
to: addHexPrefix(to as string),
323340
amount: new BigNumber(bufferToHex(amount as Buffer)).toFixed(),
324341
expireTime: bufferToInt(expireTime as Buffer),
@@ -417,19 +434,35 @@ export function decodeERC1155TransferData(data: string): ERC1155TransferData {
417434
* Decode the given ABI-encoded transfer data for the sendMultisig function and return parsed fields
418435
*
419436
* @param data The data to decode
437+
* @param isFirstSigner whether transaction is being built for a first signer
420438
* @returns parsed transfer data
421439
*/
422-
export function decodeNativeTransferData(data: string): NativeTransferData {
440+
export function decodeNativeTransferData(data: string, isFirstSigner?: boolean): NativeTransferData {
423441
if (!data.startsWith(sendMultisigMethodId)) {
424442
throw new BuildTransactionError(`Invalid transfer bytecode: ${data}`);
425443
}
426444

427-
const [to, amount, internalData, expireTime, sequenceId, signature] = getRawDecoded(
428-
sendMultiSigTypes,
429-
getBufferedByteCode(sendMultisigMethodId, data)
430-
);
445+
let to: RecursiveBufferOrString | undefined;
446+
let amount: RecursiveBufferOrString | undefined;
447+
let internalData: RecursiveBufferOrString | undefined;
448+
let expireTime: RecursiveBufferOrString | undefined;
449+
let sequenceId: RecursiveBufferOrString | undefined;
450+
let signature: RecursiveBufferOrString | undefined;
451+
let prefix: RecursiveBufferOrString | undefined;
452+
if (!isFirstSigner) {
453+
[to, amount, internalData, expireTime, sequenceId, signature] = getRawDecoded(
454+
sendMultiSigTypes,
455+
getBufferedByteCode(sendMultisigMethodId, data)
456+
);
457+
} else {
458+
[prefix, to, amount, internalData, expireTime, sequenceId] = getRawDecoded(
459+
sendMultiSigTypesFirstSigner,
460+
getBufferedByteCode(sendMultisigMethodId, data)
461+
);
462+
}
431463

432464
return {
465+
operationHashPrefix: isFirstSigner ? (prefix as string) : undefined,
433466
to: addHexPrefix(to as string),
434467
amount: new BigNumber(bufferToHex(amount as Buffer)).toFixed(),
435468
expireTime: bufferToInt(expireTime as Buffer),

modules/abstract-eth/src/lib/walletUtil.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ export const flushTokensTypesv4 = ['address'];
2424
export const flushCoinsTypes = [];
2525

2626
export const sendMultiSigTypes = ['address', 'uint', 'bytes', 'uint', 'uint', 'bytes'];
27+
export const sendMultiSigTypesFirstSigner = ['string', 'address', 'uint', 'bytes', 'uint', 'uint'];
2728

2829
export const sendMultiSigTokenTypes = ['address', 'uint', 'address', 'uint', 'uint', 'bytes'];
30+
export const sendMultiSigTokenTypesFirstSigner = ['string', 'address', 'uint', 'address', 'uint', 'uint'];
2931

3032
export const ERC721SafeTransferTypes = ['address', 'address', 'uint256', 'bytes'];
3133

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class TransactionBuilder extends EthLikeTransactionBuilder {
2929
* @param [data] transfer data to initialize the transfer builder with, empty if none given
3030
* @returns {TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder} the transfer builder
3131
*/
32-
transfer(data?: string): TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder {
32+
transfer(data?: string, isFirstSigner?: boolean): TransferBuilder | ERC721TransferBuilder | ERC1155TransferBuilder {
3333
if (
3434
!(
3535
this._type === TransactionType.Send ||
@@ -40,7 +40,7 @@ export class TransactionBuilder extends EthLikeTransactionBuilder {
4040
throw new BuildTransactionError('Transfers can only be set for send transactions');
4141
} else if (!this._transfer) {
4242
if (this._type === TransactionType.Send) {
43-
this._transfer = new TransferBuilder(data);
43+
this._transfer = new TransferBuilder(data, isFirstSigner);
4444
} else if (this._type === TransactionType.SendERC721) {
4545
this._transfer = new ERC721TransferBuilder(data);
4646
} else if (this._type === TransactionType.SendERC1155) {

modules/sdk-coin-eth/test/resources/eth.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ export const CONTRACT_TOKEN_CUSD_ADDRESS = '0xa561131a1C8aC25925FB848bCa45A74aF6
9696
export const SEND_TX_BROADCAST_LEGACY =
9797
'0xf901cc02843b9aca0083b8a1a0948f977e912ef500548a0c3be6ddde9899f1199b8180b901643912521500000000000000000000000019645032c7f1533395d44a629462e751084d3e4c000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417e522e602252e010f97b81b1a83128cf283dcef2ea06c221a236c1c11883adfc222a46f4c9a6ab8cd1d5dd1e963ffa443de88c9cebf755c399702dc00b0b55d61b000000000000000000000000000000000000000000000000000000000000008284f4a0375b0731252b8a4a6f54cd3ee8078e5ba8a89168c8b9b3a49a7a3fb60984b49fa029de0bb07d891c5ad4273016055e474b0c70fa288008eadfaa16ec73b6b78427';
9898

99+
export const SEND_TX_BROADCAST_RECOVERY =
100+
'0x02f9014b824268020a648203e8948f977e912ef500548a0c3be6ddde9899f1199b8180b901253912521500000000000000000000000000000000000000000000000000000000000000c000000000000000000000000019645032c7f1533395d44a629462e751084d3e4c000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000054554484552000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0808080';
101+
99102
export const SEND_TX_BROADCAST_EIP1559 = `0x02f901d282426802830f4240840605234083b8a1a0948f977e912ef500548a0c3be6ddde9899f1199b8180b901643912521500000000000000000000000019645032c7f1533395d44a629462e751084d3e4c000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417e522e602252e010f97b81b1a83128cf283dcef2ea06c221a236c1c11883adfc222a46f4c9a6ab8cd1d5dd1e963ffa443de88c9cebf755c399702dc00b0b55d61b00000000000000000000000000000000000000000000000000000000000000c080a011efa5a61513c91c611ac1ba2ad1ed35ac90b7541f9c2bcc3fad9f14f156ee09a010be91f8e395e9fb9be5b6afbcbe7982691f149a6e5f3fc2ff5db327b03b74e0`;
100103

101104
export const SEND_TX_AMOUNT_ZERO_BROADCAST =

0 commit comments

Comments
 (0)