Skip to content

Commit

Permalink
sign typed message and updating public rpcs for tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Husienvora authored and Husienvora committed Sep 25, 2024
1 parent b0712ac commit 064ebdd
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 6 deletions.
5 changes: 4 additions & 1 deletion package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@
"@getsafle/vault-stacks-controller": "^1.0.5",
"@getsafle/vault-velas-controller": "^1.3.1",
"bip39": "^3.0.4",
"crypto": "^1.0.1",
"crypto-js": "^4.1.1",
"eth-sig-util": "^3.0.1",
"ethers": "^5.5.3",
"jest": "^29.4.3",
"limiter": "^2.1.0",
Expand Down
95 changes: 95 additions & 0 deletions src/lib/keyring.js
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,102 @@ class Keyring {
return { response: signedMessage };
}
}
async signTypedMessage(address, data, pin, encryptionKey, rpcUrl = "") {
if (
typeof pin != "string" ||
pin.match(/^[0-9]+$/) === null ||
pin < 0 ||
pin.length != 6
) {
return { error: ERROR_MESSAGE.INCORRECT_PIN_TYPE };
}

const res = await this.validatePin(pin);

if (res.response == false || res.error) {
return { error: ERROR_MESSAGE.INCORRECT_PIN };
}

const err = helper.validateEncryptionKey(
this.vault,
JSON.stringify(encryptionKey)
);

if (err.error) {
return { error: err.error };
}

const { error, response } = await this.exportPrivateKey(address, pin);

if (error) {
return { error };
}

const { privateKey, isImported } = response;

if (isImported) {
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl));

if (this.chain === "ethereum") {
const signedMessage = await this.keyringInstance.sign(
data,
privateKey,
web3
);

return { response: signedMessage.message };
}

if (Chains.evmChains.hasOwnProperty(this.chain)) {
const keyringInstance = await helper.getCoinInstance(this.chain);

const signedMessage = await keyringInstance.sign(
data,
privateKey,
web3
);

return { response: signedMessage.message };
}

if (Chains?.[this.chain]) {
const { signedMessage } = await this[this.chain].signTypedMessage(
data,
address,
privateKey
);
return { response: signedMessage };
}

return { error: ERROR_MESSAGE.UNSUPPORTED_NON_EVM_FUNCTIONALITY };
} else {
const accounts = await this.getAccounts();

if (accounts.response.filter((e) => e.address === address).length < 1) {
return { error: ERROR_MESSAGE.NONEXISTENT_KEYRING_ACCOUNT };
}

if (
Chains.evmChains.hasOwnProperty(this.chain) ||
this.chain === "ethereum"
) {
const msgParams = { from: address, data: data };

const signedMsg = await this.keyringInstance.signTypedMessage(
msgParams
);

return { response: signedMsg };
}

const { signedMessage } = await this[this.chain].signTypedMessage(
data,
address
);

return { response: signedMessage };
}
}
async signTransaction(rawTx, pin, rpcUrl) {
if (
typeof pin != "string" ||
Expand Down
120 changes: 115 additions & 5 deletions src/lib/test/keyring.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
jest.setTimeout(30000);

const crypto = require("crypto");
const assert = require("assert");
const { before } = require("lodash");
let KeyRing = require("../keyring");
let Vault = require("../vault");
const sigUtil = require("eth-sig-util");
const Web3 = require("web3");
const NETWORKS = {
ethereum: {
URL: "https://eth-goerli.public.blastapi.io",
CHAIN_ID: 5,
URL: "https://eth.llamarpc.com",
CHAIN_ID: 1,
},
bsc: {
URL: "https://data-seed-prebsc-1-s1.binance.org:8545/",
Expand All @@ -18,8 +20,8 @@ const NETWORKS = {
CHAIN_ID: 80001,
},
optimism: {
URL: "https://optimism-goerli.public.blastapi.io",
CHAIN_ID: 420,
URL: "https://optimism.llamarpc.com",
CHAIN_ID: 10,
},
arbitrum: {
URL: "https://sepolia-rollup.arbitrum.io/rpc",
Expand Down Expand Up @@ -666,6 +668,114 @@ describe("sign", () => {
});
});

describe("sign message", () => {
Object.keys(NETWORKS).forEach((chainName) => {
const networkConfig = getNetworkConfig(chainName);
vault.changeNetwork(chainName);
test(`signMessage for ${chainName}`, async () => {
const message = `Hello, eth!`;
let web3 = new Web3(networkConfig.url);
const hash = crypto.createHash("sha256").update(message).digest();
const hexData = web3.utils.toHex(hash);

const msgParams = {
from: "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd",
data: hexData,
};

const raw_sign = await vault.signMessage(
"0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd",
msgParams.data,
pin,
bufView,
ethUrl
);
console.log(raw_sign);
});
test(`signTypeMessage for ${chainName}`, async () => {
const accounts = ["0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd"];

// Ensure accounts is not empty
if (accounts.length === 0) {
throw new Error("No accounts found");
}

// console.log(accounts[0]);

let msgParams = {
from: "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd",
data: {
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: NETWORKS[chainName].CHAIN_ID,
verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
},
message: {
from: {
name: "Cow",
wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
},
to: {
name: "Bob",
wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
},
contents: "Hello, Bob!",
},
},
};

const rawSignature = await vault.signTypedMessage(
"0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd",
msgParams.data,
pin,
bufView,
networkConfig.url
);
console.log("Raw signature:", rawSignature);

// Verify the signature
msgParams = { ...msgParams.data, from: msgParams.from };
console.log();
const recoveredAddress = sigUtil.recoverTypedSignature({
data: msgParams,
sig: rawSignature.response,
});

// console.log("Recovered address:", recoveredAddress);
// console.log("Original address:", msgParams.from);

// Compare the recovered address with the original signer's address
const isSignatureValid =
recoveredAddress.toLowerCase() === msgParams.from.toLowerCase();

assert(
isSignatureValid,
`Signature verification failed for ${chainName}`
);
assert(rawSignature, `Failed to Sign Message for ${chainName}`);
});
});
});

describe("validateMnemonic", () => {
let signUpPhrase =
"join danger verb slide lava blossom garment school panel shaft damp ghost";
Expand Down

0 comments on commit 064ebdd

Please sign in to comment.