diff --git a/.gitignore b/.gitignore index 29e01d2..09cc525 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,7 @@ Thumbs.db *.app *.exe *.war - +.env # Large media files *.mp4 *.tiff diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ff4ac9..c278239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -670,7 +670,9 @@ - Update BEVM controller version - Fixed validatePin function for tests -### 2.9.1 (2024-09-23) +### 2.9.2 (2024-09-23) -Integrated vault-evm-controller -Resolved issue for unarchival of a wallet +-Adding test for bitcoin +-Adding sensitive info in env github pipeline diff --git a/package-lock.json b/package-lock.json index 11af544..f2a9a52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@getsafle/safle-vault", - "version": "2.9.1", + "version": "2.9.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@getsafle/safle-vault", - "version": "2.9.0", + "version": "2.9.2", "license": "MIT", "dependencies": { "@getsafle/safle-identity-wallet": "^1.3.0", @@ -18,7 +18,7 @@ "@getsafle/vault-bitcoin-controller": "^2.0.7", "@getsafle/vault-bsc-controller": "^1.2.4", "@getsafle/vault-eth-controller": "^1.4.6", - "@getsafle/vault-evm-controller": "^1.0.0", + "@getsafle/vault-evm-controller": "^1.0.1", "@getsafle/vault-mantle-controller": "^1.0.1", "@getsafle/vault-optimism-controller": "^1.0.8", "@getsafle/vault-polygon-controller": "^1.2.8", @@ -28,7 +28,10 @@ "@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", + "dotenv": "^16.4.5", + "eth-sig-util": "^3.0.1", "ethers": "^5.5.3", "jest": "^29.4.3", "limiter": "^2.1.0", @@ -1935,9 +1938,9 @@ } }, "node_modules/@getsafle/vault-evm-controller": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@getsafle/vault-evm-controller/-/vault-evm-controller-1.0.0.tgz", - "integrity": "sha512-AHL1gJNEdMdvX7iBNNpKxXA3bm8YYggpGywJ9untiyBRwZiSVXuUMmCPbqe23me8Lk1nxyl0TLyDw33iq0SIoQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@getsafle/vault-evm-controller/-/vault-evm-controller-1.0.1.tgz", + "integrity": "sha512-dlleo03yLkLRY2jMjrNml1i2h5KvRodhqD2cN2/3xnhUbHJGCf1mTf6YhZOKlpt3dn4HcriNuxwyUyjrRGgDTg==", "license": "MIT", "dependencies": { "@ethereumjs/common": "2.6.0", @@ -6068,6 +6071,18 @@ "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/drbg.js": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", @@ -6362,6 +6377,7 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-3.0.1.tgz", "integrity": "sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==", "deprecated": "Deprecated in favor of '@metamask/eth-sig-util'", + "license": "ISC", "dependencies": { "ethereumjs-abi": "^0.6.8", "ethereumjs-util": "^5.1.1", diff --git a/package.json b/package.json index a70fe5f..f969175 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@getsafle/safle-vault", - "version": "2.9.1", + "version": "2.9.2", "description": "Safle Vault is a non-custodial, flexible and highly available crypto wallet which can be used to access dapps, send/receive crypto and store identity. Vault SDK is used to manage the vault and provide methods to generate vault, add new accounts, update the state and also enable the user to perform several vault related operations.", "main": "src/index.js", "scripts": { @@ -57,7 +57,7 @@ "@getsafle/vault-bitcoin-controller": "^2.0.7", "@getsafle/vault-bsc-controller": "^1.2.4", "@getsafle/vault-eth-controller": "^1.4.6", - "@getsafle/vault-evm-controller": "^1.0.0", + "@getsafle/vault-evm-controller": "^1.0.1", "@getsafle/vault-mantle-controller": "^1.0.1", "@getsafle/vault-optimism-controller": "^1.0.8", "@getsafle/vault-polygon-controller": "^1.2.8", @@ -67,7 +67,10 @@ "@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", + "dotenv": "^16.4.5", + "eth-sig-util": "^3.0.1", "ethers": "^5.5.3", "jest": "^29.4.3", "limiter": "^2.1.0", diff --git a/src/lib/keyring.js b/src/lib/keyring.js index c69ee68..4094d84 100644 --- a/src/lib/keyring.js +++ b/src/lib/keyring.js @@ -591,6 +591,130 @@ 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) { + if ( + Chains.evmChains.hasOwnProperty(this.chain) || + this.chain === "ethereum" + ) { + const signedMsg = await this.keyringInstance.customSignTypedMessage( + "0x" + privateKey, + data + ); + + return { response: signedMsg }; + } + return { error: ERROR_MESSAGE.UNSUPPORTED_NON_EVM_FUNCTIONALITY }; + } + + 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 personalSign(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; + + 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 signedMsg = await this.keyringInstance.customPersonalSign( + "0x" + privateKey, + data + ); + + return { response: signedMsg }; + } else { + return { error: ERROR_MESSAGE.UNSUPPORTED_NON_EVM_FUNCTIONALITY }; + } + } async signTransaction(rawTx, pin, rpcUrl) { if ( @@ -621,14 +745,13 @@ class Keyring { if (isImported) { const signedTransaction = await this.keyringInstance.signTransaction( rawTx, - web3, privateKey ); return { response: signedTransaction }; } else { const signedTx = await this.keyringInstance.signTransaction( rawTx, - web3 + privateKey ); return { response: signedTx }; } @@ -1083,7 +1206,42 @@ class Keyring { }); if (isDuplicateAddress) { - return { error: ERROR_MESSAGE.ADDRESS_ALREADY_PRESENT }; + try { + Object.keys(this.decryptedVault) + .slice(0, -1) + .forEach((chain) => { + this.decryptedVault[chain]?.public?.forEach( + (account, index) => { + if (account.address === address && account.isDeleted) { + this.decryptedVault[chain].public[ + index + ].isDeleted = false; + } + } + ); + }); + + const vault = await helper.cryptography( + JSON.stringify(this.decryptedVault), + JSON.stringify(encryptionKey), + "encryption" + ); + + this.vault = vault; + + this.logs.getState().logs.push({ + timestamp: Date.now(), + action: "import-wallet", + vault: this.vault, + chain: this.chain, + address, + }); + + return { response: { vault, address } }; + } catch (error) { + console.error("Error processing duplicate address:", error); + throw error; // or handle it as appropriate for your application + } } } diff --git a/src/lib/test/keyring.test.js b/src/lib/test/keyring.test.js index 1f33dc9..5122ad2 100644 --- a/src/lib/test/keyring.test.js +++ b/src/lib/test/keyring.test.js @@ -1,8 +1,12 @@ jest.setTimeout(30000); - +const crypto = require("crypto"); +const assert = require("assert"); const { before } = require("lodash"); let KeyRing = require("../keyring"); let Vault = require("../vault"); +require("dotenv").config(); +const helper = require("../../utils/helper"); +const sigUtil = require("eth-sig-util"); const Web3 = require("web3"); let NETWORKS = { ethereum: { @@ -68,6 +72,7 @@ const chainConfigs = { zkEVM: { symbol: "ZKEVM", txType: 2 }, bevm: { symbol: "BTC", txType: 0 }, rootstock: { symbol: "RBTC", txType: 0 }, + bitcoin: { symbol: "BTC", txType: 0 }, }; // Add the helper function @@ -88,16 +93,16 @@ const bufView = [ 105, 178, 182, 108, 174, 199, 124, 141, 155, 73, 21, 85, 81, 109, 78, 233, 152, 108, 242, 238, 192, 31, 147, 86, 174, 195, 55, 229, 4, 36, ]; -let phrase = - "fun rough treat scan glimpse region century purpose expire video remind second"; -let pin = "696969"; +let phrase = process.env.MNEMONIC; +console.log(phrase, "phrase"); +let pin = process.env.PIN; let result; let vault = new Vault({}); let vaultAddress; let privateKey; let accAddress; -let privateKeyImp = - "0x7a9633b8103fec11c9e855a6b6c8c072e9af311a69b92ab0ad8186b1fb57371f"; +let privateKeyImp = process.env.PRIVATE_KEY_EVM; +let privateKeybtcImp = process.env.PRIVATE_KEY_BTC; let impAccAddress; let chains; @@ -106,6 +111,7 @@ const polygonRpcUrl = "https://polygon.llamarpc.com"; const bscRpcUrl = "https://rpc.ankr.com/bsc"; beforeAll(async () => { result = await vault.generateVault(bufView, pin, phrase); + vaultAddress = result.response; await vault.getAccounts(bufView); }); @@ -222,43 +228,66 @@ describe("exportPrivateKey", () => { }); describe("importWallet", () => { - test("importWallet/valid import", async () => { - let result = await vault.importWallet("0x" + privateKeyImp, pin, bufView); - impAccAddress = result.response.address; - expect(result).toHaveProperty("response.address"); - }); - - test("importWallet/valid address exists already", async () => { - let result = await vault.importWallet("0x" + privateKey, pin, bufView); - expect(result.response).toHaveProperty("vault"); - }); + const evmaddresses = [process.env.EVM_ADDRESS_1, process.env.EVM_ADDRESS_2]; + const bitcoinadresses = [ + process.env.BITCOIN_ADDRESS_1, + process.env.BITCOIN_ADDRESS_2, + ]; + Object.keys(NETWORKS).map((chainName) => { + const networkConfig = getNetworkConfig(chainName); - test("importWallet/empty private key", async () => { - try { - let result = await vault.importWallet(null, pin, bufView); - } catch (e) { - expect(e.message).toBe( - "Cannot read properties of null (reading 'startsWith')" - ); + let addresses; + let impprivatekey; + if (chainName == "bitcoin") { + addresses = bitcoinadresses; + impprivatekey = privateKeybtcImp; + } else { + addresses = evmaddresses; + impprivatekey = "0x" + privateKeyImp; } - }); - test("importWallet/empty pin", async () => { - let result = await vault.importWallet("0x" + privateKey, null, bufView); - expect(result.error).toBe("Wrong pin type, format or length"); - }); - test("importWallet/incorrect pin", async () => { - let result = await vault.importWallet("0x" + privateKey, "111111", bufView); - expect(result.error).toBe("Incorrect pin"); - }); - test("importWallet/empty encryption key", async () => { - let result = await vault.importWallet("0x" + privateKey, pin, null); - expect(result.error).toBe("Incorrect Encryption Key or vault string"); - }); + test(`importWallet/valid import ${chainName}`, async () => { + let var1 = chainName; + let var2 = impprivatekey; + vault.changeNetwork(chainName); + let result = await vault.importWallet(impprivatekey, pin, bufView); + impAccAddress = result.response.address; - test("importWallet/empty all params", async () => { - let result = await vault.importWallet(null, null, null); - expect(result.error).toBe("Wrong pin type, format or length"); + expect(result).toHaveProperty("response.address"); + }); + + test("importWallet/valid address exists already", async () => { + let result = await vault.importWallet(impprivatekey, pin, bufView); + expect(result.response).toHaveProperty("vault"); + }); + + test("importWallet/empty private key", async () => { + try { + let result = await vault.importWallet(null, pin, bufView); + } catch (e) { + expect(e.message).toBe( + "Cannot read properties of null (reading 'startsWith')" + ); + } + }); + + test("importWallet/empty pin", async () => { + let result = await vault.importWallet(impprivatekey, null, bufView); + expect(result.error).toBe("Wrong pin type, format or length"); + }); + test("importWallet/incorrect pin", async () => { + let result = await vault.importWallet(impprivatekey, "111111", bufView); + expect(result.error).toBe("Incorrect pin"); + }); + test("importWallet/empty encryption key", async () => { + let result = await vault.importWallet(impprivatekey, pin, null); + expect(result.error).toBe("Incorrect Encryption Key or vault string"); + }); + + test("importWallet/empty all params", async () => { + let result = await vault.importWallet(null, null, null); + expect(result.error).toBe("Wrong pin type, format or length"); + }); }); }); @@ -520,149 +549,652 @@ describe("getBalance", () => { }); describe("updateLabel", () => { - test("updateLabel/valid", async () => { - let result = await vault.updateLabel( - "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd", - bufView, - "Wallet 1" - ); - expect(result).toHaveProperty("response"); - }); + const addresses = [process.env.EVM_ADDRESS_1, process.env.EVM_ADDRESS_2]; + addresses.forEach((address, index) => { + test(`updateLabel/valid using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + await vault.importWallet("0x" + privateKeyImp, pin, bufView); + let result = await vault.updateLabel( + address.toLowerCase(), + bufView, + "Wallet 1" + ); + expect(result).toHaveProperty("response"); + }); - test("updateLabel/invalid address", async () => { - let result = await vault.updateLabel("adeded", bufView, "Wallet 1"); - expect(result.error).toBe("This address is not present in the vault"); - }); + test(`updateLabel/invalid address using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let result = await vault.updateLabel("adeded", bufView, "Wallet 1"); + expect(result.error).toBe("This address is not present in the vault"); + }); - test("updateLabel/empty address", async () => { - let result = await vault.updateLabel(null, bufView, "Wallet 1"); - expect(result.error).toBe("This address is not present in the vault"); - }); - test("updateLabel/invalid encryption key", async () => { - let result = await vault.updateLabel( - "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd", - "afers", - "Wallet 1" - ); - expect(result.error).toBe("Incorrect Encryption Key or vault string"); - }); - test("updateLabel/empty encryption key", async () => { - let result = await vault.updateLabel( - "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd", - null, - "Wallet 1" - ); - expect(result.error).toBe("Incorrect Encryption Key or vault string"); - }); - test("updateLabel/empty label", async () => { - try { + test(`updateLabel/empty address using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let result = await vault.updateLabel(null, bufView, "Wallet 1"); + expect(result.error).toBe("This address is not present in the vault"); + }); + test(`updateLabel/invalid encryption key using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { let result = await vault.updateLabel( - "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd", - bufView, - null + address.toLowerCase(), + "afers", + "Wallet 1" ); - } catch (e) { - expect(e.message).toBe("chainName is not defined"); - } - }); - test("updateLabel/all empty params", async () => { - let result = await vault.updateLabel(null, null, null); - expect(result.error).toBe("Incorrect Encryption Key or vault string"); + expect(result.error).toBe("Incorrect Encryption Key or vault string"); + }); + test(`updateLabel/empty encryption key using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let result = await vault.updateLabel( + address.toLowerCase(), + null, + "Wallet 1" + ); + expect(result.error).toBe("Incorrect Encryption Key or vault string"); + }); + test(`updateLabel/empty label using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + try { + let result = await vault.updateLabel( + address.toLowerCase(), + bufView, + null + ); + } catch (e) { + expect(e.message).toBe("chainName is not defined"); + } + }); + test(`updateLabel/all empty params using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let result = await vault.updateLabel(null, null, null); + expect(result.error).toBe("Incorrect Encryption Key or vault string"); + }); }); }); describe("sign", () => { - test("sign/valid", async () => { - let data = "hello world"; - console.log("sign/valid--->", pin, ethUrl); - await vault.restoreKeyringState(vault, pin, bufView); - - let result = await vault.sign( - data, - "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd", - pin, - ethUrl - ); - console.log("sign/valid--->", result); - expect(result.response).toHaveProperty("signature"); - }); + const evmaddresses = [process.env.EVM_ADDRESS_1, process.env.EVM_ADDRESS_2]; + const bitcoinadresses = [ + process.env.BITCOIN_ADDRESS_1, + process.env.BITCOIN_ADDRESS_2, + ]; + Object.keys(NETWORKS) + .filter((key) => key !== "bitcoin") + .forEach((chainName) => { + const networkConfig = getNetworkConfig(chainName); - test("sign/empty data", async () => { - let data = "hello world"; - let result = await vault.sign( - "", - "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd", - pin, - ethUrl - ); - expect(result.response).toHaveProperty("signature"); - }); + let addresses; + let impprivatekey; + if (chainName == "bitcoin") { + addresses = bitcoinadresses; + impprivatekey = privateKeybtcImp; + } else { + addresses = evmaddresses; + impprivatekey = "0x" + privateKeyImp; + } + addresses.forEach((address, index) => { + test(`sign/valid for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + vault.changeNetwork(chainName); + await vault.importWallet(impprivatekey, pin, bufView); + + console.log("sign/valid--->", pin, networkConfig.url); + await vault.restoreKeyringState(vault, pin, bufView); + + let result = await vault.sign( + data, + address.toLowerCase(), + pin, + networkConfig.url + ); + console.log("sign/valid--->", result); + expect(result.response).toHaveProperty("signature"); + }); + + test(`sign/empty data for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + let result = await vault.sign( + "", + address.toLowerCase(), + pin, + networkConfig.url + ); + expect(result.response).toHaveProperty("signature"); + }); + + test(`sign/empty address for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + try { + let result = await vault.sign(data, null, pin, networkConfig.url); + } catch (e) { + expect(e.message).toBe( + "Cannot read properties of null (reading 'toLowerCase')" + ); + } + }); + test(`sign/invalid address using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + try { + let result = await vault.sign(data, "abc", pin, networkConfig.url); + } catch (e) { + expect(e.message).toBe( + 'Given address "abc" is not a valid Ethereum address.' + ); + } + }); + test(`sign/empty pin for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + + let result = await vault.sign(data, "abc", null, networkConfig.url); + expect(result.error).toBe("Wrong pin type, format or length"); + }); + test(`sign/incorrect for ${chainName} pin using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + + let result = await vault.sign( + data, + "abc", + "111111", + networkConfig.url + ); + expect(result.error).toBe("Incorrect pin"); + }); + test(`sign/invalid for ${chainName} pin using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + let result = await vault.sign( + data, + accAddress, + "abc", + networkConfig.url + ); + expect(result.error).toBe("Wrong pin type, format or length"); + }); + + test(`sign/empty for ${chainName} url using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + let result = await vault.sign(data, address.toLowerCase(), pin, null); + expect(result.response).toHaveProperty("signature"); + }); + + test(`sign/invalid url for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + let result = await vault.sign( + data, + address.toLowerCase(), + pin, + "abc" + ); + expect(result.response).toHaveProperty("signature"); + }); + + test(`sign/all params empty for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let data = "hello world"; + + let result = await vault.sign(null, null, null, null); + expect(result.error).toBe("Wrong pin type, format or length"); + }); + }); + }); +}); - test("sign/empty address", async () => { - let data = "hello world"; - try { - let result = await vault.sign(data, null, pin, ethUrl); - } catch (e) { - expect(e.message).toBe( - "Cannot read properties of null (reading 'toLowerCase')" - ); - } - }); - test("sign/invalid address", async () => { - let data = "hello world"; - try { - let result = await vault.sign(data, "abc", pin, ethUrl); - } catch (e) { - expect(e.message).toBe( - 'Given address "abc" is not a valid Ethereum address.' - ); - } - }); - test("sign/empty pin", async () => { - let data = "hello world"; +describe("sign message", () => { + const evmaddresses = [process.env.EVM_ADDRESS_1, process.env.EVM_ADDRESS_2]; + const bitcoinadresses = [ + process.env.BITCOIN_ADDRESS_1, + process.env.BITCOIN_ADDRESS_2, + ]; + Object.keys(NETWORKS).forEach(async (chainName) => { + const networkConfig = getNetworkConfig(chainName); - let result = await vault.sign(data, "abc", null, ethUrl); - expect(result.error).toBe("Wrong pin type, format or length"); + let addresses; + let impprivatekey; + if (chainName == "bitcoin") { + addresses = bitcoinadresses; + impprivatekey = privateKeybtcImp; + } else { + addresses = evmaddresses; + impprivatekey = "0x" + privateKeyImp; + } + addresses.forEach((address, index) => { + test(`signMessage for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + vault.changeNetwork(chainName); + await vault.importWallet(impprivatekey, pin, bufView); + + 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: address, + data: hexData, + }; + + const raw_sign = await vault.signMessage( + address, + msgParams.data, + pin, + bufView, + ethUrl + ); + console.log(raw_sign); + }); + + // Skip signTypedMessage and personalSign tests for Bitcoin + if (chainName !== "bitcoin") { + test(`signTypeMessage for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let msgParams = { + from: address, + 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( + address, + msgParams.data, + pin, + bufView, + networkConfig.url + ); + console.log("Raw signature:", rawSignature); + + // Verify the signature + msgParams = { ...msgParams.data, from: msgParams.from }; + const recoveredAddress = sigUtil.recoverTypedSignature({ + data: msgParams, + sig: rawSignature.response, + }); + + const isSignatureValid = + recoveredAddress.toLowerCase() === msgParams.from.toLowerCase(); + + assert( + isSignatureValid, + `Signature verification failed for ${chainName} using address ${address}` + ); + assert( + rawSignature, + `Failed to Sign Message for ${chainName} using address ${address}` + ); + }); + + test(`personalSign for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + const message = "Hello, personal sign!"; + const msgParams = { + from: address, + data: message, + }; + + const rawSignature = await vault.personalSign( + address, + msgParams.data, + pin, + bufView, + networkConfig.url + ); + + console.log("Raw signature:", rawSignature); + + // Verify the signature + let web3 = new Web3(networkConfig.url); + const recoveredAddress = web3.eth.accounts.recover( + message, + rawSignature.response + ); + + const isSignatureValid = + recoveredAddress.toLowerCase() === address.toLowerCase(); + + assert( + isSignatureValid, + `Signature verification failed for ${chainName} using address ${address}` + ); + + assert( + rawSignature, + `Failed to Personal Sign Message for ${chainName} using address ${address}` + ); + }); + } + }); }); - test("sign/incorrect pin", async () => { - let data = "hello world"; +}); - let result = await vault.sign(data, "abc", "111111", ethUrl); - expect(result.error).toBe("Incorrect pin"); - }); - test("sign/invalid pin", async () => { - let data = "hello world"; - let result = await vault.sign(data, accAddress, "abc", ethUrl); - expect(result.error).toBe("Wrong pin type, format or length"); - }); +describe("signTransaction", () => { + const evmaddresses = [process.env.EVM_ADDRESS_1, process.env.EVM_ADDRESS_2]; + const bitcoinadresses = [ + process.env.BITCOIN_ADDRESS_1, + process.env.BITCOIN_ADDRESS_2, + ]; + Object.keys(NETWORKS).forEach((chainName) => { + const networkConfig = getNetworkConfig(chainName); - test("sign/empty url", async () => { - let data = "hello world"; - let result = await vault.sign( - data, - "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd", - pin, - null - ); - expect(result.response).toHaveProperty("signature"); - }); + let addresses; + let impprivatekey; + if (chainName == "bitcoin") { + addresses = bitcoinadresses; + impprivatekey = privateKeybtcImp; + } else { + addresses = evmaddresses; + impprivatekey = "0x" + privateKeyImp; + } + addresses.forEach((address, index) => { + test(`signTransaction/valid for ${chainName} using ${ + index === 1 ? "imported" : "" + } address ${address}`, async () => { + vault.changeNetwork(chainName); + const web3 = new Web3(networkConfig.url); + await vault.importWallet(impprivatekey, pin, bufView); + + const rawTx = { + to: addresses[index === 0 ? 1 : 0], + from: address.toLowerCase(), + value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), + gasLimit: web3.utils.numberToHex(21000), + maxPriorityFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("42.25770", "gwei")) + ), + maxFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("150.99", "gwei")) + ), + amount: 0, + satPerByte: 1, + data: "0x0", + type: "0x2", + }; + await vault.getActiveChains(); + try { + let result = await vault.signTransaction( + rawTx, + pin, + networkConfig.url + ); + + // Add more specific assertions based on the expected result structure + } catch (e) { + expect(e.message).toBe("Cannot read property 'salt' of undefined"); + } + }); + + test(`signTransaction/empty raw tx for ${chainName} using ${ + index === 1 ? "imported" : "" + } + address ${address}`, async () => { + let from = process.env.EVM_ADDRESS_1; + const web3 = new Web3(networkConfig.url); + try { + let result = await vault.signTransaction({}, pin, networkConfig.url); + } catch (e) { + expect(e.message).toBe( + "Cannot read properties of undefined (reading 'toLowerCase')" + ); + } + }); + + test(`signTransaction/invalid raw for ${chainName} using ${ + index === 1 ? "imported" : "" + } address ${address}`, async () => { + try { + let result = await vault.signTransaction( + "invalid", + pin, + networkConfig.url + ); + } catch (e) { + expect(e.message).toBe( + "Cannot read properties of undefined (reading 'toLowerCase')" + ); + } + }); + + test(`signTransaction/empty pin for ${chainName} using ${ + index === 1 ? "imported" : "" + } address ${address}`, async () => { + const web3 = new Web3(networkConfig.url); + const rawTx = { + to: addresses[index === 0 ? 1 : 0], + from: address.toLowerCase(), + value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), + gasLimit: web3.utils.numberToHex(21000), + maxPriorityFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("42.25770", "gwei")) + ), + maxFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("150.99", "gwei")) + ), + amount: 0, + satPerByte: 1, + data: "0x0", + type: "0x2", + }; - test("sign/invalid url", async () => { - let data = "hello world"; - let result = await vault.sign( - data, - "0x80f850d6bfa120bcc462df27cf94d7d23bd8b7fd", - pin, - "abc" - ); - expect(result.response).toHaveProperty("signature"); - }); + let result = await vault.signTransaction( + rawTx, + null, + networkConfig.url + ); + expect(result.error).toBe("Wrong pin type, format or length"); + }); + + test(`signTransaction/invalid pin for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let from = address.toLowerCase(); + const web3 = new Web3(networkConfig.url); + + const rawTx = { + to: addresses[index === 0 ? 1 : 0], + from: address.toLowerCase(), + value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), + gasLimit: web3.utils.numberToHex(21000), + maxPriorityFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("42.25770", "gwei")) + ), + maxFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("150.99", "gwei")) + ), + amount: 0, + satPerByte: 1, + data: "0x0", + type: "0x2", + }; - test("sign/all params empty", async () => { - let data = "hello world"; + let result = await vault.signTransaction( + "evwf", + "afewf", + networkConfig.url + ); + expect(result.error).toBe("Wrong pin type, format or length"); + }); + test(`signTransaction/incorrect pin for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let from = address.toLowerCase(); + const web3 = new Web3(networkConfig.url); + + const rawTx = { + to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address + from: from.toLowerCase(), //sender address + value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), + gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below + maxPriorityFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("42.25770", "gwei")) + ), + maxFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("150.99", "gwei")) + ), + data: "0x0", // method to generate data is provided below + + type: "0x2", + }; - let result = await vault.sign(null, null, null, null); - expect(result.error).toBe("Wrong pin type, format or length"); + let result = await vault.signTransaction( + "evwf", + "112344", + networkConfig.url + ); + expect(result.error).toBe("Incorrect pin"); + }); + + test(`signTransaction/empty polygon rpc for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let from = address.toLowerCase(); + const web3 = new Web3(networkConfig.url); + + const rawTx = { + to: addresses[index === 0 ? 1 : 0], + from: address.toLowerCase(), + value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), + gasLimit: web3.utils.numberToHex(21000), + maxPriorityFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("42.25770", "gwei")) + ), + maxFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("150.99", "gwei")) + ), + amount: 0, + satPerByte: 1, + data: "0x0", + type: "0x2", + }; + + try { + let result = await vault.signTransaction(rawTx, pin, null); + } catch (e) { + expect(e.message).toBe( + "CONNECTION ERROR: Couldn't connect to node http://localhost:8545." + ); + } + }); + + test(`signTransaction/invalid polygon rpc for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let from = address.toLowerCase(); + const web3 = new Web3(networkConfig.url); + + const rawTx = { + to: addresses[index === 0 ? 1 : 0], + from: address.toLowerCase(), + value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), + gasLimit: web3.utils.numberToHex(21000), + maxPriorityFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("42.25770", "gwei")) + ), + maxFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("150.99", "gwei")) + ), + amount: 0, + satPerByte: 1, + data: "0x0", + type: "0x2", + }; + let invalidRpc = "efrwgrwdvfr"; + try { + let result = await vault.signTransaction(rawTx, pin, invalidRpc); + } catch (e) { + expect(e.message).toBe( + `CONNECTION ERROR: Couldn't connect to node ${invalidRpc}.` + ); + } + }); + + test(`signTransaction/all empty params for ${chainName} using ${ + index == 1 ? "imported" : "" + } address ${address}`, async () => { + let from = address.toLowerCase(); + const web3 = new Web3(networkConfig.url); + + const rawTx = { + to: addresses[index === 0 ? 1 : 0], + from: address.toLowerCase(), + value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), + gasLimit: web3.utils.numberToHex(21000), + maxPriorityFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("42.25770", "gwei")) + ), + maxFeePerGas: web3.utils.numberToHex( + parseFloat(web3.utils.toWei("150.99", "gwei")) + ), + amount: 0, + satPerByte: 1, + data: "0x0", + type: "0x2", + }; + let invalidRpc = "efrwgrwdvfr"; + + let result = await vault.signTransaction(null, null, null); + expect(result.error).toBe("Wrong pin type, format or length"); + }); + }); }); }); @@ -870,323 +1402,90 @@ describe("Add new network", () => { }); }); -describe("signTransaction", () => { - Object.keys(NETWORKS).forEach((chainName) => { - const networkConfig = getNetworkConfig(chainName); - vault.changeNetwork(chainName); - test(`signTransaction/valid for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - await vault.getActiveChains(); - try { - let result = await vault.signTransaction(rawTx, pin, networkConfig.url); - } catch (e) { - expect(e.message).toBe("Cannot read property 'salt' of undefined"); - } - }); - - test(`signTransaction/empty raw tx for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - try { - let result = await vault.signTransaction({}, pin, networkConfig.url); - } catch (e) { - expect(e.message).toBe( - "Cannot read properties of undefined (reading 'toLowerCase')" - ); - } - }); +describe("getFees", () => { + const evmAddresses = [process.env.EVM_ADDRESS_1, process.env.EVM_ADDRESS_2]; + const bitcoinAddresses = [ + process.env.BITCOIN_ADDRESS_1, + process.env.BITCOIN_ADDRESS_2, + ]; - test(`signTransaction/invalid raw for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - try { - let result = await vault.signTransaction( - "evwf", - pin, - networkConfig.url - ); - } catch (e) { - expect(e.message).toBe( - "Cannot read properties of undefined (reading 'toLowerCase')" - ); - } - }); - - test(`signTransaction/empty pin for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - - let result = await vault.signTransaction("evwf", null, networkConfig.url); - expect(result.error).toBe("Wrong pin type, format or length"); - }); - - test(`signTransaction/invalid pin for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - - let result = await vault.signTransaction( - "evwf", - "afewf", - networkConfig.url - ); - expect(result.error).toBe("Wrong pin type, format or length"); - }); - test(`signTransaction/incorrect pin for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - - let result = await vault.signTransaction( - "evwf", - "112344", - networkConfig.url - ); - expect(result.error).toBe("Incorrect pin"); - }); - - test(`signTransaction/empty polygon rpc for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - - try { - let result = await vault.signTransaction("evwf", pin, null); - } catch (e) { - expect(e.message).toBe( - "CONNECTION ERROR: Couldn't connect to node http://localhost:8545." - ); - } - }); - - test(`signTransaction/invalid polygon rpc for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - let invalidRpc = "efrwgrwdvfr"; - try { - let result = await vault.signTransaction("evwf", pin, invalidRpc); - } catch (e) { - expect(e.message).toBe( - `CONNECTION ERROR: Couldn't connect to node ${invalidRpc}.` - ); - } - }); - - test(`signTransaction/all empty params for ${chainName}`, async () => { - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - const nonce = await web3.eth.getTransactionCount(from.toLowerCase()); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", //recepient address - from: from.toLowerCase(), //sender address - value: web3.utils.numberToHex(web3.utils.toWei("0.001", "ether")), - gasLimit: web3.utils.numberToHex(21000), //method to compute gas provided below - maxPriorityFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("42.25770", "gwei")) - ), - maxFeePerGas: web3.utils.numberToHex( - parseFloat(web3.utils.toWei("150.99", "gwei")) - ), - data: "0x0", // method to generate data is provided below - nonce: nonce, - type: "0x2", - }; - let invalidRpc = "efrwgrwdvfr"; - - let result = await vault.signTransaction(null, null, null); - expect(result.error).toBe("Wrong pin type, format or length"); - }); - }); -}); - -describe("get Fees", () => { Object.keys(NETWORKS).forEach((chainName) => { - test(`get Fees, validate for ${chainName}`, async () => { - const networkConfig = getNetworkConfig(chainName); - vault.changeNetwork(chainName); - - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); - - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", - from: from.toLowerCase(), - value: web3.utils.numberToHex(web3.utils.toWei("0", "ether")), - chainID: networkConfig.chainId, - }; - - let result = await vault.getFees(rawTx, networkConfig.url); - expect(result.response).toHaveProperty("gasLimit"); - expect(result.response).toHaveProperty("fees"); - - // Additional checks specific to the chain - if (networkConfig.txType === 2) { - expect(result.response.fees.fast).toHaveProperty("maxFeePerGas"); - expect(result.response.fees.fast).toHaveProperty( - "maxPriorityFeePerGas" - ); - } else { - expect(result.response.fees.fast).toHaveProperty("gasPrice"); - } - }); - - test(`get fees, invalid for ${chainName}`, async () => { - const networkConfig = getNetworkConfig(chainName); - vault.changeNetwork(chainName); - - let from = "0x80F850d6BFA120Bcc462df27cF94d7D23bd8B7FD"; - const web3 = new Web3(networkConfig.url); + const networkConfig = getNetworkConfig(chainName); - const rawTx = { - to: "0xacde0f575d8caf7bdba417326797c1a1d1b21f88", - from: from.toLowerCase(), - value: web3.utils.numberToHex(web3.utils.toWei("0", "ether")), - chainID: networkConfig.chainId, - }; + let addresses; + if (chainName === "bitcoin") { + addresses = bitcoinAddresses; + } else { + addresses = evmAddresses; + } - try { - let result = await vault.getFees(rawTx, "invalid_url"); - fail("Should have thrown an error"); - } catch (e) { - expect(e.message).toBe( - "CONNECTION ERROR: Couldn't connect to node invalid_url." - ); - } + addresses.forEach((address, index) => { + test(`getFees/valid for ${chainName} using address ${address}`, async () => { + vault.changeNetwork(chainName); + const web3 = + chainName !== "bitcoin" ? new Web3(networkConfig.url) : null; + + const rawTx = + chainName === "bitcoin" + ? { + to: addresses[index === 0 ? 1 : 0], + from: address, + value: "0.0001", // BTC value + } + : { + to: addresses[index === 0 ? 1 : 0], + from: address.toLowerCase(), + value: web3.utils.numberToHex(web3.utils.toWei("0", "ether")), + chainID: networkConfig.chainId, + }; + + let result = await vault.getFees(rawTx, networkConfig.url); + + if (chainName === "bitcoin") { + expect(result.response).toHaveProperty("transactionSize"); + expect(result.response).toHaveProperty("fees"); + expect(result.response.fees).toHaveProperty("slow"); + expect(result.response.fees).toHaveProperty("standard"); + expect(result.response.fees).toHaveProperty("fast"); + expect(result.response.fees.slow).toHaveProperty("satPerByte"); + expect(result.response.fees.standard).toHaveProperty("satPerByte"); + expect(result.response.fees.fast).toHaveProperty("satPerByte"); + expect(typeof result.response.transactionSize).toBe("number"); + expect(typeof result.response.fees.slow.satPerByte).toBe("number"); + expect(typeof result.response.fees.standard.satPerByte).toBe( + "number" + ); + expect(typeof result.response.fees.fast.satPerByte).toBe("number"); + } else { + expect(result.response).toHaveProperty("gasLimit"); + expect(result.response).toHaveProperty("fees"); + if (networkConfig.txType === 2) { + expect(result.response.fees.fast).toHaveProperty("maxFeePerGas"); + expect(result.response.fees.fast).toHaveProperty( + "maxPriorityFeePerGas" + ); + } else { + expect(result.response.fees.fast).toHaveProperty("gasPrice"); + } + } + }); + + test(`getFees/network error for ${chainName} using address ${address}`, async () => { + // Mock axios to simulate a network error + + const rawTx = + chainName === "bitcoin" + ? { from: address } + : { from: address.toLowerCase() }; + + try { + let result = await vault.getFees(rawTx, "invalid_url"); + } catch (e) { + expect(e.message).toBe( + "CONNECTION ERROR: Couldn't connect to node invalid_url." + ); + } + }); }); }); }); diff --git a/src/lib/test/vault.test.js b/src/lib/test/vault.test.js index a0db9c9..cbe7383 100644 --- a/src/lib/test/vault.test.js +++ b/src/lib/test/vault.test.js @@ -2,15 +2,19 @@ jest.setTimeout(30000); const crypto = require("crypto"); let Vault = require("../vault"); + +require("dotenv").config(); + const bufView = [ 48, 0, 236, 187, 187, 172, 177, 90, 255, 184, 9, 116, 142, 96, 197, 158, 87, 35, 26, 101, 187, 30, 116, 138, 50, 131, 166, 50, 51, 197, 198, 83, 238, 167, 105, 178, 182, 108, 174, 199, 124, 141, 155, 73, 21, 85, 81, 109, 78, 233, 152, 108, 242, 238, 192, 31, 147, 86, 174, 195, 55, 229, 4, 36, ]; -let phrase = - "fun rough treat scan glimpse region century purpose expire video remind second"; -let pin = "696969"; +let oldphrase = process.env.OLD_MNEMONIC; +let phrase = process.env.MNEMONIC; + +let pin = process.env.PIN; let vault = new Vault({}); const logs = [ @@ -163,7 +167,7 @@ describe("recoverVault", () => { test("recoverVault/logs valid", async () => { let result = await vault.recoverVault( - phrase, + oldphrase, bufView, pin, null, @@ -174,7 +178,13 @@ describe("recoverVault", () => { }); test("recoverVault/logs empty logs valid", async () => { - let result = await vault.recoverVault(phrase, bufView, pin, null, "logs"); + let result = await vault.recoverVault( + oldphrase, + bufView, + pin, + null, + "logs" + ); expect(result).toHaveProperty("response"); }); diff --git a/src/lib/vault.js b/src/lib/vault.js index 1cf5238..554ded5 100644 --- a/src/lib/vault.js +++ b/src/lib/vault.js @@ -40,7 +40,10 @@ class Vault extends Keyring { const evmChainInfo = Chains.getEvmChainInfo(this.chain); const keyringController = new KeyringController({ txType: evmChainInfo.txType, - + persistKeyrings: this.keyringInstance?.keyrings, + persistStore: this.keyringInstance?.store, + persistmemStore: this.keyringInstance?.memStore, + persistImported: this.keyringInstance?.importedWallets, encryptor: { encrypt(pass, object) { const ciphertext = CryptoJS.AES.encrypt(