From 0a9c8da471fdea9d83a26f9e9b711120d825577c Mon Sep 17 00:00:00 2001 From: Abdulrahman Yusuf Date: Tue, 3 May 2022 02:56:32 +0100 Subject: [PATCH 1/5] add wallet encryptions from ethereum wallets --- .gitignore | 1 + src/common/helpers/ethersHelper.ts | 27 +++++++++++++++++++++++++++ src/common/utils/types.ts | 12 ++++++++++++ src/services/wallet/index.ts | 30 ++++++++++++++++++++++++++++++ test/wallet.test.ts | 27 +++++++++++++++++++++++++++ 5 files changed, 97 insertions(+) diff --git a/.gitignore b/.gitignore index 4c9d7c3..a887ac9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .DS_Store node_modules dist +.vscode \ No newline at end of file diff --git a/src/common/helpers/ethersHelper.ts b/src/common/helpers/ethersHelper.ts index d017d99..98e0892 100644 --- a/src/common/helpers/ethersHelper.ts +++ b/src/common/helpers/ethersHelper.ts @@ -4,7 +4,9 @@ import { ethers } from 'ethers'; import { BalancePayload, GetAddressFromPrivateKeyPayload, + GetEncryptedJsonFromPrivateKey, GetTransactionPayload, + GetWalletFromEncryptedjsonPayload, TransferPayload, } from '../utils/types'; import { successResponse } from '../utils'; @@ -183,6 +185,29 @@ const getTransaction = async ({ hash, rpcUrl }: GetTransactionPayload) => { } }; +const getEncryptedJsonFromPrivateKey = async ( + args: GetEncryptedJsonFromPrivateKey +) => { + const wallet = new ethers.Wallet(args.privateKey); + const json = await wallet.encrypt(args.password); + + return successResponse({ json }); +}; + +const getWalletFromEncryptedJson = async ( + args: GetWalletFromEncryptedjsonPayload +) => { + const wallet = await ethers.Wallet.fromEncryptedJson( + args.json, + args.password + ); + + return successResponse({ + privateKey: wallet.privateKey, + address: wallet.address, + }); +}; + export default { getBalance, createWallet, @@ -190,4 +215,6 @@ export default { generateWalletFromMnemonic, transfer, getTransaction, + getEncryptedJsonFromPrivateKey, + getWalletFromEncryptedJson, }; diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts index 24e254c..3559920 100644 --- a/src/common/utils/types.ts +++ b/src/common/utils/types.ts @@ -41,3 +41,15 @@ export interface GenerateWalletFromMnemonicPayload { export interface IResponse { [key: string]: any; } + +export interface GetEncryptedJsonFromPrivateKey { + password: string; + privateKey: string; + network: string; +} + +export interface GetWalletFromEncryptedjsonPayload { + json: string; + password: string; + network: string; +} diff --git a/src/services/wallet/index.ts b/src/services/wallet/index.ts index 00d3ac5..4f61611 100644 --- a/src/services/wallet/index.ts +++ b/src/services/wallet/index.ts @@ -8,6 +8,8 @@ import { GetAddressFromPrivateKeyPayload, GenerateWalletFromMnemonicPayload, GetTransactionPayload, + GetWalletFromEncryptedjsonPayload, + GetEncryptedJsonFromPrivateKey, } from '../../common/utils/types'; export async function getBalance(args: BalancePayload) { @@ -103,3 +105,31 @@ export async function getTransaction(args: GetTransactionPayload) { throw error; } } + +export async function getEncryptedJsonFromPrivateKey( + args: GetEncryptedJsonFromPrivateKey +) { + try { + if (args.network === 'ethereum') { + return await ethereumHelper.getEncryptedJsonFromPrivateKey({ ...args }); + } + + return; + } catch (error) { + throw error; + } +} + +export async function getWalletFromEncryptedJson( + args: GetWalletFromEncryptedjsonPayload +) { + try { + if (args.network === 'ethereum') { + return await ethereumHelper.getWalletFromEncryptedJson({ ...args }); + } + + return; + } catch (error) { + throw error; + } +} diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 9d19223..dcc55e0 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -5,6 +5,8 @@ import { getAddressFromPrivateKey, getTransaction, transfer, + getWalletFromEncryptedJson, + getEncryptedJsonFromPrivateKey, } from '../src'; describe('MultichainCryptoWallet', () => { @@ -190,4 +192,29 @@ describe('MultichainCryptoWallet', () => { expect(typeof receipt).toBe('object'); }); + + it('encrypts ethereum address privatekey and returns the encrypted json', async () => { + const data = await getEncryptedJsonFromPrivateKey({ + privateKey: + '0f9e5c0bee6c7d06b95204ca22dea8d7f89bb04e8527a2c59e134d185d9af8ad', + network: 'ethereum', + password: 'walletpassword', + }); + + expect(typeof data).toBe('object'); + expect(typeof (data && data.json)).toBe('string'); + }); + + it('decrypts ethereum address and returns the wallet details', async () => { + const data = await getWalletFromEncryptedJson({ + json: + '{"address":"1c082d1052fb44134a408651c01148adbfcce7fe","id":"ca8b45b0-e69d-4e5e-8003-8f3dbb1082cf","version":3,"Crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"fe66bd308ad315126ae6f09f0d6599f4"},"ciphertext":"5f2abe02e49868c36df36f884680b132333e541f89cd7eb375247ff7c8a6ccdd","kdf":"scrypt","kdfparams":{"salt":"2570bf687cb7d9cd694e1c79f6e817c9c66467e81b04013104620670f0664bf5","n":131072,"dklen":32,"p":1,"r":8},"mac":"35f69fb7283c65d75c000a0c93042c063d2903efe9b9e6f03b05d842f47ed1e9"}}', + network: 'ethereum', + password: 'walletpassword', + }); + + expect(typeof data).toBe('object'); + expect(typeof (data && data.privateKey)).toBe('string'); + expect(typeof (data && data.address)).toBe('string'); + }); }); From 5d84d76750dfdb41494d641b5cf37c15ac599718 Mon Sep 17 00:00:00 2001 From: Abdulrahman Yusuf Date: Tue, 3 May 2022 03:12:26 +0100 Subject: [PATCH 2/5] update README with encryption docs --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 02838bd..85e11a7 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ const data = await multichainWallet.getBalance({ ```javascript { - balance: 2 + balance: 2; } ``` @@ -181,7 +181,7 @@ const address = await multichainWallet.getAddressFromPrivateKey({ ```javascript { - address: '0x1C082D1052fb44134a408651c01148aDBFcCe7Fe' + address: '0x1C082D1052fb44134a408651c01148aDBFcCe7Fe'; } ``` @@ -211,7 +211,7 @@ const receipt = await multichainWallet.getTransaction({ ```javascript { receipt: { - object + object; } } ``` @@ -285,8 +285,58 @@ const transfer = await multichainWallet.transfer({ ```javascript { - hash: '0xf2978fe918f3e28b7f57101bbc99aa9d7d2d71507ca4a08bac6dd09575527502' + hash: '0xf2978fe918f3e28b7f57101bbc99aa9d7d2d71507ca4a08bac6dd09575527502'; +} +``` + +### Encryptions + +#### encrypt private key + +It supports encryption of ethereum and other EVM compatible chains private keys. + +```javascript +// encrypt private key. + +const encrypted = await multichainWallet.getEncryptedJsonFromPrivateKey({ + network: 'ethereum', + privateKey: + '0f9e5c0bee6c7d06b95204ca22dea8d7f89bb04e8527a2c59e134d185d9af8ad', + password: 'walletpassword', +}); +``` + +#### Response + +```javascript +{ + json: '{"address":"1c082d1052fb44134a408651c01148adbfcce7fe","id":"abfb9f10-165a-4b7a-935d-51729f10c310","version":3,"Crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"f3fac53ee2d76c293977d1af3a7d73bb"},"ciphertext":"c5034579cdf32d7a612c9a83801aad899abfebb7436712f363ecf89546bbcbce","kdf":"scrypt","kdfparams":{"salt":"78ff80ece5d681b1aecd829526388472d1889da233229fa5c1416e8f2035b7a8","n":131072,"dklen":32,"p":1,"r":8},"mac":"0f70eca6138ffe60b174308b6ab7a8a81a0d2b662e2cf5d8727443cf12af766c"}}'; +} +``` + +#### decrypt JSON key + +It supports decryption of encrypted JSONs (A.K.A keystore). + +```javascript +// decrypting encrypted JSON. + +const decrypted = await multichainWallet.getWalletFromEncryptedJson({ + network: 'ethereum', + json: + '{"address":"1c082d1052fb44134a408651c01148adbfcce7fe","id":"abfb9f10-165a-4b7a-935d-51729f10c310","version":3,"Crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"f3fac53ee2d76c293977d1af3a7d73bb"},"ciphertext":"c5034579cdf32d7a612c9a83801aad899abfebb7436712f363ecf89546bbcbce","kdf":"scrypt","kdfparams":{"salt":"78ff80ece5d681b1aecd829526388472d1889da233229fa5c1416e8f2035b7a8","n":131072,"dklen":32,"p":1,"r":8},"mac":"0f70eca6138ffe60b174308b6ab7a8a81a0d2b662e2cf5d8727443cf12af766c"}}', + password: 'walletpassword', +}); +``` + +#### Response + +```javascript +{ + privateKey: '0x0f9e5c0bee6c7d06b95204ca22dea8d7f89bb04e8527a2c59e134d185d9af8ad', + address: '0x1C082D1052fb44134a408651c01148aDBFcCe7Fe' } + ``` #### Solana Network @@ -320,7 +370,7 @@ const transfer = await MultichainCryptoWallet.transfer({ ```javascript { - hash: '3nGq2yczqCpm8bF2dyvdPtXpnFLJ1oGWkDfD6neLbRay8SjNqYNhWQBKE1ZFunxvFhJ47FyT6igNpYPP293jXCZk' + hash: '3nGq2yczqCpm8bF2dyvdPtXpnFLJ1oGWkDfD6neLbRay8SjNqYNhWQBKE1ZFunxvFhJ47FyT6igNpYPP293jXCZk'; } ``` From 272e24c225d9784a7d833fd774a8ab6ea3ff2eff Mon Sep 17 00:00:00 2001 From: Abdulrahman Yusuf Date: Tue, 3 May 2022 03:27:01 +0100 Subject: [PATCH 3/5] update README --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 85e11a7..ec1e7b4 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ The following methods are available with this SDK: - [Get Address from Private Key](#get-address-from-private-key) - [Get Transaction Hash](#get-transaction-with-hash) - [Transfer](#transfer) +- [Encrypt Private Key](#encryptions#encrypt-private-key) +- [Decrypt Encrypted JSON](#encryptions#decrypt-encrypted-json) ### Create Wallet @@ -291,7 +293,7 @@ const transfer = await multichainWallet.transfer({ ### Encryptions -#### encrypt private key +#### Encrypt Private Key It supports encryption of ethereum and other EVM compatible chains private keys. @@ -314,7 +316,7 @@ const encrypted = await multichainWallet.getEncryptedJsonFromPrivateKey({ } ``` -#### decrypt JSON key +#### Decrypt Encrypted JSON It supports decryption of encrypted JSONs (A.K.A keystore). From 1467e13e4ab4dd3c6b3a678be5179880d729c18a Mon Sep 17 00:00:00 2001 From: Abdulrahman Yusuf Date: Tue, 3 May 2022 03:28:10 +0100 Subject: [PATCH 4/5] update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ec1e7b4..dbc5acb 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ The following methods are available with this SDK: - [Get Address from Private Key](#get-address-from-private-key) - [Get Transaction Hash](#get-transaction-with-hash) - [Transfer](#transfer) -- [Encrypt Private Key](#encryptions#encrypt-private-key) -- [Decrypt Encrypted JSON](#encryptions#decrypt-encrypted-json) +- [Encrypt Private Key](#encrypt-private-key) +- [Decrypt Encrypted JSON](#decrypt-encrypted-json) ### Create Wallet From aa18625e2f361d4fbc5c466eb0a9539c263eea68 Mon Sep 17 00:00:00 2001 From: Abdulrahman Yusuf Date: Wed, 4 May 2022 14:32:49 +0100 Subject: [PATCH 5/5] ignore node's builtin stream module on browser --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 64c57cb..add18dd 100644 --- a/package.json +++ b/package.json @@ -76,5 +76,8 @@ "buffer-layout": "^1.2.2", "ed25519-hd-key": "^1.2.0", "ethers": "^5.6.2" + }, + "browser": { + "stream": false } }