@arkecosystem/typescript-crypto 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/identities/PrivateKey.d.ts +1 -0
- package/dist/identities/PrivateKey.d.ts.map +1 -1
- package/dist/identities/PrivateKey.js +9 -0
- package/dist/index.js +20 -0
- package/dist/transactions/builders/AbstractTransactionBuilder.d.ts +1 -0
- package/dist/transactions/builders/AbstractTransactionBuilder.d.ts.map +1 -1
- package/dist/transactions/builders/AbstractTransactionBuilder.js +7 -0
- package/dist/transactions/types/AbstractTransaction.d.ts +1 -0
- package/dist/transactions/types/AbstractTransaction.d.ts.map +1 -1
- package/dist/transactions/types/AbstractTransaction.js +8 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/TransactionUtils.d.ts.map +1 -1
- package/dist/utils/TransactionUtils.js +3 -0
- package/package.json +1 -1
- package/src/identities/PrivateKey.ts +9 -1
- package/src/transactions/builders/AbstractTransactionBuilder.ts +8 -0
- package/src/transactions/types/AbstractTransaction.ts +9 -0
- package/src/types.ts +3 -0
- package/src/utils/TransactionUtils.ts +4 -0
- package/tests/fixtures/transactions/transfer-legacy-second-signature.json +19 -0
- package/tests/unit/transactions/builders/TransferBuilder.test.ts +30 -0
@@ -11,6 +11,7 @@ export declare class PrivateKey {
|
|
11
11
|
static fromHex(hex: string): PrivateKey;
|
12
12
|
static fromWif(wif: string): PrivateKey;
|
13
13
|
sign(message: string): Promise<RecoverableSignature>;
|
14
|
+
signToEcdsa(message: string): Promise<string>;
|
14
15
|
}
|
15
16
|
export {};
|
16
17
|
//# sourceMappingURL=PrivateKey.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"PrivateKey.d.ts","sourceRoot":"","sources":["../../src/identities/PrivateKey.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAkC,MAAM,QAAQ,CAAC;AAMhE,UAAU,oBAAoB;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACV;AAED,qBAAa,UAAU;IACf,UAAU,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,CAAC,MAAM;IAIlC,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU;IAIrD,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU;IAMvC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU;IAMjC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;
|
1
|
+
{"version":3,"file":"PrivateKey.d.ts","sourceRoot":"","sources":["../../src/identities/PrivateKey.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAkC,MAAM,QAAQ,CAAC;AAMhE,UAAU,oBAAoB;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACV;AAED,qBAAa,UAAU;IACf,UAAU,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,CAAC,MAAM;IAIlC,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU;IAIrD,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU;IAMvC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU;IAMjC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAWpD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAQnD"}
|
@@ -38,4 +38,13 @@ export class PrivateKey {
|
|
38
38
|
};
|
39
39
|
});
|
40
40
|
}
|
41
|
+
signToEcdsa(message) {
|
42
|
+
return __awaiter(this, void 0, void 0, function* () {
|
43
|
+
const hash = keccak256("0x" + message).slice(2);
|
44
|
+
const signature = yield signAsync(hash, this.privateKey);
|
45
|
+
const v = signature.recovery + Constants.ETHEREUM_RECOVERY_ID_OFFSET;
|
46
|
+
// @see https://github.com/ArkEcosystem/mainsail/blob/16e50d45dcfbf15b20245f11b123634f0fd0b713/packages/utils/source/format-ecdsa-signature.ts#L2
|
47
|
+
return signature.toCompactHex() + v.toString(16).padStart(2, "0");
|
48
|
+
});
|
49
|
+
}
|
41
50
|
}
|
package/dist/index.js
CHANGED
@@ -23528,6 +23528,12 @@ var PrivateKey = class _PrivateKey {
|
|
23528
23528
|
v: signature.recovery + 27 /* ETHEREUM_RECOVERY_ID_OFFSET */
|
23529
23529
|
};
|
23530
23530
|
}
|
23531
|
+
async signToEcdsa(message) {
|
23532
|
+
const hash2 = keccak256("0x" + message).slice(2);
|
23533
|
+
const signature = await signAsync(hash2, this.privateKey);
|
23534
|
+
const v = signature.recovery + 27 /* ETHEREUM_RECOVERY_ID_OFFSET */;
|
23535
|
+
return signature.toCompactHex() + v.toString(16).padStart(2, "0");
|
23536
|
+
}
|
23531
23537
|
};
|
23532
23538
|
|
23533
23539
|
// src/identities/PublicKey.ts
|
@@ -24965,6 +24971,11 @@ var AbstractTransactionBuilder = class {
|
|
24965
24971
|
this.transaction.data.hash = this.transaction.hash();
|
24966
24972
|
return this;
|
24967
24973
|
}
|
24974
|
+
async legacySecondSign(passphrase, secondPassprase) {
|
24975
|
+
await this.sign(passphrase);
|
24976
|
+
this.transaction = await this.transaction.legacySecondSign(PrivateKey.fromPassphrase(secondPassprase));
|
24977
|
+
return this;
|
24978
|
+
}
|
24968
24979
|
verify() {
|
24969
24980
|
return this.transaction.verify();
|
24970
24981
|
}
|
@@ -24997,6 +25008,9 @@ var TransactionUtils = class {
|
|
24997
25008
|
fields.push(toBeArray(transaction["v"] - 27 /* ETHEREUM_RECOVERY_ID_OFFSET */));
|
24998
25009
|
fields.push("0x" + transaction["r"]);
|
24999
25010
|
fields.push("0x" + transaction["s"]);
|
25011
|
+
if (transaction.legacySecondSignature) {
|
25012
|
+
fields.push(`0x${transaction.legacySecondSignature}`);
|
25013
|
+
}
|
25000
25014
|
}
|
25001
25015
|
const encoded = encodeRlp(fields);
|
25002
25016
|
const payload = "02" /* EIP_1559_PREFIX */ + encoded.substring(2);
|
@@ -25040,6 +25054,11 @@ var AbstractTransaction = class {
|
|
25040
25054
|
this.data["s"] = signature.s;
|
25041
25055
|
return this;
|
25042
25056
|
}
|
25057
|
+
async legacySecondSign(privateKey) {
|
25058
|
+
const hash2 = TransactionUtils.toBuffer(this.data, true).toString("hex");
|
25059
|
+
this.data.legacySecondSignature = await privateKey.signToEcdsa(hash2);
|
25060
|
+
return this;
|
25061
|
+
}
|
25043
25062
|
recoverSender() {
|
25044
25063
|
const publicKey = this.recoverPublicKey();
|
25045
25064
|
this.data["senderPublicKey"] = publicKey.publicKey;
|
@@ -25061,6 +25080,7 @@ var AbstractTransaction = class {
|
|
25061
25080
|
"gas",
|
25062
25081
|
"nonce",
|
25063
25082
|
"senderPublicKey",
|
25083
|
+
"legacySecondSignature",
|
25064
25084
|
"to",
|
25065
25085
|
"value",
|
25066
25086
|
"data",
|
@@ -9,6 +9,7 @@ export declare abstract class AbstractTransactionBuilder<T extends ITransactionB
|
|
9
9
|
nonce(nonce: string): T;
|
10
10
|
network(network: number): T;
|
11
11
|
sign(passphrase: string): Promise<T>;
|
12
|
+
legacySecondSign(passphrase: string, secondPassprase: string): Promise<T>;
|
12
13
|
verify(): boolean;
|
13
14
|
toObject(): TransactionData;
|
14
15
|
toJson(): string;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"AbstractTransactionBuilder.d.ts","sourceRoot":"","sources":["../../../src/transactions/builders/AbstractTransactionBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAK7E,OAAO,SAAS,MAAM,cAAc,CAAC;AAErC,8BAAsB,0BAA0B,CAAC,CAAC,SAAS,mBAAmB,CAAC,CAAC,CAAC,CAAE,YAAW,mBAAmB,CAAC,CAAC,CAAC;IAC5G,WAAW,EAAE,YAAY,CAAC;gBAErB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAcnC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC;IAU/B,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC;IAMjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC;IAUzC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC;IAMvB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC;IAMrB,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;
|
1
|
+
{"version":3,"file":"AbstractTransactionBuilder.d.ts","sourceRoot":"","sources":["../../../src/transactions/builders/AbstractTransactionBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAK7E,OAAO,SAAS,MAAM,cAAc,CAAC;AAErC,8BAAsB,0BAA0B,CAAC,CAAC,SAAS,mBAAmB,CAAC,CAAC,CAAC,CAAE,YAAW,mBAAmB,CAAC,CAAC,CAAC;IAC5G,WAAW,EAAE,YAAY,CAAC;gBAErB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAcnC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC;IAU/B,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC;IAMjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC;IAUzC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC;IAMvB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC;IAMrB,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAUpC,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAQ/E,MAAM,IAAI,OAAO;IAIjB,QAAQ,IAAI,eAAe;IAI3B,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,MAAM;IAIzB,SAAS,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY;CACvF"}
|
@@ -57,6 +57,13 @@ export class AbstractTransactionBuilder {
|
|
57
57
|
return this;
|
58
58
|
});
|
59
59
|
}
|
60
|
+
legacySecondSign(passphrase, secondPassprase) {
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
62
|
+
yield this.sign(passphrase);
|
63
|
+
this.transaction = yield this.transaction.legacySecondSign(PrivateKey.fromPassphrase(secondPassprase));
|
64
|
+
return this;
|
65
|
+
});
|
66
|
+
}
|
60
67
|
verify() {
|
61
68
|
return this.transaction.verify();
|
62
69
|
}
|
@@ -8,6 +8,7 @@ export declare abstract class AbstractTransaction implements ITransaction {
|
|
8
8
|
abstract getPayload(): string;
|
9
9
|
refreshPayloadData(): ITransaction;
|
10
10
|
sign(privateKey: PrivateKey): Promise<ITransaction>;
|
11
|
+
legacySecondSign(privateKey: PrivateKey): Promise<ITransaction>;
|
11
12
|
recoverSender(): void;
|
12
13
|
verify(): boolean;
|
13
14
|
toObject(): TransactionData;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"AbstractTransaction.d.ts","sourceRoot":"","sources":["../../../src/transactions/types/AbstractTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAIxD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAKnD,8BAAsB,mBAAoB,YAAW,YAAY;IACzD,IAAI,EAAE,eAAe,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEnB,IAAI,EAAE,eAAe;aAMxB,UAAU,IAAI,MAAM;IAE7B,kBAAkB,IAAI,YAAY;IAM5B,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;
|
1
|
+
{"version":3,"file":"AbstractTransaction.d.ts","sourceRoot":"","sources":["../../../src/transactions/types/AbstractTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAIxD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAKnD,8BAAsB,mBAAoB,YAAW,YAAY;IACzD,IAAI,EAAE,eAAe,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEnB,IAAI,EAAE,eAAe;aAMxB,UAAU,IAAI,MAAM;IAE7B,kBAAkB,IAAI,YAAY;IAM5B,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAYnD,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAQrE,aAAa,IAAI,IAAI;IAOrB,MAAM,IAAI,OAAO;IAWjB,QAAQ,IAAI,eAAe;IA6B3B,MAAM,IAAI,MAAM;IAIhB,IAAI,CAAC,aAAa,UAAQ,GAAG,MAAM;IAInC,SAAS,CAAC,aAAa,UAAQ,GAAG,MAAM;IAI/C,SAAS,CAAC,gBAAgB,IAAI,SAAS;CAYvC"}
|
@@ -32,6 +32,13 @@ export class AbstractTransaction {
|
|
32
32
|
return this;
|
33
33
|
});
|
34
34
|
}
|
35
|
+
legacySecondSign(privateKey) {
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
37
|
+
const hash = TransactionUtils.toBuffer(this.data, true).toString("hex");
|
38
|
+
this.data.legacySecondSignature = yield privateKey.signToEcdsa(hash);
|
39
|
+
return this;
|
40
|
+
});
|
41
|
+
}
|
35
42
|
recoverSender() {
|
36
43
|
const publicKey = this.recoverPublicKey();
|
37
44
|
this.data["senderPublicKey"] = publicKey.publicKey;
|
@@ -53,6 +60,7 @@ export class AbstractTransaction {
|
|
53
60
|
"gas",
|
54
61
|
"nonce",
|
55
62
|
"senderPublicKey",
|
63
|
+
"legacySecondSignature",
|
56
64
|
"to",
|
57
65
|
"value",
|
58
66
|
"data",
|
package/dist/types.d.ts
CHANGED
@@ -3,6 +3,7 @@ import { Result } from "ethers";
|
|
3
3
|
export interface TransactionData {
|
4
4
|
gasPrice?: string | null;
|
5
5
|
network?: number | string | null;
|
6
|
+
legacySecondSignature?: number | string | null;
|
6
7
|
hash?: string | null;
|
7
8
|
gas?: string | null;
|
8
9
|
nonce?: number | string | null;
|
@@ -30,6 +31,7 @@ export interface ITransaction {
|
|
30
31
|
getPayload(): string;
|
31
32
|
refreshPayloadData(): ITransaction;
|
32
33
|
sign(privateKey: unknown): Promise<ITransaction>;
|
34
|
+
legacySecondSign(privateKey: unknown): Promise<ITransaction>;
|
33
35
|
recoverSender(): void;
|
34
36
|
verify(): boolean;
|
35
37
|
toObject(): TransactionData;
|
@@ -45,6 +47,7 @@ export interface ITransactionBuilder<T extends ITransactionBuilder<T>> {
|
|
45
47
|
nonce(nonce: string): T;
|
46
48
|
network(network: number): T;
|
47
49
|
sign(passphrase: string): Promise<T>;
|
50
|
+
legacySecondSign(passphrase: string, secondPassphrase: string): Promise<T>;
|
48
51
|
verify(): boolean;
|
49
52
|
toObject(): TransactionData;
|
50
53
|
toJson(): string;
|
package/dist/types.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"TransactionUtils.d.ts","sourceRoot":"","sources":["../../src/utils/TransactionUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,qBAAa,gBAAgB;WACd,QAAQ,CAAC,WAAW,EAAE,eAAe,EAAE,aAAa,UAAQ,GAAG,MAAM;
|
1
|
+
{"version":3,"file":"TransactionUtils.d.ts","sourceRoot":"","sources":["../../src/utils/TransactionUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,qBAAa,gBAAgB;WACd,QAAQ,CAAC,WAAW,EAAE,eAAe,EAAE,aAAa,UAAQ,GAAG,MAAM;WAgCrE,MAAM,CAAC,WAAW,EAAE,eAAe,EAAE,aAAa,UAAQ,GAAG,MAAM;CAKjF"}
|
@@ -20,6 +20,9 @@ export class TransactionUtils {
|
|
20
20
|
fields.push(toBeArray(transaction["v"] - Constants.ETHEREUM_RECOVERY_ID_OFFSET));
|
21
21
|
fields.push("0x" + transaction["r"]);
|
22
22
|
fields.push("0x" + transaction["s"]);
|
23
|
+
if (transaction.legacySecondSignature) {
|
24
|
+
fields.push(`0x${transaction.legacySecondSignature}`);
|
25
|
+
}
|
23
26
|
}
|
24
27
|
const encoded = encodeRlp(fields);
|
25
28
|
const payload = Constants.EIP_1559_PREFIX + encoded.substring(2);
|
package/package.json
CHANGED
@@ -37,7 +37,6 @@ export class PrivateKey {
|
|
37
37
|
|
38
38
|
async sign(message: string): Promise<RecoverableSignature> {
|
39
39
|
const hash = keccak256("0x" + message).slice(2);
|
40
|
-
|
41
40
|
const signature = await signAsync(hash, this.privateKey);
|
42
41
|
|
43
42
|
return {
|
@@ -46,4 +45,13 @@ export class PrivateKey {
|
|
46
45
|
v: signature.recovery + Constants.ETHEREUM_RECOVERY_ID_OFFSET,
|
47
46
|
};
|
48
47
|
}
|
48
|
+
|
49
|
+
async signToEcdsa(message: string): Promise<string> {
|
50
|
+
const hash = keccak256("0x" + message).slice(2);
|
51
|
+
const signature = await signAsync(hash, this.privateKey);
|
52
|
+
|
53
|
+
const v = signature.recovery + Constants.ETHEREUM_RECOVERY_ID_OFFSET;
|
54
|
+
// @see https://github.com/ArkEcosystem/mainsail/blob/16e50d45dcfbf15b20245f11b123634f0fd0b713/packages/utils/source/format-ecdsa-signature.ts#L2
|
55
|
+
return signature.toCompactHex() + v.toString(16).padStart(2, "0");
|
56
|
+
}
|
49
57
|
}
|
@@ -70,6 +70,14 @@ export abstract class AbstractTransactionBuilder<T extends ITransactionBuilder<T
|
|
70
70
|
return this as unknown as T;
|
71
71
|
}
|
72
72
|
|
73
|
+
public async legacySecondSign(passphrase: string, secondPassprase: string): Promise<T> {
|
74
|
+
await this.sign(passphrase);
|
75
|
+
|
76
|
+
this.transaction = await this.transaction.legacySecondSign(PrivateKey.fromPassphrase(secondPassprase));
|
77
|
+
|
78
|
+
return this as unknown as T;
|
79
|
+
}
|
80
|
+
|
73
81
|
public verify(): boolean {
|
74
82
|
return this.transaction.verify();
|
75
83
|
}
|
@@ -38,6 +38,14 @@ export abstract class AbstractTransaction implements ITransaction {
|
|
38
38
|
return this;
|
39
39
|
}
|
40
40
|
|
41
|
+
public async legacySecondSign(privateKey: PrivateKey): Promise<ITransaction> {
|
42
|
+
const hash = TransactionUtils.toBuffer(this.data, true).toString("hex");
|
43
|
+
|
44
|
+
this.data.legacySecondSignature = await privateKey.signToEcdsa(hash);
|
45
|
+
|
46
|
+
return this;
|
47
|
+
}
|
48
|
+
|
41
49
|
public recoverSender(): void {
|
42
50
|
const publicKey = this.recoverPublicKey();
|
43
51
|
|
@@ -64,6 +72,7 @@ export abstract class AbstractTransaction implements ITransaction {
|
|
64
72
|
"gas",
|
65
73
|
"nonce",
|
66
74
|
"senderPublicKey",
|
75
|
+
"legacySecondSignature",
|
67
76
|
"to",
|
68
77
|
"value",
|
69
78
|
"data",
|
package/src/types.ts
CHANGED
@@ -4,6 +4,7 @@ import { Result } from "ethers";
|
|
4
4
|
export interface TransactionData {
|
5
5
|
gasPrice?: string | null;
|
6
6
|
network?: number | string | null;
|
7
|
+
legacySecondSignature?: number | string | null;
|
7
8
|
hash?: string | null;
|
8
9
|
gas?: string | null;
|
9
10
|
nonce?: number | string | null;
|
@@ -36,6 +37,7 @@ export interface ITransaction {
|
|
36
37
|
getPayload(): string;
|
37
38
|
refreshPayloadData(): ITransaction;
|
38
39
|
sign(privateKey: unknown): Promise<ITransaction>;
|
40
|
+
legacySecondSign(privateKey: unknown): Promise<ITransaction>;
|
39
41
|
recoverSender(): void;
|
40
42
|
|
41
43
|
verify(): boolean;
|
@@ -54,6 +56,7 @@ export interface ITransactionBuilder<T extends ITransactionBuilder<T>> {
|
|
54
56
|
nonce(nonce: string): T;
|
55
57
|
network(network: number): T;
|
56
58
|
sign(passphrase: string): Promise<T>;
|
59
|
+
legacySecondSign(passphrase: string, secondPassphrase: string): Promise<T>;
|
57
60
|
verify(): boolean;
|
58
61
|
toObject(): TransactionData;
|
59
62
|
toJson(): string;
|
@@ -22,6 +22,10 @@ export class TransactionUtils {
|
|
22
22
|
fields.push(toBeArray(transaction["v"] - Constants.ETHEREUM_RECOVERY_ID_OFFSET));
|
23
23
|
fields.push("0x" + transaction["r"]);
|
24
24
|
fields.push("0x" + transaction["s"]);
|
25
|
+
|
26
|
+
if (transaction.legacySecondSignature) {
|
27
|
+
fields.push(`0x${transaction.legacySecondSignature}`);
|
28
|
+
}
|
25
29
|
}
|
26
30
|
|
27
31
|
const encoded = encodeRlp(fields);
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"data": {
|
3
|
+
"network": 10000,
|
4
|
+
"nonce": "1",
|
5
|
+
"gasPrice": "5000000000",
|
6
|
+
"gas": "21000",
|
7
|
+
"to": "0x6F0182a0cc707b055322CcF6d4CB6a5Aff1aEb22",
|
8
|
+
"value": "100000000",
|
9
|
+
"data": "",
|
10
|
+
"v": 28,
|
11
|
+
"r": "104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da0",
|
12
|
+
"s": "46d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a9136",
|
13
|
+
"senderPublicKey": "0243333347c8cbf4e3cbc7a96964181d02a2b0c854faa2fef86b4b8d92afcf473d",
|
14
|
+
"from": "0x1E6747BEAa5B4076a6A98D735DF8c35a70D18Bdd",
|
15
|
+
"hash": "b7927d90b38cd1296351f26145b3d8b0674fdc9b8721bc1a10f71a12bcbccf60",
|
16
|
+
"legacySecondSignature": "104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da046d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a91361c"
|
17
|
+
},
|
18
|
+
"serialized": "02f8b0822710018085012a05f200825208946f0182a0cc707b055322ccf6d4cb6a5aff1aeb228405f5e10080c001a0104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da0a046d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a9136b841104665257d4dea61c4654e74c6c0f6cd0a398905781c3040bea67dc641a66da046d718d04b2331f3b0561808549ed3f3f0d867a284acf6b334869078df7a91361c"
|
19
|
+
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import fixture from "@tests/fixtures/transactions/transfer.json";
|
2
|
+
import legacySecondSignatureFixture from "@tests/fixtures/transactions/transfer-legacy-second-signature.json";
|
2
3
|
import fixtureTransferLargeAmount from "@tests/fixtures/transactions/transfer-large-amount.json";
|
3
4
|
import identityFixture from "@tests/fixtures/identity.json";
|
4
5
|
|
@@ -50,6 +51,35 @@ it("should sign a transaction", async () => {
|
|
50
51
|
expect(transaction.verify()).toBe(true);
|
51
52
|
});
|
52
53
|
|
54
|
+
it("should build a transaction using legacy second signature", async () => {
|
55
|
+
const transaction = (
|
56
|
+
await TransferBuilder.new()
|
57
|
+
.value(legacySecondSignatureFixture.data.value)
|
58
|
+
.to(legacySecondSignatureFixture.data.to)
|
59
|
+
.nonce(legacySecondSignatureFixture.data.nonce)
|
60
|
+
.gasPrice(legacySecondSignatureFixture.data.gasPrice)
|
61
|
+
.gas(legacySecondSignatureFixture.data.gas)
|
62
|
+
.network(legacySecondSignatureFixture.data.network)
|
63
|
+
.legacySecondSign(identityFixture.passphrase, identityFixture.passphrase)
|
64
|
+
).transaction;
|
65
|
+
|
66
|
+
expect(transaction.data.gasPrice).toBe(legacySecondSignatureFixture.data.gasPrice);
|
67
|
+
expect(transaction.data.nonce).toBe(legacySecondSignatureFixture.data.nonce);
|
68
|
+
expect(transaction.data.network).toBe(legacySecondSignatureFixture.data.network);
|
69
|
+
expect(transaction.data.gas).toBe(legacySecondSignatureFixture.data.gas);
|
70
|
+
expect(transaction.data.to).toBe(legacySecondSignatureFixture.data.to);
|
71
|
+
expect(transaction.data.value).toBe(legacySecondSignatureFixture.data.value);
|
72
|
+
expect(transaction.data.v).toBe(legacySecondSignatureFixture.data.v);
|
73
|
+
expect(transaction.data.r).toBe(legacySecondSignatureFixture.data.r);
|
74
|
+
expect(transaction.data.s).toBe(legacySecondSignatureFixture.data.s);
|
75
|
+
expect(transaction.data.hash).toBe(legacySecondSignatureFixture.data.hash);
|
76
|
+
expect(transaction.data.hash).toBe(legacySecondSignatureFixture.data.hash);
|
77
|
+
expect(transaction.data.legacySecondSignature).toBe(legacySecondSignatureFixture.data.legacySecondSignature);
|
78
|
+
|
79
|
+
expect(transaction.serialize().toString("hex")).toEqual(legacySecondSignatureFixture.serialized);
|
80
|
+
expect(transaction.verify()).toBe(true);
|
81
|
+
});
|
82
|
+
|
53
83
|
it("should handle large amounts", async () => {
|
54
84
|
const transaction = (
|
55
85
|
await TransferBuilder.new()
|