Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Add eth_signTypedData #149

Merged
merged 3 commits into from
Aug 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions lib/statemanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var BlockchainDouble = require("./blockchain_double.js");
var ForkedBlockchain = require("./utils/forkedblockchain.js");
var Web3 = require('web3');
var util = require("util");
var sigUtil = require('eth-sig-util')
var _ = require("lodash");

var to = require('./utils/to');
Expand Down Expand Up @@ -469,6 +470,35 @@ StateManager.prototype.sign = function(address, dataToSign) {
return utils.toRpcSig(sgn.v, sgn.r, sgn.s);
};

StateManager.prototype.signTypedData = function(address, typedDataToSign) {
var account = this.accounts[to.hex(address).toLowerCase()];
if (!account) {
throw new Error("cannot sign data; no private key");
}

if(!typedDataToSign.types) {
throw new Error("cannot sign data; types missing");
}

if(!typedDataToSign.types.EIP712Domain) {
throw new Error("cannot sign data; EIP712Domain definition missing");
}

if(!typedDataToSign.domain) {
throw new Error("cannot sign data; domain missing");
}

if(!typedDataToSign.primaryType) {
throw new Error("cannot sign data; primaryType missing");
}

if(!typedDataToSign.message) {
throw new Error("cannot sign data; message missing");
}

return sigUtil.signTypedData(account.secretKey, { data: typedDataToSign });
};

StateManager.prototype.printTransactionReceipt = function(tx_hash, error, callback){
var self = this;

Expand Down
13 changes: 13 additions & 0 deletions lib/subproviders/geth_api_double.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,19 @@ GethApiDouble.prototype.eth_sign = function(address, dataToSign, callback) {
callback(error, result);
};

GethApiDouble.prototype.eth_signTypedData = function(address, typedDataToSign, callback) {
var result;
var error;

try {
result = this.state.signTypedData(address, typedDataToSign);
} catch (e) {
error = e;
}

callback(error, result);
};

GethApiDouble.prototype.eth_sendTransaction = function(tx_data, callback) {
this.state.queueTransaction("eth_sendTransaction", tx_data, null, callback);
};
Expand Down
19 changes: 4 additions & 15 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"lib": "./lib"
},
"scripts": {
"test": "mocha --check-leaks --globals _scratch"
"test": "mocha --check-leaks --globals _scratch,sanitizedData"
},
"dependencies": {
"abstract-leveldown": "^3.0.0",
Expand All @@ -19,6 +19,7 @@
"cachedown": "^1.0.0",
"chai": "^3.5.0",
"clone": "^2.1.1",
"eth-sig-util": "^2.0.2",
"ethereumjs-account": "~2.0.4",
"ethereumjs-block": "~1.2.2",
"ethereumjs-tx": "1.3.4",
Expand Down
55 changes: 54 additions & 1 deletion test/requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,59 @@ var tests = function(web3) {

});

describe("eth_signTypedData", function() {
var accounts;
var signingWeb3;

// Account based on https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.js
var acc = {
balance: "0x00",
secretKey: web3.utils.sha3('cow')
};

// Load account.
before(function( done ){
signingWeb3 = new Web3();
signingWeb3.setProvider(Ganache.provider({
accounts: [ acc ]
}));
signingWeb3.eth.getAccounts(function(err, accs) {
if (err) return done(err);
accounts = accs.map(function(val) {
return val.toLowerCase();
});
done();
});
});

it("should produce a signature whose signer can be recovered", function(done) {
var typedData = {"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Person":[{"name":"name","type":"string"},{"name":"wallet","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person"},{"name":"contents","type":"string"}]},"primaryType":"Mail","domain":{"name":"Ether Mail","version":"1","chainId":1,"verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","wallet":"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},"contents":"Hello, Bob!"}}
var msg = utils.toBuffer("asparagus");
var msgHash = utils.hashPersonalMessage(msg);

signingWeb3.currentProvider.sendAsync({
jsonrpc: "2.0",
method: "eth_signTypedData",
params: [accounts[0], typedData],
id: new Date().getTime()
}, function(err, response) {
if (err) {
return done(err);
}
console.log(response);
assert.equal(response.result, "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c");
done();
});
});

after("shutdown", function(done) {
let provider = signingWeb3._provider;
signingWeb3.setProvider()
provider.close(done)
});

});

describe('eth_sendRawTransaction', () => {

it("should fail with bad nonce (too low)", function(done) {
Expand Down Expand Up @@ -1278,7 +1331,7 @@ describe("WebSockets Server:", function(done) {
});
server.listen(port, function(err) {
var provider = new Web3WsProvider("ws://localhost:" + port);
var Web3 = require('web3');
var Web3 = require('web3');
web3.setProvider(provider);
done();
});
Expand Down