Skip to content

Commit b31a41d

Browse files
committedJul 12, 2022
Support signTypedData
1 parent 50173f9 commit b31a41d

14 files changed

+755
-257
lines changed
 

‎.editorconfig

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ indent_size = 4
1414

1515
[*.js]
1616
indent_size = 4
17+
quote_type = single
1718

1819
[*.html]
1920
indent_size = 4

‎README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ In order to contribute you can
172172

173173
## Recent History
174174

175+
__4.3.0__
176+
- Support `signTypedData`
177+
175178
__4.2.0__
176179
- Add the name key when the `call()` and `send()` methods has only one return value
177180
- Optimize the `TriggerConstantContract()` method
@@ -279,7 +282,7 @@ __2.5.4__
279282
* Adds cache in Trx to cache Contracts locally and make the process more efficient
280283

281284
__2.5.2__
282-
* Adds static methods `Trx.signString` and `Trx.verifySignature
285+
* Adds static methods `Trx.signString` and `Trx.verifySignature`
283286

284287
__2.5.0__
285288
* Allows freeBandwidth, freeBandwidthLimit, frozenAmount and frozenDuration to be zero

‎karma.conf.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const basePlugins = [
1111
'source-map-support'
1212
];
1313

14-
const files = globby.sync([ 'test/**/*.test.js', '!test/**/abi.test.js' ]);
14+
const files = globby.sync([ 'test/**/*.test.js', '!test/**/abi.test.js', '!test/**/typedData.test.js' ]);
1515

1616
module.exports = function (config) {
1717
config.set({

‎package-lock.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tronweb",
3-
"version": "4.2.0",
3+
"version": "4.3.0",
44
"description": "JavaScript SDK that encapsulates the TRON HTTP API",
55
"main": "dist/TronWeb.node.js",
66
"scripts": {

‎src/lib/trx.js

+52
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,37 @@ export default class Trx {
647647
return base58Address == TronWeb.address.fromHex(address);
648648
}
649649

650+
verifyTypedData(domain, types, value, signature, address = this.tronWeb.defaultAddress.base58, callback = false) {
651+
if (utils.isFunction(address)) {
652+
callback = address;
653+
address = this.tronWeb.defaultAddress.base58;
654+
}
655+
656+
if (!callback)
657+
return this.injectPromise(this.verifyTypedData, domain, types, value, signature, address);
658+
659+
if (Trx.verifyTypedData(domain, types, value, signature, address))
660+
return callback(null, true);
661+
662+
callback('Signature does not match');
663+
}
664+
665+
static verifyTypedData(domain, types, value, signature, address) {
666+
signature = signature.replace(/^0x/, '');
667+
668+
const messageDigest = utils.TypedDataEncoder.hash(domain, types, value);
669+
const recovered = recoverAddress(messageDigest, {
670+
recoveryParam: signature.substring(128, 130) == '1c' ? 1 : 0,
671+
r: '0x' + signature.substring(0, 64),
672+
s: '0x' + signature.substring(64, 128),
673+
});
674+
675+
const tronAddress = ADDRESS_PREFIX + recovered.substr(2);
676+
const base58Address = TronWeb.address.fromHex(tronAddress);
677+
678+
return base58Address == TronWeb.address.fromHex(address);
679+
}
680+
650681
async sign(transaction = false, privateKey = this.tronWeb.defaultPrivateKey, useTronHeader = true, multisig = false, callback = false) {
651682

652683
if (utils.isFunction(multisig)) {
@@ -732,6 +763,27 @@ export default class Trx {
732763
return signatureHex
733764
}
734765

766+
signTypedData(domain, types, value, privateKey = this.tronWeb.defaultPrivateKey, callback = false) {
767+
if (utils.isFunction(privateKey)) {
768+
callback = privateKey;
769+
privateKey = this.tronWeb.defaultPrivateKey;
770+
}
771+
772+
if (!callback)
773+
return this.injectPromise(this.signTypedData, domain, types, value, privateKey);
774+
775+
try {
776+
const signatureHex = Trx.signTypedData(domain, types, value, privateKey);
777+
return callback(null, signatureHex);
778+
} catch (ex) {
779+
callback(ex);
780+
}
781+
}
782+
783+
static signTypedData(domain, types, value, privateKey) {
784+
return utils.crypto.signTypedData(domain, types, value, privateKey);
785+
}
786+
735787
async multiSign(transaction = false, privateKey = this.tronWeb.defaultPrivateKey, permissionId = false, callback = false) {
736788

737789
if (utils.isFunction(permissionId)) {

‎src/utils/crypto.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import {base64DecodeFromString, hexStr2byteArray} from './code';
44
import {encode58, decode58} from './base58';
55
import {byte2hexStr, byteArray2hexStr} from './bytes';
66
import {ec as EC} from 'elliptic';
7-
import {keccak256, sha256} from './ethersUtils';
7+
import {keccak256, sha256, SigningKey} from './ethersUtils';
8+
import {TypedDataEncoder} from './typedData';
89

910
export function getBase58CheckAddress(addressBytes) {
1011
const hash0 = SHA256(addressBytes);
@@ -76,6 +77,26 @@ export function signBytes(privateKey, contents) {
7677
return signBytes;
7778
}
7879

80+
export function signTypedData(domain, types, value, privateKey) {
81+
const key = {
82+
toHexString: function () {
83+
return '0x' + privateKey;
84+
},
85+
value: privateKey,
86+
};
87+
const signingKey = new SigningKey(key);
88+
89+
const messageDigest = TypedDataEncoder.hash(domain, types, value);
90+
const signature = signingKey.signDigest(messageDigest);
91+
const signatureHex = [
92+
'0x',
93+
signature.r.substring(2),
94+
signature.s.substring(2),
95+
Number(signature.v).toString(16),
96+
].join('');
97+
return signatureHex;
98+
}
99+
79100
export function getRowBytesFromTransactionBase64(base64Data) {
80101
const bytesDecode = base64DecodeFromString(base64Data);
81102
const transaction = proto.protocol.Transaction.deserializeBinary(bytesDecode);

‎src/utils/ethersUtils.js

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const AbiCoder = utils.AbiCoder;
1010
const Interface = utils.Interface;
1111
const FormatTypes = utils.FormatTypes;
1212
const arrayify = utils.arrayify;
13+
const splitSignature = utils.splitSignature;
14+
const joinSignature = utils.joinSignature;
1315

1416
export {
1517
keccak256,
@@ -21,5 +23,7 @@ export {
2123
AbiCoder,
2224
Interface,
2325
FormatTypes,
26+
splitSignature,
27+
joinSignature,
2428
arrayify
2529
};

‎src/utils/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as crypto from './crypto';
55
import * as code from './code';
66
import * as abi from './abi';
77
import * as ethersUtils from './ethersUtils';
8+
import {TypedDataEncoder} from './typedData'
89

910
import validator from 'validator';
1011
import BigNumber from 'bignumber.js';
@@ -150,5 +151,6 @@ export default {
150151
bytes,
151152
crypto,
152153
abi,
154+
TypedDataEncoder,
153155
ethersUtils
154156
};

0 commit comments

Comments
 (0)