Skip to content

Commit

Permalink
Merge pull request #111 from nomiclabs/implement-local-eth-sign
Browse files Browse the repository at this point in the history
Implement local account's based eth_sign
  • Loading branch information
itirabasso committed Dec 21, 2018
2 parents 411c057 + 0d968d5 commit 2f2b14d
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 9 deletions.
20 changes: 18 additions & 2 deletions src/core/providers/accounts.ts
Expand Up @@ -23,8 +23,24 @@ export function createLocalAccountsProvider(
}

if (method === "eth_sign") {
// TODO: This should be supported before the first version
throw new Error("eth_sign is not supported yet");
const [address, data] = params;

if (address !== undefined) {
if (data === undefined) {
throw new Error("Missing data param when calling eth_sign");
}

const account = accounts.find(
acc => acc.address.toLowerCase() === address.toLowerCase()
);

if (account === undefined) {
// TODO: Throw a better error
throw new Error(address + " isn't one of the local accounts");
}

return account.sign(data).signature;
}
}

if (method === "eth_sendTransaction" && params.length > 0) {
Expand Down
124 changes: 117 additions & 7 deletions test/core/providers/accounts.ts
Expand Up @@ -12,6 +12,7 @@ import { IEthereumProvider } from "../../../src/core/providers/ethereum";

class MockProvider extends EventEmitter implements IEthereumProvider {
public transactionsCountParams: any[] | undefined = undefined;
public numberOfCallsToNetVersion: number = 0;

public async send(method: string, params?: any[]): Promise<any> {
if (method === "eth_getTransactionCount") {
Expand All @@ -20,6 +21,7 @@ class MockProvider extends EventEmitter implements IEthereumProvider {
}

if (method === "net_version") {
this.numberOfCallsToNetVersion += 1;
return 123;
}

Expand Down Expand Up @@ -61,13 +63,6 @@ describe("Local accounts provider", () => {
assert.equal(response[1], privateKeyToAddress(accounts[1]));
});

it("Should throw in eth_sign", async () => {
await expectErrorAsync(
() => wrapper.send("eth_sign"),
"eth_sign is not supported yet"
);
});

it("Should throw when calling sendTransaction without gas", async () => {
const params = [
{
Expand Down Expand Up @@ -209,6 +204,121 @@ describe("Local accounts provider", () => {
"pending"
]);
});

it("Should get the chainId if not provided, caching it", async () => {
assert.equal(mock.numberOfCallsToNetVersion, 0);

await wrapper.send("eth_sendTransaction", [
{
from: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead",
to: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead",
gas: 21000,
gasPrice: 678912,
nonce: 1,
value: 1
}
]);

assert.equal(mock.numberOfCallsToNetVersion, 1);

await wrapper.send("eth_sendTransaction", [
{
from: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead",
to: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead",
gas: 21000,
gasPrice: 678912,
nonce: 1,
value: 1
}
]);

assert.equal(mock.numberOfCallsToNetVersion, 1);
});

describe("Describe eth_sign", () => {
it("Should be compatible with parity's implementation", async () => {
// This test was created by using Parity Ethereum
// v2.2.5-beta-7fbcdfeed-20181213 and calling eth_sign

const provider = createLocalAccountsProvider(new MockProvider(), [
"0x6e59a6617c48d76d3b21d722eaba867e16ecf54ab3da7a93724f51812bc6d1aa"
]);

const result = await provider.send("eth_sign", [
"0x24f1a362780503D762060C1683864C4066A74b05",
"0x41206d657373616765"
]);

assert.equal(
result,
"0x25c349f668c90a890c84aa79a78cf6c74e96483b43ec3ed06aa8aec835477c034aa096e883cc9871aa4ffdffd9f21f6ee4aa4b70f478ad56a18971e4ec2c753e1b"
);
});

it("Should be compatible with ganache-cli's implementation", async () => {
// This test was created by using Ganache CLI v6.1.6 (ganache-core: 2.1.5)

const provider = createLocalAccountsProvider(new MockProvider(), [
"0xf159c85082f4dd4ee472583a37a1b5683c727ec99708f3d94ff05faa7a7a70ce"
]);

const result = await provider.send("eth_sign", [
"0x0a929c90dd22f0fb09ec38983780530ee30a29a3",
"0x41206d657373616765"
]);

// This test is weird because ganache encodes the v param of the signature
// differently than the rest. It subtracts 27 from it before serializing.
assert.equal(
result.slice(0, -2),
"0x84d993fc1b54926db1b6b81544aada29f0f36850a83dc979e8bacfa87e7c7cb11689b2f4ca64697842c42bb7e0cb02dff1851b42e25e62858f27f57bd00ff74b00".slice(
0,
-2
)
);
});

it("Should be compatible with geth's implementation", async () => {
// This test was created by using Geth 1.8.20-stable

const provider = createLocalAccountsProvider(new MockProvider(), [
"0xf2d19e944851ea0faa9440e24a22ddab850210cae46b306a3fde4c98b22a0dcb"
]);

const result = await provider.send("eth_sign", [
"0x5Fd8509eABccFFec1d2530e48F55545B49Bd5B5e",
"0x41206d657373616765"
]);

assert.equal(
result,
"0x88c6ac158d40e84f519fbb48b6a1355a31202b684163f637fe5c92cc1109acbe5c79a2dd95a8aecff45756c6fc3b4fc8aef345179605bcead2916dd533fb22651b"
);
});

it("Should throw if no data is given", async () => {
await expectErrorAsync(
() => wrapper.send("eth_sign", [privateKeyToAddress(accounts[0])]),
"Missing data param when calling eth_sign"
);
});

it("Should throw if the address isn't one of the local ones", async () => {
await expectErrorAsync(
() =>
wrapper.send("eth_sign", [
"0x000006d4548a3ac17d72b372ae1e416bf65b8ead",
"0x00"
]),
/isn't one of the local accounts/
);
});

it("Should just forward if no address is given", async () => {
const params = await wrapper.send("eth_sign");
assert.deepEqual(params, []);
});
});
});

describe("hdwallet provider", () => {
Expand Down

0 comments on commit 2f2b14d

Please sign in to comment.