From 445a9ba919a362e8a7936133c3eb3aceb645b878 Mon Sep 17 00:00:00 2001 From: Soralit Date: Sat, 29 Jan 2022 16:22:33 +0800 Subject: [PATCH 01/18] Support QR hardware --- src/keyring/KeyringController.ts | 116 ++++++++ yarn.lock | 494 ++++++++++++++++++++++++++++++- 2 files changed, 605 insertions(+), 5 deletions(-) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 0f168df88bf..da79ff2fd6d 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -33,6 +33,7 @@ const privates = new WeakMap(); export enum KeyringTypes { simple = 'Simple Key Pair', hd = 'HD Key Tree', + qr = 'QR Hardware Wallet Device', } /** @@ -140,6 +141,8 @@ export class KeyringController extends BaseController< private setSelectedAddress: PreferencesController['setSelectedAddress']; + private setAccountLabel: PreferencesController['setAccountLabel']; + /** * Creates a KeyringController instance. * @@ -148,6 +151,7 @@ export class KeyringController extends BaseController< * @param options.syncIdentities - Sync identities with the given list of addresses. * @param options.updateIdentities - Generate an identity for each address given that doesn't already have an identity. * @param options.setSelectedAddress - Set the selected address. + * @param options.setAccountLabel - Set a new name for account. * @param config - Initial options used to configure this controller. * @param state - Initial state to set on this controller. */ @@ -157,11 +161,13 @@ export class KeyringController extends BaseController< syncIdentities, updateIdentities, setSelectedAddress, + setAccountLabel, }: { removeIdentity: PreferencesController['removeIdentity']; syncIdentities: PreferencesController['syncIdentities']; updateIdentities: PreferencesController['updateIdentities']; setSelectedAddress: PreferencesController['setSelectedAddress']; + setAccountLabel: PreferencesController['setAccountLabel']; }, config?: Partial, state?: Partial, @@ -179,6 +185,7 @@ export class KeyringController extends BaseController< this.syncIdentities = syncIdentities; this.updateIdentities = updateIdentities; this.setSelectedAddress = setSelectedAddress; + this.setAccountLabel = setAccountLabel; this.initialize(); this.fullUpdate(); } @@ -430,6 +437,18 @@ export class KeyringController extends BaseController< ) { try { const address = normalizeAddress(messageParams.from); + const QRKeyring = await this.getQRKeyring(); + const qrAccounts = await QRKeyring.getAccounts(); + if ( + qrAccounts.find( + (qrAddress: string) => + qrAddress.toLowerCase() === address.toLowerCase(), + ) + ) { + return privates + .get(this) + .keyring.signTypedMessage(messageParams, { version }); + } const { password } = privates.get(this).keyring; const privateKey = await this.exportAccount(password, address); const privateKeyBuffer = toBuffer(addHexPrefix(privateKey)); @@ -586,6 +605,103 @@ export class KeyringController extends BaseController< this.update({ keyrings: [...keyrings] }); return privates.get(this).keyring.fullUpdate(); } + + // QR Hardware related methods + + /** + * Add qr hardware keyring. + * + * @returns The added keyring + */ + private async addQRKeyring() { + return await privates.get(this).keyring.addNewKeyring(KeyringTypes.qr); + } + + /** + * Get qr hardware keyring. + * + * @returns The added keyring + */ + private async getQRKeyring() { + const keyring = privates + .get(this) + .keyring.getKeyringsByType(KeyringTypes.qr)[0]; + if (keyring) { + return keyring; + } + return await this.addQRKeyring(); + } + + getQRKeyringState = async () => { + return (await this.getQRKeyring()).getMemStore(); + }; + + submitQRKeyring = async (cryptoHDKey: any) => + (await this.getQRKeyring()).syncKeyring(cryptoHDKey); + + submitQRCryptoHDKey = async (cryptoHDKey: any) => + (await this.getQRKeyring()).submitCryptoHDKey(cryptoHDKey); + + cancelSyncQRCryptoHDKey = async () => + // eslint-disable-next-line node/no-sync + (await this.getQRKeyring()).cancelSync(); + + submitQRHardwareSignature = async (requestId: string, ethSignature: any) => + (await this.getQRKeyring()).submitSignature(requestId, ethSignature); + + cancelQRHardwareSignRequest = async () => + (await this.getQRKeyring()).cancelSignRequest(); + + connectQRHardware = async (page: number) => { + try { + const keyring = await this.getQRKeyring(); + let accounts = []; + switch (page) { + case -1: + accounts = await keyring.getPreviousPage(); + break; + case 1: + accounts = await keyring.getNextPage(); + break; + default: + accounts = await keyring.getFirstPage(); + } + return accounts; + } catch (e) { + throw new Error('Unspecified error when connect QR Hardware'); + } + }; + + async unlockQRHardwareWalletAccount(index: number) { + const keyring = await this.getQRKeyring(); + + keyring.setAccountToUnlock(index); + const oldAccounts = await privates.get(this).keyring.getAccounts(); + await privates.get(this).keyring.addNewAccount(keyring); + const newAccounts = await privates.get(this).keyring.getAccounts(); + this.updateIdentities(newAccounts); + newAccounts.forEach((address: string) => { + if (!oldAccounts.includes(address)) { + if (this.setAccountLabel) { + this.setAccountLabel(address, `QR Hardware ${index}`); + } + this.setSelectedAddress(address); + } + }); + return this.fullUpdate(); + } + + async getAccountKeyringType(account: string) { + return (await privates.get(this).keyring.getKeyringForAccount(account)) + .type; + } + + async forgetQRDevice() { + const keyring = await this.getQRKeyring(); + keyring.forgetDevice(); + await this.fullUpdate(); + return true; + } } export default KeyringController; diff --git a/yarn.lock b/yarn.lock index 04ba1f1909d..b0bf0398872 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@apocentre/alias-sampling@^0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@apocentre/alias-sampling/-/alias-sampling-0.5.3.tgz#897ff181b48ad7b2bcb4ecf29400214888244f08" + integrity sha512-7UDWIIF9hIeJqfKXkNIzkVandlwLf1FWTSdrb9iXvOP8oF544JRXQjCbiTmCv2c9n44n/FIWtehhBfNuAx2CZA== + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -440,6 +445,14 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@ethereumjs/common@^2.0.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.0.tgz#feb96fb154da41ee2cc2c5df667621a440f36348" + integrity sha512-Cq2qS0FTu6O2VU1sgg+WyU9Ps0M6j/BEMHN+hRaECXCV/r0aI78u4N6p52QW/BDVhwWZpCdrvG8X7NJdzlpNUA== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.3" + "@ethereumjs/common@^2.3.1": version "2.3.1" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.3.1.tgz#d692e3aff5adb35dd587dd1e6caab69e0ed2fa0b" @@ -456,6 +469,14 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.0" +"@ethereumjs/tx@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.0.0.tgz#8dfd91ed6e91e63996e37b3ddc340821ebd48c81" + integrity sha512-H9tfy6qgYxPXvt1TSObfVmVjlF43OoQqoPQ3PJsG2JiuqaMHj5ettV1pGFEC3FamENDBkl6vD6niQEvIlXv/VQ== + dependencies: + "@ethereumjs/common" "^2.0.0" + ethereumjs-util "^7.0.7" + "@ethereumjs/tx@^3.2.1": version "3.2.1" resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.2.1.tgz#65f5f1c11541764f08377a94ba4b0dcbbd67739e" @@ -1049,6 +1070,48 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" +"@keystonehq/base-eth-keyring@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@keystonehq/base-eth-keyring/-/base-eth-keyring-0.3.2.tgz#71efe1495d4931fab5fd0016c8722fe5d9657da9" + integrity sha512-y/kv8XNRSzqcSl7fvZklBKr4MVir1OJHzqM5vC+3yvzkh3mVtN8vUjAAxHtmVVVyM8rsdqK7aYZ7paexYdpnag== + dependencies: + "@ethereumjs/tx" "3.0.0" + "@keystonehq/bc-ur-registry-eth" "^0.7.7" + ethereumjs-util "^7.0.8" + hdkey "^2.0.1" + uuid "^8.3.2" + +"@keystonehq/bc-ur-registry-eth@^0.7.7": + version "0.7.7" + resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry-eth/-/bc-ur-registry-eth-0.7.7.tgz#45267510900049050ef860a1e78fde9087b75972" + integrity sha512-2gZf18ogSCLjsn3PxGqwiOMz/G11v7byRnTLv5/wNJGzCqkMf86OKaVbUgsVokq0B5KAZtpCFQxj96rrFhPRiQ== + dependencies: + "@keystonehq/bc-ur-registry" "^0.4.4" + ethereumjs-util "^7.0.8" + hdkey "^2.0.1" + uuid "^8.3.2" + +"@keystonehq/bc-ur-registry@^0.4.4": + version "0.4.4" + resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry/-/bc-ur-registry-0.4.4.tgz#3073fdd4b33cdcbd04526a313a7685891a4b4583" + integrity sha512-SBdKdAZfp3y14GTGrKjfJJHf4iXObjcm4/qKUZ92lj8HVR8mxHHGmHksjE328bJPTAsJPloLix4rTnWg+qgS2w== + dependencies: + "@ngraveio/bc-ur" "^1.1.5" + base58check "^2.0.0" + tslib "^2.3.0" + +"@keystonehq/metamask-airgapped-keyring@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@keystonehq/metamask-airgapped-keyring/-/metamask-airgapped-keyring-0.2.2.tgz#8beb3e3fddf814be05e3c3178f973769b3ab40d7" + integrity sha512-1tuSNpc98jEoJ/9sptasxG6hm8KzESx0ShbKtPkNNKP+XxcDuMi632n03E748X98leCscI+M1WlRvsTryiEB8Q== + dependencies: + "@ethereumjs/tx" "^3.3.0" + "@keystonehq/base-eth-keyring" "^0.3.2" + "@keystonehq/bc-ur-registry-eth" "^0.7.7" + "@metamask/obs-store" "^7.0.0" + rlp "^2.2.6" + uuid "^8.3.2" + "@lavamoat/allow-scripts@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@lavamoat/allow-scripts/-/allow-scripts-1.0.6.tgz#fbdf7c35a5c2c2cff05ba002b7bc8f3355bda22c" @@ -1107,6 +1170,14 @@ resolved "https://registry.yarnpkg.com/@metamask/metamask-eth-abis/-/metamask-eth-abis-3.0.0.tgz#eccc0746b3ab1ab63000444403819c16e88b5272" integrity sha512-YtIl4e1VzqwwHGafuLIVPqbcWWWqQ0Ezo8/Ci5m5OGllqE2oTTx9iVHdUmXNkgCVD37SBfwn/fm/S1IGkM8BQA== +"@metamask/obs-store@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@metamask/obs-store/-/obs-store-7.0.0.tgz#6cae5f28306bb3e83a381bc9ae22682316095bd3" + integrity sha512-Tr61Uu9CGXkCg5CZwOYRMQERd+y6fbtrtLd/PzDTPHO5UJpmSbU+7MPcQK7d1DwZCOCeCIvhmZSUCvYliC8uGw== + dependencies: + "@metamask/safe-event-emitter" "^2.0.0" + through2 "^2.0.3" + "@metamask/safe-event-emitter@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c" @@ -1117,6 +1188,19 @@ resolved "https://registry.yarnpkg.com/@metamask/types/-/types-1.1.0.tgz#9bd14b33427932833c50c9187298804a18c2e025" integrity sha512-EEV/GjlYkOSfSPnYXfOosxa3TqYtIW3fhg6jdw+cok/OhMgNn4wCfbENFqjytrHMU2f7ZKtBAvtiP5V8H44sSw== +"@ngraveio/bc-ur@^1.1.5": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@ngraveio/bc-ur/-/bc-ur-1.1.6.tgz#8f8c75fff22f6a5e4dfbc5a6b540d7fe8f42cd39" + integrity sha512-G+2XgjXde2IOcEQeCwR250aS43/Swi7gw0FuETgJy2c3HqF8f88SXDMsIGgJlZ8jXd0GeHR4aX0MfjXf523UZg== + dependencies: + "@apocentre/alias-sampling" "^0.5.3" + assert "^2.0.0" + bignumber.js "^9.0.1" + cbor-sync "^1.0.4" + crc "^3.8.0" + jsbi "^3.1.5" + sha.js "^2.4.11" + "@nodelib/fs.scandir@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" @@ -1821,6 +1905,16 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= +assert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== + dependencies: + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" + assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" @@ -1877,6 +1971,11 @@ atob@^2.1.1: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -1967,6 +2066,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-x@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-1.1.0.tgz#42d3d717474f9ea02207f6d1aa1f426913eeb7ac" + integrity sha1-QtPXF0dPnqAiB/bRqh9CaRPut6w= + base-x@^3.0.2: version "3.0.8" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" @@ -1974,11 +2078,23 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" +base58check@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base58check/-/base58check-2.0.0.tgz#8046652d14bc87f063bd16be94a39134d3b61173" + integrity sha1-gEZlLRS8h/BjvRa+lKORNNO2EXM= + dependencies: + bs58 "^3.0.0" + base64-js@^1.0.2: version "1.3.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -2004,6 +2120,11 @@ bech32@1.1.4: resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== +bignumber.js@^9.0.1: + version "9.0.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" + integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== + "bignumber.js@git+https://github.com/frozeman/bignumber.js-nolookahead.git": version "2.0.7" resolved "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" @@ -2058,6 +2179,11 @@ bn.js@^5.1.2: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== +bn.js@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2138,6 +2264,13 @@ bs-logger@0.x: dependencies: fast-json-stable-stringify "2.x" +bs58@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-3.1.0.tgz#d4c26388bf4804cac714141b1945aa47e5eb248e" + integrity sha1-1MJjiL9IBMrHFBQbGUWqR+XrJI4= + dependencies: + base-x "^1.1.0" + bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" @@ -2176,6 +2309,14 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= +buffer@^5.1.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + buffer@^5.2.1: version "5.4.0" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.0.tgz#33294f5c1f26e08461e528b69fa06de3c45cbd8c" @@ -2199,6 +2340,14 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2226,6 +2375,11 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +cbor-sync@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cbor-sync/-/cbor-sync-1.0.4.tgz#5a11a1ab75c2a14d1af1b237fd84aa8c1593662f" + integrity sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA== + chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2445,6 +2599,13 @@ crc-32@^1.2.0: exit-on-epipe "~1.0.1" printj "~1.1.0" +crc@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" + integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ== + dependencies: + buffer "^5.1.0" + create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" @@ -2738,7 +2899,7 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.4.1, elliptic@^6.5.2: +elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.4.1, elliptic@^6.5.2, elliptic@^6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -2811,6 +2972,32 @@ es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" +es-abstract@^1.18.5: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + es-abstract@^1.5.0: version "1.13.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" @@ -2841,6 +3028,11 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -3406,6 +3598,17 @@ ethereumjs-util@^7.0.2: ethjs-util "0.1.6" rlp "^2.2.4" +ethereumjs-util@^7.0.7, ethereumjs-util@^7.0.8, ethereumjs-util@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.3.tgz#b55d7b64dde3e3e45749e4c41288238edec32d23" + integrity sha512-y+82tEbyASO0K0X1/SRhbJJoAlfcvq8JbrG4a5cjrOks7HS/36efU/0j2flxCPOUM++HFahk33kr/ZxyC4vNuw== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + ethereumjs-util@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz#e2b43a30bfcdbcb432a4eb42bd5f2393209b3fd5" @@ -3881,6 +4084,11 @@ for-in@^1.0.2: resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -3963,6 +4171,15 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -3982,6 +4199,14 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -4116,6 +4341,11 @@ har-validator@~5.1.0, har-validator@~5.1.3: ajv "^6.5.5" har-schema "^2.0.0" +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -4136,6 +4366,18 @@ has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -4195,6 +4437,15 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hdkey@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/hdkey/-/hdkey-2.0.1.tgz#0a211d0c510bfc44fa3ec9d44b13b634641cad74" + integrity sha512-c+tl9PHG9/XkGgG0tD7CJpRVaE0jfZizDNmnErUAKQ4EjQSOcOUcV3EN9ZEZS8pZ4usaeiiK0H7stzuzna8feA== + dependencies: + bs58check "^2.1.2" + safe-buffer "^5.1.1" + secp256k1 "^4.0.0" + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -4261,6 +4512,11 @@ idna-uts46-hx@^2.3.1: dependencies: punycode "2.1.0" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ieee754@^1.1.4: version "1.1.13" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" @@ -4333,6 +4589,15 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" @@ -4357,11 +4622,34 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -4377,6 +4665,11 @@ is-callable@^1.2.0: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw== +is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -4496,6 +4789,13 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" @@ -4508,6 +4808,26 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= +is-nan@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -4551,6 +4871,19 @@ is-regex@^1.1.0: dependencies: has-symbols "^1.0.1" +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -4566,6 +4899,13 @@ is-string@^1.0.5: resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== +is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + is-symbol@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" @@ -4573,11 +4913,36 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.0" +is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.3, is-typed-array@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" + integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.18.5" + foreach "^2.0.5" + has-tostringtag "^1.0.0" + is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -5183,6 +5548,11 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +jsbi@^3.1.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.2.5.tgz#b37bb90e0e5c2814c1c2a1bcd8c729888a2e37d6" + integrity sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ== + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -6004,11 +6374,24 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + object-inspect@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -6036,6 +6419,16 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" +object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -6846,6 +7239,13 @@ rlp@^2.2.4: dependencies: bn.js "^4.11.1" +rlp@^2.2.6: + version "2.2.7" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + rsvp@^4.8.4: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" @@ -6938,6 +7338,15 @@ secp256k1@^3.0.1: nan "^2.14.0" safe-buffer "^5.1.2" +secp256k1@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" + integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== + dependencies: + elliptic "^6.5.4" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + secp256k1@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.2.tgz#15dd57d0f0b9fdb54ac1fa1694f40e5e9a54f4a1" @@ -6999,7 +7408,7 @@ setimmediate@^1.0.5: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= -sha.js@^2.4.0, sha.js@^2.4.8: +sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== @@ -7060,6 +7469,15 @@ shiki@^0.9.3: onigasm "^2.2.5" vscode-textmate "^5.2.0" +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -7321,6 +7739,14 @@ string.prototype.trimend@^1.0.1: define-properties "^1.1.3" es-abstract "^1.17.5" +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + string.prototype.trimstart@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" @@ -7329,6 +7755,14 @@ string.prototype.trimstart@^1.0.1: define-properties "^1.1.3" es-abstract "^1.17.5" +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -7606,6 +8040,11 @@ tslib@^2.0.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -7709,9 +8148,9 @@ typedoc@^0.20.32: typedoc-default-themes "^0.12.9" typescript@~4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.2.tgz#1450f020618f872db0ea17317d16d8da8ddb8c4c" - integrity sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ== + version "4.2.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" + integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== uglify-js@^3.1.4: version "3.6.5" @@ -7721,6 +8160,16 @@ uglify-js@^3.1.4: commander "~2.20.3" source-map "~0.6.1" +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -7781,6 +8230,18 @@ util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +util@^0.12.0: + version "0.12.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" + integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + uuid@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" @@ -7951,11 +8412,34 @@ whatwg-url@^8.0.0: tr46 "^2.0.2" webidl-conversions "^6.1.0" +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= +which-typed-array@^1.1.2: + version "1.1.7" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" + integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.18.5" + foreach "^2.0.5" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.7" + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" From db807486dda76734cc9c9387125297b1f486ff6e Mon Sep 17 00:00:00 2001 From: Soralit Date: Fri, 18 Feb 2022 16:32:12 +0800 Subject: [PATCH 02/18] fix bugs when signing typed message with QR hardware --- src/keyring/KeyringController.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index da79ff2fd6d..e674370d6aa 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -445,6 +445,12 @@ export class KeyringController extends BaseController< qrAddress.toLowerCase() === address.toLowerCase(), ) ) { + if (version !== 'V1') { + // But we don't have to require that. We can stop suggesting it now: + if (typeof messageParams.data === 'string') { + messageParams.data = JSON.parse(messageParams.data); + } + } return privates .get(this) .keyring.signTypedMessage(messageParams, { version }); From ab0ea202cb265bd6cf1f2c7438d2b43ecc43b351 Mon Sep 17 00:00:00 2001 From: Soralit Date: Fri, 18 Feb 2022 19:41:52 +0800 Subject: [PATCH 03/18] use keyring name as account label --- src/keyring/KeyringController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index e674370d6aa..988f0f117ff 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -689,7 +689,7 @@ export class KeyringController extends BaseController< newAccounts.forEach((address: string) => { if (!oldAccounts.includes(address)) { if (this.setAccountLabel) { - this.setAccountLabel(address, `QR Hardware ${index}`); + this.setAccountLabel(address, `${keyring.getName()} ${index}`); } this.setSelectedAddress(address); } From 4b79b45e8439d28190f4ce46d60cc48c2cd965dc Mon Sep 17 00:00:00 2001 From: Soralit Date: Mon, 21 Feb 2022 11:47:49 +0800 Subject: [PATCH 04/18] update selected address after forget QR keyring --- src/keyring/KeyringController.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 988f0f117ff..2ae9f6d8ba2 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -705,7 +705,12 @@ export class KeyringController extends BaseController< async forgetQRDevice() { const keyring = await this.getQRKeyring(); keyring.forgetDevice(); - await this.fullUpdate(); + const accounts = (await privates + .get(this) + .keyring.getAccounts()) as string[]; + accounts.forEach((account) => { + this.setSelectedAddress(account); + }); return true; } } From 56c4af449a5f3f13750bbfe4927cf96ef78b392f Mon Sep 17 00:00:00 2001 From: Soralit Date: Mon, 21 Feb 2022 16:52:57 +0800 Subject: [PATCH 05/18] should persist keyrings after QR keyring was forgot --- src/keyring/KeyringController.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 2ae9f6d8ba2..f3b58eb2425 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -711,6 +711,8 @@ export class KeyringController extends BaseController< accounts.forEach((account) => { this.setSelectedAddress(account); }); + await privates.get(this).keyring.persistAllKeyrings(); + await this.fullUpdate(); return true; } } From e6132ccb44de6742a4124646aa4410e5b2400892 Mon Sep 17 00:00:00 2001 From: Soralit Date: Tue, 22 Feb 2022 10:46:46 +0800 Subject: [PATCH 06/18] support sync QR crypto-account, rename methods for naming consistence --- src/keyring/KeyringController.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index f3b58eb2425..b773e230690 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -648,14 +648,17 @@ export class KeyringController extends BaseController< submitQRCryptoHDKey = async (cryptoHDKey: any) => (await this.getQRKeyring()).submitCryptoHDKey(cryptoHDKey); + submitQRCryptoAccount = async (cryptoAccount: any) => + (await this.getQRKeyring()).submitCryptoAccount(cryptoAccount); + cancelSyncQRCryptoHDKey = async () => // eslint-disable-next-line node/no-sync (await this.getQRKeyring()).cancelSync(); - submitQRHardwareSignature = async (requestId: string, ethSignature: any) => + submitQRSignature = async (requestId: string, ethSignature: any) => (await this.getQRKeyring()).submitSignature(requestId, ethSignature); - cancelQRHardwareSignRequest = async () => + cancelQRSignRequest = async () => (await this.getQRKeyring()).cancelSignRequest(); connectQRHardware = async (page: number) => { From 35b8a5b3f0c401326e03f885254916a17eacad6d Mon Sep 17 00:00:00 2001 From: Soralit Date: Tue, 22 Feb 2022 13:33:58 +0800 Subject: [PATCH 07/18] should name qr hardware account from 1 --- src/keyring/KeyringController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index b773e230690..c89937c6260 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -692,7 +692,7 @@ export class KeyringController extends BaseController< newAccounts.forEach((address: string) => { if (!oldAccounts.includes(address)) { if (this.setAccountLabel) { - this.setAccountLabel(address, `${keyring.getName()} ${index}`); + this.setAccountLabel(address, `${keyring.getName()} ${index + 1}`); } this.setSelectedAddress(address); } From 02d574cdd204b7bee741c8d16feb4f3d52698cff Mon Sep 17 00:00:00 2001 From: Soralit Date: Thu, 24 Feb 2022 16:02:20 +0800 Subject: [PATCH 08/18] support sync address balance when connect QR hardware --- src/assets/AccountTrackerController.ts | 23 +++++++++++++++++++++++ src/keyring/KeyringController.ts | 9 +++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/assets/AccountTrackerController.ts b/src/assets/AccountTrackerController.ts index 176a8d5feb6..994c907e293 100644 --- a/src/assets/AccountTrackerController.ts +++ b/src/assets/AccountTrackerController.ts @@ -155,6 +155,29 @@ export class AccountTrackerController extends BaseController< }); } }; + + /** + * Sync accounts balances with some additional addresses. + * + * @param addresses - the additional addresses, may be hardware wallet addresses. + * @returns accounts - current state accounts + */ + syncWithAddresses = async (addresses: string[]) => { + this.syncAccounts(); + const { accounts } = this.state; + addresses.forEach((address) => { + accounts[address] = { balance: '0x0' }; + }); + + for (const address in accounts) { + await safelyExecuteWithTimeout(async () => { + const balance = await query(this.ethQuery, 'getBalance', [address]); + accounts[address] = { balance: BNToHex(balance) }; + this.update({ accounts: { ...accounts } }); + }); + } + return this.state.accounts; + }; } export default AccountTrackerController; diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index c89937c6260..557f0783027 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -664,7 +664,7 @@ export class KeyringController extends BaseController< connectQRHardware = async (page: number) => { try { const keyring = await this.getQRKeyring(); - let accounts = []; + let accounts: any[]; switch (page) { case -1: accounts = await keyring.getPreviousPage(); @@ -675,7 +675,12 @@ export class KeyringController extends BaseController< default: accounts = await keyring.getFirstPage(); } - return accounts; + return accounts.map((account: any) => { + return { + ...account, + balance: '0x0', + }; + }); } catch (e) { throw new Error('Unspecified error when connect QR Hardware'); } From 9e3e80e2e234d06b44d6accd4bc7428de21fecda Mon Sep 17 00:00:00 2001 From: Soralit Date: Fri, 25 Feb 2022 17:25:29 +0800 Subject: [PATCH 09/18] should save the state when adding new QR account --- src/keyring/KeyringController.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 557f0783027..15fef7dca2a 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -702,6 +702,7 @@ export class KeyringController extends BaseController< this.setSelectedAddress(address); } }); + await privates.get(this).keyring.persistAllKeyrings(); return this.fullUpdate(); } From 596164dc2756c63ff002c47d14b5d8dac7adf519 Mon Sep 17 00:00:00 2001 From: Soralit Date: Thu, 10 Mar 2022 20:02:42 +0800 Subject: [PATCH 10/18] add method to restore QR keyring --- src/keyring/KeyringController.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 15fef7dca2a..985fa020a32 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -638,6 +638,12 @@ export class KeyringController extends BaseController< return await this.addQRKeyring(); } + restoreQRKeyring = async (serialized: any) => { + (await this.getQRKeyring()).deserialize(serialized); + this.updateIdentities(await privates.get(this).keyring.getAccounts()); + this.fullUpdate(); + }; + getQRKeyringState = async () => { return (await this.getQRKeyring()).getMemStore(); }; From 01493de971ad1cca3f5f1698bb4e033df98b855f Mon Sep 17 00:00:00 2001 From: Soralit Date: Mon, 14 Mar 2022 15:45:43 +0800 Subject: [PATCH 11/18] resolve code issues --- src/assets/AccountTrackerController.ts | 8 +-- src/keyring/KeyringController.ts | 77 ++++++++++++++------------ 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/assets/AccountTrackerController.ts b/src/assets/AccountTrackerController.ts index 994c907e293..ec2efee4870 100644 --- a/src/assets/AccountTrackerController.ts +++ b/src/assets/AccountTrackerController.ts @@ -146,14 +146,14 @@ export class AccountTrackerController extends BaseController< */ refresh = async () => { this.syncAccounts(); - const { accounts } = this.state; + const accounts = Object.assign({}, this.state.accounts); for (const address in accounts) { await safelyExecuteWithTimeout(async () => { const balance = await query(this.ethQuery, 'getBalance', [address]); accounts[address] = { balance: BNToHex(balance) }; - this.update({ accounts: { ...accounts } }); }); } + this.update({ accounts: { ...accounts } }); }; /** @@ -164,7 +164,7 @@ export class AccountTrackerController extends BaseController< */ syncWithAddresses = async (addresses: string[]) => { this.syncAccounts(); - const { accounts } = this.state; + const accounts = Object.assign({}, this.state.accounts); addresses.forEach((address) => { accounts[address] = { balance: '0x0' }; }); @@ -173,9 +173,9 @@ export class AccountTrackerController extends BaseController< await safelyExecuteWithTimeout(async () => { const balance = await query(this.ethQuery, 'getBalance', [address]); accounts[address] = { balance: BNToHex(balance) }; - this.update({ accounts: { ...accounts } }); }); } + this.update({ accounts }); return this.state.accounts; }; } diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 985fa020a32..7af3214a2c9 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -437,23 +437,24 @@ export class KeyringController extends BaseController< ) { try { const address = normalizeAddress(messageParams.from); - const QRKeyring = await this.getQRKeyring(); + const QRKeyring = await this.getOrAddQRKeyring(); const qrAccounts = await QRKeyring.getAccounts(); if ( - qrAccounts.find( + qrAccounts.findIndex( (qrAddress: string) => qrAddress.toLowerCase() === address.toLowerCase(), ) ) { - if (version !== 'V1') { - // But we don't have to require that. We can stop suggesting it now: - if (typeof messageParams.data === 'string') { - messageParams.data = JSON.parse(messageParams.data); - } + const messageParamsClone = Object.assign({}, messageParams); + if ( + version !== SignTypedDataVersion.V1 && + typeof messageParamsClone.data === 'string' + ) { + messageParamsClone.data = JSON.parse(messageParamsClone.data); } return privates .get(this) - .keyring.signTypedMessage(messageParams, { version }); + .keyring.signTypedMessage(messageParamsClone, { version }); } const { password } = privates.get(this).keyring; const privateKey = await this.exportAccount(password, address); @@ -628,7 +629,7 @@ export class KeyringController extends BaseController< * * @returns The added keyring */ - private async getQRKeyring() { + private async getOrAddQRKeyring() { const keyring = privates .get(this) .keyring.getKeyringsByType(KeyringTypes.qr)[0]; @@ -638,38 +639,44 @@ export class KeyringController extends BaseController< return await this.addQRKeyring(); } - restoreQRKeyring = async (serialized: any) => { - (await this.getQRKeyring()).deserialize(serialized); + async restoreQRKeyring(serialized: any) { + (await this.getOrAddQRKeyring()).deserialize(serialized); this.updateIdentities(await privates.get(this).keyring.getAccounts()); this.fullUpdate(); - }; + } - getQRKeyringState = async () => { - return (await this.getQRKeyring()).getMemStore(); - }; + async getQRKeyringState() { + return (await this.getOrAddQRKeyring()).getMemStore(); + } - submitQRKeyring = async (cryptoHDKey: any) => - (await this.getQRKeyring()).syncKeyring(cryptoHDKey); + async submitQRKeyring(cryptoHDKey: any) { + return (await this.getOrAddQRKeyring()).syncKeyring(cryptoHDKey); + } - submitQRCryptoHDKey = async (cryptoHDKey: any) => - (await this.getQRKeyring()).submitCryptoHDKey(cryptoHDKey); + async submitQRCryptoHDKey(cryptoHDKey: any) { + (await this.getOrAddQRKeyring()).submitCryptoHDKey(cryptoHDKey); + } - submitQRCryptoAccount = async (cryptoAccount: any) => - (await this.getQRKeyring()).submitCryptoAccount(cryptoAccount); + async submitQRCryptoAccount(cryptoAccount: any) { + (await this.getOrAddQRKeyring()).submitCryptoAccount(cryptoAccount); + } - cancelSyncQRCryptoHDKey = async () => + async cancelSyncQRCryptoHDKey() { // eslint-disable-next-line node/no-sync - (await this.getQRKeyring()).cancelSync(); + (await this.getOrAddQRKeyring()).cancelSync(); + } - submitQRSignature = async (requestId: string, ethSignature: any) => - (await this.getQRKeyring()).submitSignature(requestId, ethSignature); + async submitQRSignature(requestId: string, ethSignature: any) { + (await this.getOrAddQRKeyring()).submitSignature(requestId, ethSignature); + } - cancelQRSignRequest = async () => - (await this.getQRKeyring()).cancelSignRequest(); + async cancelQRSignRequest() { + (await this.getOrAddQRKeyring()).cancelSignRequest(); + } - connectQRHardware = async (page: number) => { + async connectQRHardware(page: number) { try { - const keyring = await this.getQRKeyring(); + const keyring = await this.getOrAddQRKeyring(); let accounts: any[]; switch (page) { case -1: @@ -688,12 +695,12 @@ export class KeyringController extends BaseController< }; }); } catch (e) { - throw new Error('Unspecified error when connect QR Hardware'); + throw new Error(`Unspecified error when connect QR Hardware, ${e}`); } - }; + } async unlockQRHardwareWalletAccount(index: number) { - const keyring = await this.getQRKeyring(); + const keyring = await this.getOrAddQRKeyring(); keyring.setAccountToUnlock(index); const oldAccounts = await privates.get(this).keyring.getAccounts(); @@ -702,9 +709,7 @@ export class KeyringController extends BaseController< this.updateIdentities(newAccounts); newAccounts.forEach((address: string) => { if (!oldAccounts.includes(address)) { - if (this.setAccountLabel) { - this.setAccountLabel(address, `${keyring.getName()} ${index + 1}`); - } + this.setAccountLabel(address, `${keyring.getName()} ${index + 1}`); this.setSelectedAddress(address); } }); @@ -718,7 +723,7 @@ export class KeyringController extends BaseController< } async forgetQRDevice() { - const keyring = await this.getQRKeyring(); + const keyring = await this.getOrAddQRKeyring(); keyring.forgetDevice(); const accounts = (await privates .get(this) From 29fabce68c74dfbc790942478505ea816a9f5a1c Mon Sep 17 00:00:00 2001 From: Soralit Date: Mon, 14 Mar 2022 16:35:16 +0800 Subject: [PATCH 12/18] keep account label consistent with Keystone --- src/keyring/KeyringController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 7af3214a2c9..8c984eb018a 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -709,7 +709,7 @@ export class KeyringController extends BaseController< this.updateIdentities(newAccounts); newAccounts.forEach((address: string) => { if (!oldAccounts.includes(address)) { - this.setAccountLabel(address, `${keyring.getName()} ${index + 1}`); + this.setAccountLabel(address, `${keyring.getName()} ${index}`); this.setSelectedAddress(address); } }); From 2a0d54f59635b1356b5fff40eb8090ebaa6c2579 Mon Sep 17 00:00:00 2001 From: Soralit Date: Tue, 15 Mar 2022 10:58:38 +0800 Subject: [PATCH 13/18] optimize code --- src/assets/AccountTrackerController.ts | 39 ++++++++++++++------------ src/keyring/KeyringController.ts | 11 +++----- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/assets/AccountTrackerController.ts b/src/assets/AccountTrackerController.ts index ec2efee4870..8537a67d88f 100644 --- a/src/assets/AccountTrackerController.ts +++ b/src/assets/AccountTrackerController.ts @@ -1,6 +1,6 @@ import EthQuery from 'eth-query'; import { Mutex } from 'async-mutex'; -import { BaseController, BaseConfig, BaseState } from '../BaseController'; +import { BaseConfig, BaseController, BaseState } from '../BaseController'; import { PreferencesState } from '../user/PreferencesController'; import { BNToHex, query, safelyExecuteWithTimeout } from '../util'; @@ -146,37 +146,40 @@ export class AccountTrackerController extends BaseController< */ refresh = async () => { this.syncAccounts(); - const accounts = Object.assign({}, this.state.accounts); + const accounts = { ...this.state.accounts }; for (const address in accounts) { await safelyExecuteWithTimeout(async () => { const balance = await query(this.ethQuery, 'getBalance', [address]); accounts[address] = { balance: BNToHex(balance) }; }); } - this.update({ accounts: { ...accounts } }); + this.update({ accounts }); }; /** * Sync accounts balances with some additional addresses. * * @param addresses - the additional addresses, may be hardware wallet addresses. - * @returns accounts - current state accounts + * @returns accounts - addresses with synced balance */ - syncWithAddresses = async (addresses: string[]) => { - this.syncAccounts(); - const accounts = Object.assign({}, this.state.accounts); - addresses.forEach((address) => { - accounts[address] = { balance: '0x0' }; + syncBalanceWithAddresses = async (addresses: string[]) => { + return await Promise.all( + addresses.map((address) => { + return safelyExecuteWithTimeout(async () => { + const balance = await query(this.ethQuery, 'getBalance', [address]); + return [address, balance]; + }); + }), + ).then((value) => { + return value.reduce((obj, [address, balance]) => { + return { + ...obj, + [address]: { + balance, + }, + }; + }, {}); }); - - for (const address in accounts) { - await safelyExecuteWithTimeout(async () => { - const balance = await query(this.ethQuery, 'getBalance', [address]); - accounts[address] = { balance: BNToHex(balance) }; - }); - } - this.update({ accounts }); - return this.state.accounts; }; } diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 8c984eb018a..5b11c2e9613 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -437,15 +437,15 @@ export class KeyringController extends BaseController< ) { try { const address = normalizeAddress(messageParams.from); - const QRKeyring = await this.getOrAddQRKeyring(); - const qrAccounts = await QRKeyring.getAccounts(); + const qrKeyring = await this.getOrAddQRKeyring(); + const qrAccounts = await qrKeyring.getAccounts(); if ( qrAccounts.findIndex( (qrAddress: string) => qrAddress.toLowerCase() === address.toLowerCase(), ) ) { - const messageParamsClone = Object.assign({}, messageParams); + const messageParamsClone = { ...messageParams }; if ( version !== SignTypedDataVersion.V1 && typeof messageParamsClone.data === 'string' @@ -633,10 +633,7 @@ export class KeyringController extends BaseController< const keyring = privates .get(this) .keyring.getKeyringsByType(KeyringTypes.qr)[0]; - if (keyring) { - return keyring; - } - return await this.addQRKeyring(); + return keyring || (await this.addQRKeyring()); } async restoreQRKeyring(serialized: any) { From 65a183c3a6cc1357d0e92d2693250fcc0d7a2d22 Mon Sep 17 00:00:00 2001 From: Soralit Date: Thu, 17 Mar 2022 21:52:26 +0800 Subject: [PATCH 14/18] update code / add resetQRKeyringState method to KeyringController / add type for KeyringController new methods --- package.json | 1 + src/assets/AccountTrackerController.test.ts | 18 ++++++++ src/assets/AccountTrackerController.ts | 25 +++++++---- src/keyring/KeyringController.test.ts | 8 +++- src/keyring/KeyringController.ts | 48 +++++++++++++-------- yarn.lock | 40 ++++++++--------- 6 files changed, 91 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index 011825a3d6c..346a38b42af 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "web3-provider-engine": "^16.0.3" }, "devDependencies": { + "@keystonehq/metamask-airgapped-keyring": "^0.2.6-alpha.1", "@lavamoat/allow-scripts": "^1.0.6", "@metamask/auto-changelog": "^2.5.0", "@metamask/eslint-config": "^9.0.0", diff --git a/src/assets/AccountTrackerController.test.ts b/src/assets/AccountTrackerController.test.ts index 7c0fc7cd732..d5cd4bbad87 100644 --- a/src/assets/AccountTrackerController.test.ts +++ b/src/assets/AccountTrackerController.test.ts @@ -2,6 +2,7 @@ import { stub, spy } from 'sinon'; import HttpProvider from 'ethjs-provider-http'; import type { ContactEntry } from '../user/AddressBookController'; import { PreferencesController } from '../user/PreferencesController'; +import * as utils from '../util'; import { AccountTrackerController } from './AccountTrackerController'; const provider = new HttpProvider( @@ -44,6 +45,23 @@ describe('AccountTrackerController', () => { expect(controller.state.accounts[address].balance).toBeDefined(); }); + it('should sync balance with addresses', async () => { + const address = '0xc38bf1ad06ef69f0c04e29dbeb4152b4175f0a8d'; + const queryStub = stub(utils, 'query'); + const controller = new AccountTrackerController( + { + onPreferencesStateChange: stub(), + getIdentities: () => { + return {}; + }, + }, + { provider }, + ); + queryStub.returns(Promise.resolve('0x10')); + const result = await controller.syncBalanceWithAddresses([address]); + expect(result[address].balance).toBe('0x10'); + }); + it('should sync addresses', () => { const controller = new AccountTrackerController( { diff --git a/src/assets/AccountTrackerController.ts b/src/assets/AccountTrackerController.ts index 8537a67d88f..5c202eac712 100644 --- a/src/assets/AccountTrackerController.ts +++ b/src/assets/AccountTrackerController.ts @@ -162,16 +162,23 @@ export class AccountTrackerController extends BaseController< * @param addresses - the additional addresses, may be hardware wallet addresses. * @returns accounts - addresses with synced balance */ - syncBalanceWithAddresses = async (addresses: string[]) => { + async syncBalanceWithAddresses(addresses: string[]) { return await Promise.all( - addresses.map((address) => { - return safelyExecuteWithTimeout(async () => { - const balance = await query(this.ethQuery, 'getBalance', [address]); - return [address, balance]; - }); - }), + addresses.map( + (address): Promise<[string, string] | undefined> => { + return safelyExecuteWithTimeout(async () => { + const balance = await query(this.ethQuery, 'getBalance', [address]); + return [address, balance]; + }); + }, + ), ).then((value) => { - return value.reduce((obj, [address, balance]) => { + return value.reduce((obj, item) => { + if (!item) { + return obj; + } + + const [address, balance] = item; return { ...obj, [address]: { @@ -180,7 +187,7 @@ export class AccountTrackerController extends BaseController< }; }, {}); }); - }; + } } export default AccountTrackerController; diff --git a/src/keyring/KeyringController.test.ts b/src/keyring/KeyringController.test.ts index 627358c8b08..15e777d2a48 100644 --- a/src/keyring/KeyringController.test.ts +++ b/src/keyring/KeyringController.test.ts @@ -8,6 +8,7 @@ import { import { stub } from 'sinon'; import Common from '@ethereumjs/common'; import { TransactionFactory } from '@ethereumjs/tx'; +import { MetaMaskKeyring as QRKeyring } from '@keystonehq/metamask-airgapped-keyring'; import MockEncryptor from '../../tests/mocks/mockEncryptor'; import { PreferencesController } from '../user/PreferencesController'; import { @@ -40,11 +41,16 @@ describe('KeyringController', () => { keyringTypes: string[]; keyrings: Keyring[]; }; - const baseConfig: Partial = { encryptor: new MockEncryptor() }; + const additionalKeyrings = [QRKeyring]; + const baseConfig: Partial = { + encryptor: new MockEncryptor(), + keyringTypes: additionalKeyrings, + }; beforeEach(async () => { preferences = new PreferencesController(); keyringController = new KeyringController( { + setAccountLabel: preferences.setAccountLabel.bind(preferences), removeIdentity: preferences.removeIdentity.bind(preferences), syncIdentities: preferences.syncIdentities.bind(preferences), updateIdentities: preferences.updateIdentities.bind(preferences), diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 5b11c2e9613..0a88cf8258a 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -14,6 +14,10 @@ import { import Wallet, { thirdparty as importers } from 'ethereumjs-wallet'; import Keyring from 'eth-keyring-controller'; import { Mutex } from 'async-mutex'; +import { + MetaMaskKeyring as QRKeyring, + IKeyringState as IQRKeyringState, +} from '@keystonehq/metamask-airgapped-keyring'; import { BaseController, BaseConfig, @@ -84,6 +88,7 @@ export interface KeyringMemState extends BaseState { */ export interface KeyringConfig extends BaseConfig { encryptor?: any; + keyringTypes?: any[]; } /** @@ -443,7 +448,7 @@ export class KeyringController extends BaseController< qrAccounts.findIndex( (qrAddress: string) => qrAddress.toLowerCase() === address.toLowerCase(), - ) + ) !== -1 ) { const messageParamsClone = { ...messageParams }; if ( @@ -620,7 +625,7 @@ export class KeyringController extends BaseController< * * @returns The added keyring */ - private async addQRKeyring() { + private async addQRKeyring(): Promise { return await privates.get(this).keyring.addNewKeyring(KeyringTypes.qr); } @@ -629,52 +634,58 @@ export class KeyringController extends BaseController< * * @returns The added keyring */ - private async getOrAddQRKeyring() { + private async getOrAddQRKeyring(): Promise { const keyring = privates .get(this) .keyring.getKeyringsByType(KeyringTypes.qr)[0]; return keyring || (await this.addQRKeyring()); } - async restoreQRKeyring(serialized: any) { + async restoreQRKeyring(serialized: any): Promise { (await this.getOrAddQRKeyring()).deserialize(serialized); this.updateIdentities(await privates.get(this).keyring.getAccounts()); - this.fullUpdate(); + await this.fullUpdate(); } - async getQRKeyringState() { + async resetQRKeyringState(): Promise { + (await this.getOrAddQRKeyring()).resetStore(); + } + + async getQRKeyringState(): Promise { return (await this.getOrAddQRKeyring()).getMemStore(); } - async submitQRKeyring(cryptoHDKey: any) { + async submitQRKeyring(cryptoHDKey: any): Promise { return (await this.getOrAddQRKeyring()).syncKeyring(cryptoHDKey); } - async submitQRCryptoHDKey(cryptoHDKey: any) { + async submitQRCryptoHDKey(cryptoHDKey: any): Promise { (await this.getOrAddQRKeyring()).submitCryptoHDKey(cryptoHDKey); } - async submitQRCryptoAccount(cryptoAccount: any) { + async submitQRCryptoAccount(cryptoAccount: any): Promise { (await this.getOrAddQRKeyring()).submitCryptoAccount(cryptoAccount); } - async cancelSyncQRCryptoHDKey() { + async cancelSyncQRCryptoHDKey(): Promise { // eslint-disable-next-line node/no-sync (await this.getOrAddQRKeyring()).cancelSync(); } - async submitQRSignature(requestId: string, ethSignature: any) { + async submitQRSignature(requestId: string, ethSignature: any): Promise { (await this.getOrAddQRKeyring()).submitSignature(requestId, ethSignature); } - async cancelQRSignRequest() { + async cancelQRSignRequest(): Promise { (await this.getOrAddQRKeyring()).cancelSignRequest(); } - async connectQRHardware(page: number) { + async connectQRHardware( + page: number, + ): Promise<{ balance: string; address: string; index: number }[]> { try { const keyring = await this.getOrAddQRKeyring(); - let accounts: any[]; + let accounts; switch (page) { case -1: accounts = await keyring.getPreviousPage(); @@ -696,7 +707,7 @@ export class KeyringController extends BaseController< } } - async unlockQRHardwareWalletAccount(index: number) { + async unlockQRHardwareWalletAccount(index: number): Promise { const keyring = await this.getOrAddQRKeyring(); keyring.setAccountToUnlock(index); @@ -711,15 +722,15 @@ export class KeyringController extends BaseController< } }); await privates.get(this).keyring.persistAllKeyrings(); - return this.fullUpdate(); + await this.fullUpdate(); } - async getAccountKeyringType(account: string) { + async getAccountKeyringType(account: string): Promise { return (await privates.get(this).keyring.getKeyringForAccount(account)) .type; } - async forgetQRDevice() { + async forgetQRDevice(): Promise { const keyring = await this.getOrAddQRKeyring(); keyring.forgetDevice(); const accounts = (await privates @@ -730,7 +741,6 @@ export class KeyringController extends BaseController< }); await privates.get(this).keyring.persistAllKeyrings(); await this.fullUpdate(); - return true; } } diff --git a/yarn.lock b/yarn.lock index b0bf0398872..4d1fd257504 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1070,44 +1070,44 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" -"@keystonehq/base-eth-keyring@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@keystonehq/base-eth-keyring/-/base-eth-keyring-0.3.2.tgz#71efe1495d4931fab5fd0016c8722fe5d9657da9" - integrity sha512-y/kv8XNRSzqcSl7fvZklBKr4MVir1OJHzqM5vC+3yvzkh3mVtN8vUjAAxHtmVVVyM8rsdqK7aYZ7paexYdpnag== +"@keystonehq/base-eth-keyring@^0.3.6-alpha.1": + version "0.3.6-alpha.1" + resolved "https://registry.yarnpkg.com/@keystonehq/base-eth-keyring/-/base-eth-keyring-0.3.6-alpha.1.tgz#6c5dbb62898ae9a2832961d76b221dac96e85d1d" + integrity sha512-f3HiBRSRlZhQo+oS6YseZbokXIC43PrfBmGsiD/F7YM7XYc1mbo8hLHGXaexTgSaBXXyZkLnYt3woy0VD8hsBQ== dependencies: "@ethereumjs/tx" "3.0.0" - "@keystonehq/bc-ur-registry-eth" "^0.7.7" + "@keystonehq/bc-ur-registry-eth" "^0.8.2-alpha.0" ethereumjs-util "^7.0.8" hdkey "^2.0.1" uuid "^8.3.2" -"@keystonehq/bc-ur-registry-eth@^0.7.7": - version "0.7.7" - resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry-eth/-/bc-ur-registry-eth-0.7.7.tgz#45267510900049050ef860a1e78fde9087b75972" - integrity sha512-2gZf18ogSCLjsn3PxGqwiOMz/G11v7byRnTLv5/wNJGzCqkMf86OKaVbUgsVokq0B5KAZtpCFQxj96rrFhPRiQ== +"@keystonehq/bc-ur-registry-eth@^0.8.2-alpha.0": + version "0.8.2-alpha.0" + resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry-eth/-/bc-ur-registry-eth-0.8.2-alpha.0.tgz#261bd34025f6d6404a739bfa1279c625b44e4d19" + integrity sha512-IOvDSDkXuEa+upaRViFPCtO1GGUNPHOP/w5ojXWRCRdWd5Gu4q6yleWWjwXgOF0xhTm0Nyz26XsYYBHfYF375A== dependencies: - "@keystonehq/bc-ur-registry" "^0.4.4" + "@keystonehq/bc-ur-registry" "^0.5.0-alpha.5" ethereumjs-util "^7.0.8" hdkey "^2.0.1" uuid "^8.3.2" -"@keystonehq/bc-ur-registry@^0.4.4": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry/-/bc-ur-registry-0.4.4.tgz#3073fdd4b33cdcbd04526a313a7685891a4b4583" - integrity sha512-SBdKdAZfp3y14GTGrKjfJJHf4iXObjcm4/qKUZ92lj8HVR8mxHHGmHksjE328bJPTAsJPloLix4rTnWg+qgS2w== +"@keystonehq/bc-ur-registry@^0.5.0-alpha.5": + version "0.5.0-alpha.5" + resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry/-/bc-ur-registry-0.5.0-alpha.5.tgz#3d1a7eab980e8445c1596cdde704215c96d6b88a" + integrity sha512-T80XI+c8pWnkq9ZbuadlhFq/+8o4TcHtq+LQsK1XfjkhBqH75tcwim0310gKxavOhaSoC1i8dSqAnrFpj+5dJw== dependencies: "@ngraveio/bc-ur" "^1.1.5" base58check "^2.0.0" tslib "^2.3.0" -"@keystonehq/metamask-airgapped-keyring@^0.2.2": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@keystonehq/metamask-airgapped-keyring/-/metamask-airgapped-keyring-0.2.2.tgz#8beb3e3fddf814be05e3c3178f973769b3ab40d7" - integrity sha512-1tuSNpc98jEoJ/9sptasxG6hm8KzESx0ShbKtPkNNKP+XxcDuMi632n03E748X98leCscI+M1WlRvsTryiEB8Q== +"@keystonehq/metamask-airgapped-keyring@^0.2.6-alpha.1": + version "0.2.6-alpha.1" + resolved "https://registry.yarnpkg.com/@keystonehq/metamask-airgapped-keyring/-/metamask-airgapped-keyring-0.2.6-alpha.1.tgz#72408aff6a43ff0accaaea97d956e8352cf14097" + integrity sha512-fRiaQn92qgPOvfQssDLjCwUsSaABxvZmdxbA2KR1Z33z73Sv8j3u5G92sJNUzCKUNvtlGKJZCLdgJqPaSrH3DQ== dependencies: "@ethereumjs/tx" "^3.3.0" - "@keystonehq/base-eth-keyring" "^0.3.2" - "@keystonehq/bc-ur-registry-eth" "^0.7.7" + "@keystonehq/base-eth-keyring" "^0.3.6-alpha.1" + "@keystonehq/bc-ur-registry-eth" "^0.8.2-alpha.0" "@metamask/obs-store" "^7.0.0" rlp "^2.2.6" uuid "^8.3.2" From 88c30c587abc83b28da2538730fc0954932207d0 Mon Sep 17 00:00:00 2001 From: Soralit Date: Fri, 18 Mar 2022 17:16:21 +0800 Subject: [PATCH 15/18] add tests --- package.json | 1 + src/assets/AccountTrackerController.ts | 2 +- src/keyring/KeyringController.test.ts | 347 ++++++++++++++++++++++++- src/keyring/KeyringController.ts | 26 +- 4 files changed, 360 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 346a38b42af..f14325e1063 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "web3-provider-engine": "^16.0.3" }, "devDependencies": { + "@keystonehq/bc-ur-registry-eth": "^0.8.2-alpha.0", "@keystonehq/metamask-airgapped-keyring": "^0.2.6-alpha.1", "@lavamoat/allow-scripts": "^1.0.6", "@metamask/auto-changelog": "^2.5.0", diff --git a/src/assets/AccountTrackerController.ts b/src/assets/AccountTrackerController.ts index 5c202eac712..b32f190d3b7 100644 --- a/src/assets/AccountTrackerController.ts +++ b/src/assets/AccountTrackerController.ts @@ -162,7 +162,7 @@ export class AccountTrackerController extends BaseController< * @param addresses - the additional addresses, may be hardware wallet addresses. * @returns accounts - addresses with synced balance */ - async syncBalanceWithAddresses(addresses: string[]) { + async syncBalanceWithAddresses(addresses: string[]): Promise> { return await Promise.all( addresses.map( (address): Promise<[string, string] | undefined> => { diff --git a/src/keyring/KeyringController.test.ts b/src/keyring/KeyringController.test.ts index 15e777d2a48..c9200bb789a 100644 --- a/src/keyring/KeyringController.test.ts +++ b/src/keyring/KeyringController.test.ts @@ -5,18 +5,23 @@ import { recoverTypedSignature_v4, recoverTypedSignatureLegacy, } from 'eth-sig-util'; -import { stub } from 'sinon'; +import { spy, stub } from 'sinon'; import Common from '@ethereumjs/common'; import { TransactionFactory } from '@ethereumjs/tx'; import { MetaMaskKeyring as QRKeyring } from '@keystonehq/metamask-airgapped-keyring'; +import * as uuid from 'uuid'; +import { ETHSignature } from '@keystonehq/bc-ur-registry-eth'; import MockEncryptor from '../../tests/mocks/mockEncryptor'; import { PreferencesController } from '../user/PreferencesController'; +import { AccountTrackerController } from '../assets/AccountTrackerController'; +import { MAINNET } from '../constants'; import { KeyringController, AccountImportStrategy, Keyring, KeyringConfig, SignTypedDataVersion, + KeyringTypes, } from './KeyringController'; const input = @@ -499,4 +504,344 @@ describe('KeyringController', () => { await keyringController.submitPassword(password); expect(listenerUnlock.called).toBe(true); }); + + describe('QR keyring', () => { + preferences = new PreferencesController(); + + const signProcessKeyringController = new KeyringController( + { + setAccountLabel: preferences.setAccountLabel.bind(preferences), + removeIdentity: preferences.removeIdentity.bind(preferences), + syncIdentities: preferences.syncIdentities.bind(preferences), + updateIdentities: preferences.updateIdentities.bind(preferences), + setSelectedAddress: preferences.setSelectedAddress.bind(preferences), + }, + baseConfig, + ); + + signProcessKeyringController.createNewVaultAndKeychain(password); + + it('should add a new QR keyring when first call QR keyring related methods', async () => { + expect( + signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ), + ).toBeUndefined(); + await signProcessKeyringController.getQRKeyringState(); + expect( + signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ), + ).toBeDefined(); + }); + + it('should setup QR keyring with crypto-hdkey', async () => { + setTimeout( + () => + signProcessKeyringController.submitQRCryptoHDKey( + 'a902f40358210219218eb65839d08bde4338640b03fdbbdec439ef880d397c2f881282c5b5d135045820e65ed63f52e3e93d48ffb55cd68c6721e58ead9b29b784b8aba58354f4a3d92905d90131a201183c020006d90130a30186182cf5183cf500f5021a5271c071030307d90130a2018400f480f40300081a625f3e6209684b657973746f6e650a706163636f756e742e7374616e64617264', + ), + 100, + ); + const firstPage = await signProcessKeyringController.connectQRHardware(0); + expect(firstPage).toHaveLength(5); + expect(firstPage[0].index).toBe(0); + + const secondPage = await signProcessKeyringController.connectQRHardware( + 1, + ); + expect(secondPage).toHaveLength(5); + expect(secondPage[0].index).toBe(5); + + const goBackPage = await signProcessKeyringController.connectQRHardware( + -1, + ); + expect(goBackPage).toStrictEqual(firstPage); + + await signProcessKeyringController.unlockQRHardwareWalletAccount(0); + await signProcessKeyringController.unlockQRHardwareWalletAccount(1); + await signProcessKeyringController.unlockQRHardwareWalletAccount(2); + + const qrKeyring = signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ); + expect(qrKeyring?.accounts).toHaveLength(3); + }); + + const composeMockSignature = (requestId: string, signature: string) => { + const rlpSignatureData = Buffer.from(signature, 'hex'); + const idBuffer = uuid.parse(requestId) as Uint8Array; + const ethSignature = new ETHSignature( + rlpSignatureData, + Buffer.from(idBuffer), + ); + return ethSignature.toCBOR().toString('hex'); + }; + + it('should sign message with QR keyring', async () => { + setTimeout(async () => { + const state = await signProcessKeyringController.getQRKeyringState(); + const requestId = state.getState().sign.request?.requestId || ''; + const signature = composeMockSignature( + requestId, + '4cb25933c5225f9f92fc9b487451b93bc3646c6aa01b72b01065b8509ac4fd6c37798695d0d5c0949ed10c5e102800ea2b62c2b670729c5631c81b0c52002a641b', + ); + signProcessKeyringController.submitQRSignature(requestId, signature); + }, 100); + + const data = + '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0'; + const qrKeyring = signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ); + const account = qrKeyring?.accounts[0] || ''; + const signature = await signProcessKeyringController.signMessage({ + data, + from: account, + }); + expect(signature).not.toBe(''); + }); + + it('should sign personal message with QR keyring', async () => { + setTimeout(async () => { + const state = await signProcessKeyringController.getQRKeyringState(); + const requestId = state.getState().sign.request?.requestId || ''; + const signature = composeMockSignature( + requestId, + '73f31609b618050c4058e8f959961c203470657e7218a21d8b94ac1bdef80f255ac5e7a07493302443296ccb20a04ebfa0c8f6ea4dd9134c19ecd65673c336261b', + ); + signProcessKeyringController.submitQRSignature(requestId, signature); + }, 100); + + const data = bufferToHex( + Buffer.from('Example `personal_sign` message', 'utf8'), + ); + const qrKeyring = signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ); + const account = qrKeyring?.accounts[0] || ''; + const signature = await signProcessKeyringController.signPersonalMessage({ + data, + from: account, + }); + const recovered = recoverPersonalSignature({ data, sig: signature }); + expect(account.toLowerCase()).toBe(recovered.toLowerCase()); + }); + + it('should sign typed message V1 with QR keyring', async () => { + setTimeout(async () => { + const state = await signProcessKeyringController.getQRKeyringState(); + const requestId = state.getState().sign.request?.requestId || ''; + const signature = composeMockSignature( + requestId, + '4b9b4cde5c883e3281a5a603179379817a94796f3a06079374db94f0b2c1882c5e708de2fa0ec84d74b3819f7baae0d310b4494d101359afe470910bec5d36071b', + ); + signProcessKeyringController.submitQRSignature(requestId, signature); + }, 100); + + const typedMsgParams = [ + { + name: 'Message', + type: 'string', + value: 'Hi, Alice!', + }, + { + name: 'A number', + type: 'uint32', + value: '1337', + }, + ]; + const qrKeyring = signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ); + const account = qrKeyring?.accounts[0] || ''; + const signature = await signProcessKeyringController.signTypedMessage( + { data: typedMsgParams, from: account }, + SignTypedDataVersion.V1, + ); + const recovered = recoverTypedSignatureLegacy({ + data: typedMsgParams, + sig: signature as string, + }); + expect(account.toLowerCase()).toBe(recovered.toLowerCase()); + }); + + it('should sign typed message V3 with QR keyring', async () => { + setTimeout(async () => { + const state = await signProcessKeyringController.getQRKeyringState(); + const requestId = state.getState().sign.request?.requestId || ''; + const signature = composeMockSignature( + requestId, + '112e4591abc834251f2671127acabebf33be3a8d8fa15312e94ba0f008e53d697930b4ae99cb36955e1c96fee888cf1ed6e314769db0bd4d6246d492b8685fd21c', + ); + signProcessKeyringController.submitQRSignature(requestId, signature); + }, 100); + + const msg = + '{"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":4,"verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","wallet":"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},"contents":"Hello, Bob!"}}'; + + const qrKeyring = signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ); + const account = qrKeyring?.accounts[0] || ''; + const signature = await signProcessKeyringController.signTypedMessage( + { + data: msg, + from: account, + }, + SignTypedDataVersion.V3, + ); + const recovered = recoverTypedSignature({ + data: JSON.parse(msg), + sig: signature as string, + }); + expect(account.toLowerCase()).toBe(recovered); + }); + + it('should sign typed message V4 with QR keyring', async () => { + setTimeout(async () => { + const state = await signProcessKeyringController.getQRKeyringState(); + const requestId = state.getState().sign.request?.requestId || ''; + const signature = composeMockSignature( + requestId, + '1271c3de4683ed99b11ceecc0a81f48701057174eb0edd729342ecdd9e061ed26eea3c4b84d232e01de00f1f3884fdfe15f664fe2c58c2e565d672b3cb281ccb1c', + ); + signProcessKeyringController.submitQRSignature(requestId, signature); + }, 100); + + const msg = + '{"domain":{"chainId":"4","name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail","types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Group":[{"name":"name","type":"string"},{"name":"members","type":"Person[]"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}'; + + const qrKeyring = signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ); + const account = qrKeyring?.accounts[0] || ''; + const signature = await signProcessKeyringController.signTypedMessage( + { data: msg, from: account }, + SignTypedDataVersion.V4, + ); + const recovered = recoverTypedSignature_v4({ + data: JSON.parse(msg), + sig: signature as string, + }); + expect(account.toLowerCase()).toBe(recovered); + }); + + it('should sign transaction with QR keyring', async () => { + setTimeout(async () => { + const state = await signProcessKeyringController.getQRKeyringState(); + const requestId = state.getState().sign.request?.requestId || ''; + const signature = composeMockSignature( + requestId, + '33ea4c1dc4b201ad1b1feaf172aadf60dcf2f8bd76d941396bfaebfc3b2868b0340d5689341925c99cdea39e3c5daf7fe2776f220e5b018e85d3b1df19c7bc4701', + ); + signProcessKeyringController.submitQRSignature(requestId, signature); + }, 100); + + const qrKeyring = signProcessKeyringController.state.keyrings.find( + (keyring) => keyring.type === KeyringTypes.qr, + ); + const account = qrKeyring?.accounts[0] || ''; + const tx = TransactionFactory.fromTxData( + { + accessList: [], + chainId: '0x4', + data: '0x', + gasLimit: '0x5208', + maxFeePerGas: '0x2540be400', + maxPriorityFeePerGas: '0x3b9aca00', + nonce: '0x68', + r: undefined, + s: undefined, + to: '0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb', + v: undefined, + value: '0x0', + type: 2, + }, + { + common: Common.forCustomChain( + MAINNET, + { + name: 'rinkeby', + chainId: parseInt('4'), + networkId: parseInt('4'), + }, + 'london', + ), + }, + ); + const signedTx = await signProcessKeyringController.signTransaction( + tx, + account, + ); + expect(signedTx.v).not.toBeUndefined(); + expect(signedTx).not.toBe(''); + }); + + it('should reset qr keyring state', async () => { + const data = + '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0'; + const account = + signProcessKeyringController.state.keyrings[1].accounts[0]; + + signProcessKeyringController.signMessage({ + data, + from: account, + }); + + setTimeout(async () => { + expect( + (await signProcessKeyringController.getQRKeyringState()).getState() + .sign.request, + ).toBeDefined(); + signProcessKeyringController.resetQRKeyringState(); + + expect( + (await signProcessKeyringController.getQRKeyringState()).getState() + .sign.request, + ).toBeUndefined(); + }, 100); + }); + + it('should forget qr keyring', async () => { + expect( + signProcessKeyringController.state.keyrings[1].accounts, + ).toHaveLength(3); + await signProcessKeyringController.forgetQRDevice(); + expect( + signProcessKeyringController.state.keyrings[1].accounts, + ).toHaveLength(0); + }); + + it('should restore qr keyring', async () => { + const serializedQRKeyring = { + initialized: true, + accounts: ['0xE410157345be56688F43FF0D9e4B2B38Ea8F7828'], + currentAccount: 0, + page: 0, + perPage: 5, + keyringAccount: 'account.standard', + keyringMode: 'hd', + name: 'Keystone', + version: 1, + xfp: '5271c071', + xpub: + 'xpub6CNhtuXAHDs84AhZj5ALZB6ii4sP5LnDXaKDSjiy6kcBbiysq89cDrLG29poKvZtX9z4FchZKTjTyiPuDeiFMUd1H4g5zViQxt4tpkronJr', + hdPath: "m/44'/60'/0'", + childrenPath: '0/*', + indexes: { + '0xE410157345be56688F43FF0D9e4B2B38Ea8F7828': 0, + '0xEEACb7a5e53600c144C0b9839A834bb4b39E540c': 1, + '0xA116800A72e56f91cF1677D40C9984f9C9f4B2c7': 2, + '0x4826BadaBC9894B3513e23Be408605611b236C0f': 3, + '0x8a1503beb17Ef02cC4Ff288b0A73583c4ce547c7': 4, + }, + paths: {}, + }; + await signProcessKeyringController.restoreQRKeyring(serializedQRKeyring); + expect( + signProcessKeyringController.state.keyrings[1].accounts, + ).toHaveLength(1); + }); + }); }); diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 0a88cf8258a..0a32737d320 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -626,7 +626,11 @@ export class KeyringController extends BaseController< * @returns The added keyring */ private async addQRKeyring(): Promise { - return await privates.get(this).keyring.addNewKeyring(KeyringTypes.qr); + const keyring = await privates + .get(this) + .keyring.addNewKeyring(KeyringTypes.qr); + await this.fullUpdate(); + return keyring; } /** @@ -634,7 +638,7 @@ export class KeyringController extends BaseController< * * @returns The added keyring */ - private async getOrAddQRKeyring(): Promise { + async getOrAddQRKeyring(): Promise { const keyring = privates .get(this) .keyring.getKeyringsByType(KeyringTypes.qr)[0]; @@ -655,24 +659,18 @@ export class KeyringController extends BaseController< return (await this.getOrAddQRKeyring()).getMemStore(); } - async submitQRKeyring(cryptoHDKey: any): Promise { - return (await this.getOrAddQRKeyring()).syncKeyring(cryptoHDKey); - } - - async submitQRCryptoHDKey(cryptoHDKey: any): Promise { + async submitQRCryptoHDKey(cryptoHDKey: string): Promise { (await this.getOrAddQRKeyring()).submitCryptoHDKey(cryptoHDKey); } - async submitQRCryptoAccount(cryptoAccount: any): Promise { + async submitQRCryptoAccount(cryptoAccount: string): Promise { (await this.getOrAddQRKeyring()).submitCryptoAccount(cryptoAccount); } - async cancelSyncQRCryptoHDKey(): Promise { - // eslint-disable-next-line node/no-sync - (await this.getOrAddQRKeyring()).cancelSync(); - } - - async submitQRSignature(requestId: string, ethSignature: any): Promise { + async submitQRSignature( + requestId: string, + ethSignature: string, + ): Promise { (await this.getOrAddQRKeyring()).submitSignature(requestId, ethSignature); } From c9233c13e9df14027166d5f54103c7ec97da7994 Mon Sep 17 00:00:00 2001 From: Soralit Date: Tue, 22 Mar 2022 17:30:50 +0800 Subject: [PATCH 16/18] resolve code issues --- src/assets/AccountTrackerController.ts | 4 +++- src/keyring/KeyringController.test.ts | 24 ++++++++++++------------ src/keyring/KeyringController.ts | 11 +++++++---- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/assets/AccountTrackerController.ts b/src/assets/AccountTrackerController.ts index b32f190d3b7..e026ce9e975 100644 --- a/src/assets/AccountTrackerController.ts +++ b/src/assets/AccountTrackerController.ts @@ -162,7 +162,9 @@ export class AccountTrackerController extends BaseController< * @param addresses - the additional addresses, may be hardware wallet addresses. * @returns accounts - addresses with synced balance */ - async syncBalanceWithAddresses(addresses: string[]): Promise> { + async syncBalanceWithAddresses( + addresses: string[], + ): Promise> { return await Promise.all( addresses.map( (address): Promise<[string, string] | undefined> => { diff --git a/src/keyring/KeyringController.test.ts b/src/keyring/KeyringController.test.ts index c9200bb789a..309330b655f 100644 --- a/src/keyring/KeyringController.test.ts +++ b/src/keyring/KeyringController.test.ts @@ -5,7 +5,7 @@ import { recoverTypedSignature_v4, recoverTypedSignatureLegacy, } from 'eth-sig-util'; -import { spy, stub } from 'sinon'; +import { stub } from 'sinon'; import Common from '@ethereumjs/common'; import { TransactionFactory } from '@ethereumjs/tx'; import { MetaMaskKeyring as QRKeyring } from '@keystonehq/metamask-airgapped-keyring'; @@ -13,7 +13,6 @@ import * as uuid from 'uuid'; import { ETHSignature } from '@keystonehq/bc-ur-registry-eth'; import MockEncryptor from '../../tests/mocks/mockEncryptor'; import { PreferencesController } from '../user/PreferencesController'; -import { AccountTrackerController } from '../assets/AccountTrackerController'; import { MAINNET } from '../constants'; import { KeyringController, @@ -51,6 +50,7 @@ describe('KeyringController', () => { encryptor: new MockEncryptor(), keyringTypes: additionalKeyrings, }; + beforeEach(async () => { preferences = new PreferencesController(); keyringController = new KeyringController( @@ -506,6 +506,16 @@ describe('KeyringController', () => { }); describe('QR keyring', () => { + const composeMockSignature = (requestId: string, signature: string) => { + const rlpSignatureData = Buffer.from(signature, 'hex'); + const idBuffer = uuid.parse(requestId) as Uint8Array; + const ethSignature = new ETHSignature( + rlpSignatureData, + Buffer.from(idBuffer), + ); + return ethSignature.toCBOR().toString('hex'); + }; + preferences = new PreferencesController(); const signProcessKeyringController = new KeyringController( @@ -568,16 +578,6 @@ describe('KeyringController', () => { expect(qrKeyring?.accounts).toHaveLength(3); }); - const composeMockSignature = (requestId: string, signature: string) => { - const rlpSignatureData = Buffer.from(signature, 'hex'); - const idBuffer = uuid.parse(requestId) as Uint8Array; - const ethSignature = new ETHSignature( - rlpSignatureData, - Buffer.from(idBuffer), - ); - return ethSignature.toCBOR().toString('hex'); - }; - it('should sign message with QR keyring', async () => { setTimeout(async () => { const state = await signProcessKeyringController.getQRKeyringState(); diff --git a/src/keyring/KeyringController.ts b/src/keyring/KeyringController.ts index 0a32737d320..b551bc5e57b 100644 --- a/src/keyring/KeyringController.ts +++ b/src/keyring/KeyringController.ts @@ -146,7 +146,7 @@ export class KeyringController extends BaseController< private setSelectedAddress: PreferencesController['setSelectedAddress']; - private setAccountLabel: PreferencesController['setAccountLabel']; + private setAccountLabel?: PreferencesController['setAccountLabel']; /** * Creates a KeyringController instance. @@ -172,7 +172,7 @@ export class KeyringController extends BaseController< syncIdentities: PreferencesController['syncIdentities']; updateIdentities: PreferencesController['updateIdentities']; setSelectedAddress: PreferencesController['setSelectedAddress']; - setAccountLabel: PreferencesController['setAccountLabel']; + setAccountLabel?: PreferencesController['setAccountLabel']; }, config?: Partial, state?: Partial, @@ -461,6 +461,7 @@ export class KeyringController extends BaseController< .get(this) .keyring.signTypedMessage(messageParamsClone, { version }); } + const { password } = privates.get(this).keyring; const privateKey = await this.exportAccount(password, address); const privateKeyBuffer = toBuffer(addHexPrefix(privateKey)); @@ -715,7 +716,9 @@ export class KeyringController extends BaseController< this.updateIdentities(newAccounts); newAccounts.forEach((address: string) => { if (!oldAccounts.includes(address)) { - this.setAccountLabel(address, `${keyring.getName()} ${index}`); + if (this.setAccountLabel) { + this.setAccountLabel(address, `${keyring.getName()} ${index}`); + } this.setSelectedAddress(address); } }); @@ -723,7 +726,7 @@ export class KeyringController extends BaseController< await this.fullUpdate(); } - async getAccountKeyringType(account: string): Promise { + async getAccountKeyringType(account: string): Promise { return (await privates.get(this).keyring.getKeyringForAccount(account)) .type; } From e1956055a47407e12abe199add1dbc978b61847b Mon Sep 17 00:00:00 2001 From: Soralit Date: Wed, 23 Mar 2022 17:26:31 +0800 Subject: [PATCH 17/18] refactor unit tests --- __mocks__/uuid.js | 14 ++ src/keyring/KeyringController.test.ts | 275 ++++++++++++++++---------- 2 files changed, 185 insertions(+), 104 deletions(-) create mode 100644 __mocks__/uuid.js diff --git a/__mocks__/uuid.js b/__mocks__/uuid.js new file mode 100644 index 00000000000..5f17ea96d77 --- /dev/null +++ b/__mocks__/uuid.js @@ -0,0 +1,14 @@ +const uuid = require('uuid'); + +// mock the v4 function of uuid lib to make sure it returns the fixed id for testing +const v4 = () => '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'; + +module.exports.NIL = uuid.NIL; +module.exports.v1 = uuid.v1; +module.exports.v3 = uuid.v3; +module.exports.v5 = uuid.v5; +module.exports.parse = uuid.parse; +module.exports.validate = uuid.validate; +module.exports.stringify = uuid.stringify; + +module.exports.v4 = v4; diff --git a/src/keyring/KeyringController.test.ts b/src/keyring/KeyringController.test.ts index 309330b655f..7aa44a4d52a 100644 --- a/src/keyring/KeyringController.test.ts +++ b/src/keyring/KeyringController.test.ts @@ -5,22 +5,22 @@ import { recoverTypedSignature_v4, recoverTypedSignatureLegacy, } from 'eth-sig-util'; -import { stub } from 'sinon'; +import sinon, { SinonStub, stub } from 'sinon'; import Common from '@ethereumjs/common'; import { TransactionFactory } from '@ethereumjs/tx'; import { MetaMaskKeyring as QRKeyring } from '@keystonehq/metamask-airgapped-keyring'; +import { CryptoHDKey, ETHSignature } from '@keystonehq/bc-ur-registry-eth'; import * as uuid from 'uuid'; -import { ETHSignature } from '@keystonehq/bc-ur-registry-eth'; import MockEncryptor from '../../tests/mocks/mockEncryptor'; import { PreferencesController } from '../user/PreferencesController'; import { MAINNET } from '../constants'; import { - KeyringController, AccountImportStrategy, Keyring, KeyringConfig, - SignTypedDataVersion, + KeyringController, KeyringTypes, + SignTypedDataVersion, } from './KeyringController'; const input = @@ -506,53 +506,84 @@ describe('KeyringController', () => { }); describe('QR keyring', () => { - const composeMockSignature = (requestId: string, signature: string) => { + const composeMockSignature = ( + requestId: string, + signature: string, + ): ETHSignature => { const rlpSignatureData = Buffer.from(signature, 'hex'); - const idBuffer = uuid.parse(requestId) as Uint8Array; - const ethSignature = new ETHSignature( + const idBuffer = uuid.parse(requestId); + return new ETHSignature( rlpSignatureData, - Buffer.from(idBuffer), + Buffer.from(Uint8Array.from(idBuffer)), ); - return ethSignature.toCBOR().toString('hex'); }; + let signProcessKeyringController: KeyringController; preferences = new PreferencesController(); - const signProcessKeyringController = new KeyringController( - { - setAccountLabel: preferences.setAccountLabel.bind(preferences), - removeIdentity: preferences.removeIdentity.bind(preferences), - syncIdentities: preferences.syncIdentities.bind(preferences), - updateIdentities: preferences.updateIdentities.bind(preferences), - setSelectedAddress: preferences.setSelectedAddress.bind(preferences), - }, - baseConfig, - ); - - signProcessKeyringController.createNewVaultAndKeychain(password); + let requestSignatureStub: SinonStub; + let readAccountSub: SinonStub; - it('should add a new QR keyring when first call QR keyring related methods', async () => { - expect( - signProcessKeyringController.state.keyrings.find( - (keyring) => keyring.type === KeyringTypes.qr, - ), - ).toBeUndefined(); - await signProcessKeyringController.getQRKeyringState(); - expect( - signProcessKeyringController.state.keyrings.find( - (keyring) => keyring.type === KeyringTypes.qr, + const setupQRKeyring = async () => { + readAccountSub.resolves( + CryptoHDKey.fromCBOR( + Buffer.from( + 'a902f40358210219218eb65839d08bde4338640b03fdbbdec439ef880d397c2f881282c5b5d135045820e65ed63f52e3e93d48ffb55cd68c6721e58ead9b29b784b8aba58354f4a3d92905d90131a201183c020006d90130a30186182cf5183cf500f5021a5271c071030307d90130a2018400f480f40300081a625f3e6209684b657973746f6e650a706163636f756e742e7374616e64617264', + 'hex', + ), ), - ).toBeDefined(); + ); + await signProcessKeyringController.connectQRHardware(0); + await signProcessKeyringController.unlockQRHardwareWalletAccount(0); + await signProcessKeyringController.unlockQRHardwareWalletAccount(1); + await signProcessKeyringController.unlockQRHardwareWalletAccount(2); + }; + + beforeEach(async () => { + signProcessKeyringController = new KeyringController( + { + setAccountLabel: preferences.setAccountLabel.bind(preferences), + removeIdentity: preferences.removeIdentity.bind(preferences), + syncIdentities: preferences.syncIdentities.bind(preferences), + updateIdentities: preferences.updateIdentities.bind(preferences), + setSelectedAddress: preferences.setSelectedAddress.bind(preferences), + }, + baseConfig, + ); + await signProcessKeyringController.createNewVaultAndKeychain(password); + const qrkeyring = await signProcessKeyringController.getOrAddQRKeyring(); + qrkeyring.forgetDevice(); + + if (!requestSignatureStub) { + requestSignatureStub = sinon.stub( + qrkeyring.getInteraction(), + 'requestSignature', + ); + } + + if (!readAccountSub) { + readAccountSub = sinon.stub( + qrkeyring.getInteraction(), + 'readCryptoHDKeyOrCryptoAccount', + ); + } + }); + + afterEach(() => { + requestSignatureStub.reset(); + readAccountSub.reset(); }); it('should setup QR keyring with crypto-hdkey', async () => { - setTimeout( - () => - signProcessKeyringController.submitQRCryptoHDKey( + readAccountSub.resolves( + CryptoHDKey.fromCBOR( + Buffer.from( 'a902f40358210219218eb65839d08bde4338640b03fdbbdec439ef880d397c2f881282c5b5d135045820e65ed63f52e3e93d48ffb55cd68c6721e58ead9b29b784b8aba58354f4a3d92905d90131a201183c020006d90130a30186182cf5183cf500f5021a5271c071030307d90130a2018400f480f40300081a625f3e6209684b657973746f6e650a706163636f756e742e7374616e64617264', + 'hex', ), - 100, + ), ); + const firstPage = await signProcessKeyringController.connectQRHardware(0); expect(firstPage).toHaveLength(5); expect(firstPage[0].index).toBe(0); @@ -579,15 +610,13 @@ describe('KeyringController', () => { }); it('should sign message with QR keyring', async () => { - setTimeout(async () => { - const state = await signProcessKeyringController.getQRKeyringState(); - const requestId = state.getState().sign.request?.requestId || ''; - const signature = composeMockSignature( - requestId, + await setupQRKeyring(); + requestSignatureStub.resolves( + composeMockSignature( + '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', '4cb25933c5225f9f92fc9b487451b93bc3646c6aa01b72b01065b8509ac4fd6c37798695d0d5c0949ed10c5e102800ea2b62c2b670729c5631c81b0c52002a641b', - ); - signProcessKeyringController.submitQRSignature(requestId, signature); - }, 100); + ), + ); const data = '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0'; @@ -603,15 +632,13 @@ describe('KeyringController', () => { }); it('should sign personal message with QR keyring', async () => { - setTimeout(async () => { - const state = await signProcessKeyringController.getQRKeyringState(); - const requestId = state.getState().sign.request?.requestId || ''; - const signature = composeMockSignature( - requestId, + await setupQRKeyring(); + requestSignatureStub.resolves( + composeMockSignature( + '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', '73f31609b618050c4058e8f959961c203470657e7218a21d8b94ac1bdef80f255ac5e7a07493302443296ccb20a04ebfa0c8f6ea4dd9134c19ecd65673c336261b', - ); - signProcessKeyringController.submitQRSignature(requestId, signature); - }, 100); + ), + ); const data = bufferToHex( Buffer.from('Example `personal_sign` message', 'utf8'), @@ -629,15 +656,13 @@ describe('KeyringController', () => { }); it('should sign typed message V1 with QR keyring', async () => { - setTimeout(async () => { - const state = await signProcessKeyringController.getQRKeyringState(); - const requestId = state.getState().sign.request?.requestId || ''; - const signature = composeMockSignature( - requestId, + await setupQRKeyring(); + requestSignatureStub.resolves( + composeMockSignature( + '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', '4b9b4cde5c883e3281a5a603179379817a94796f3a06079374db94f0b2c1882c5e708de2fa0ec84d74b3819f7baae0d310b4494d101359afe470910bec5d36071b', - ); - signProcessKeyringController.submitQRSignature(requestId, signature); - }, 100); + ), + ); const typedMsgParams = [ { @@ -667,15 +692,13 @@ describe('KeyringController', () => { }); it('should sign typed message V3 with QR keyring', async () => { - setTimeout(async () => { - const state = await signProcessKeyringController.getQRKeyringState(); - const requestId = state.getState().sign.request?.requestId || ''; - const signature = composeMockSignature( - requestId, + await setupQRKeyring(); + requestSignatureStub.resolves( + composeMockSignature( + '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', '112e4591abc834251f2671127acabebf33be3a8d8fa15312e94ba0f008e53d697930b4ae99cb36955e1c96fee888cf1ed6e314769db0bd4d6246d492b8685fd21c', - ); - signProcessKeyringController.submitQRSignature(requestId, signature); - }, 100); + ), + ); const msg = '{"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":4,"verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","wallet":"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},"contents":"Hello, Bob!"}}'; @@ -699,15 +722,13 @@ describe('KeyringController', () => { }); it('should sign typed message V4 with QR keyring', async () => { - setTimeout(async () => { - const state = await signProcessKeyringController.getQRKeyringState(); - const requestId = state.getState().sign.request?.requestId || ''; - const signature = composeMockSignature( - requestId, + await setupQRKeyring(); + requestSignatureStub.resolves( + composeMockSignature( + '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', '1271c3de4683ed99b11ceecc0a81f48701057174eb0edd729342ecdd9e061ed26eea3c4b84d232e01de00f1f3884fdfe15f664fe2c58c2e565d672b3cb281ccb1c', - ); - signProcessKeyringController.submitQRSignature(requestId, signature); - }, 100); + ), + ); const msg = '{"domain":{"chainId":"4","name":"Ether Mail","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC","version":"1"},"message":{"contents":"Hello, Bob!","from":{"name":"Cow","wallets":["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826","0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"]},"to":[{"name":"Bob","wallets":["0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB","0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57","0xB0B0b0b0b0b0B000000000000000000000000000"]}]},"primaryType":"Mail","types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Group":[{"name":"name","type":"string"},{"name":"members","type":"Person[]"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person[]"},{"name":"contents","type":"string"}],"Person":[{"name":"name","type":"string"},{"name":"wallets","type":"address[]"}]}}'; @@ -728,15 +749,13 @@ describe('KeyringController', () => { }); it('should sign transaction with QR keyring', async () => { - setTimeout(async () => { - const state = await signProcessKeyringController.getQRKeyringState(); - const requestId = state.getState().sign.request?.requestId || ''; - const signature = composeMockSignature( - requestId, + await setupQRKeyring(); + requestSignatureStub.resolves( + composeMockSignature( + '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d', '33ea4c1dc4b201ad1b1feaf172aadf60dcf2f8bd76d941396bfaebfc3b2868b0340d5689341925c99cdea39e3c5daf7fe2776f220e5b018e85d3b1df19c7bc4701', - ); - signProcessKeyringController.submitQRSignature(requestId, signature); - }, 100); + ), + ); const qrKeyring = signProcessKeyringController.state.keyrings.find( (keyring) => keyring.type === KeyringTypes.qr, @@ -779,31 +798,34 @@ describe('KeyringController', () => { }); it('should reset qr keyring state', async () => { - const data = - '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0'; - const account = - signProcessKeyringController.state.keyrings[1].accounts[0]; - - signProcessKeyringController.signMessage({ - data, - from: account, + await setupQRKeyring(); + (await signProcessKeyringController.getQRKeyringState()).updateState({ + sign: { + request: { + requestId: 'test', + payload: { + cbor: 'test', + type: 'test', + }, + }, + }, }); - setTimeout(async () => { - expect( - (await signProcessKeyringController.getQRKeyringState()).getState() - .sign.request, - ).toBeDefined(); - signProcessKeyringController.resetQRKeyringState(); - - expect( - (await signProcessKeyringController.getQRKeyringState()).getState() - .sign.request, - ).toBeUndefined(); - }, 100); + expect( + (await signProcessKeyringController.getQRKeyringState()).getState().sign + .request, + ).toBeDefined(); + + await signProcessKeyringController.resetQRKeyringState(); + + expect( + (await signProcessKeyringController.getQRKeyringState()).getState().sign + .request, + ).toBeUndefined(); }); it('should forget qr keyring', async () => { + await setupQRKeyring(); expect( signProcessKeyringController.state.keyrings[1].accounts, ).toHaveLength(3); @@ -843,5 +865,50 @@ describe('KeyringController', () => { signProcessKeyringController.state.keyrings[1].accounts, ).toHaveLength(1); }); + + it('should get account keyring type', async () => { + await setupQRKeyring(); + const qrAccount = '0xE410157345be56688F43FF0D9e4B2B38Ea8F7828'; + const hdAccount = + signProcessKeyringController.state.keyrings[0].accounts[0]; + expect( + await signProcessKeyringController.getAccountKeyringType(hdAccount), + ).toBe(KeyringTypes.hd); + + expect( + await signProcessKeyringController.getAccountKeyringType(qrAccount), + ).toBe(KeyringTypes.qr); + }); + + it("should call qr keyring's methods", async () => { + await setupQRKeyring(); + const qrKeyring = await signProcessKeyringController.getOrAddQRKeyring(); + + const submitCryptoHDKeyStub = sinon.stub(qrKeyring, 'submitCryptoHDKey'); + submitCryptoHDKeyStub.resolves(); + await signProcessKeyringController.submitQRCryptoHDKey('anything'); + expect(submitCryptoHDKeyStub.calledWith('anything')).toBe(true); + + const submitCryptoAccountStub = sinon.stub( + qrKeyring, + 'submitCryptoAccount', + ); + submitCryptoAccountStub.resolves(); + await signProcessKeyringController.submitQRCryptoAccount('anything'); + expect(submitCryptoAccountStub.calledWith('anything')).toBe(true); + + const submitSignatureStub = sinon.stub(qrKeyring, 'submitSignature'); + submitSignatureStub.resolves(); + await signProcessKeyringController.submitQRSignature( + 'anything', + 'anything', + ); + expect(submitSignatureStub.calledWith('anything', 'anything')).toBe(true); + + const cancelSignRequestStub = sinon.stub(qrKeyring, 'cancelSignRequest'); + cancelSignRequestStub.resolves(); + await signProcessKeyringController.cancelQRSignRequest(); + expect(cancelSignRequestStub.called).toBe(true); + }); }); }); From fa40eb3ef9442579f9d2407a2f98911cf2d8ab18 Mon Sep 17 00:00:00 2001 From: Soralit Date: Thu, 24 Mar 2022 22:34:28 +0800 Subject: [PATCH 18/18] update dependencies --- package.json | 4 ++-- yarn.lock | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index f14325e1063..059084ba334 100644 --- a/package.json +++ b/package.json @@ -71,8 +71,8 @@ "web3-provider-engine": "^16.0.3" }, "devDependencies": { - "@keystonehq/bc-ur-registry-eth": "^0.8.2-alpha.0", - "@keystonehq/metamask-airgapped-keyring": "^0.2.6-alpha.1", + "@keystonehq/bc-ur-registry-eth": "^0.9.0", + "@keystonehq/metamask-airgapped-keyring": "^0.3.0", "@lavamoat/allow-scripts": "^1.0.6", "@metamask/auto-changelog": "^2.5.0", "@metamask/eslint-config": "^9.0.0", diff --git a/yarn.lock b/yarn.lock index 4d1fd257504..9f9438edc90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1070,21 +1070,21 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" -"@keystonehq/base-eth-keyring@^0.3.6-alpha.1": - version "0.3.6-alpha.1" - resolved "https://registry.yarnpkg.com/@keystonehq/base-eth-keyring/-/base-eth-keyring-0.3.6-alpha.1.tgz#6c5dbb62898ae9a2832961d76b221dac96e85d1d" - integrity sha512-f3HiBRSRlZhQo+oS6YseZbokXIC43PrfBmGsiD/F7YM7XYc1mbo8hLHGXaexTgSaBXXyZkLnYt3woy0VD8hsBQ== +"@keystonehq/base-eth-keyring@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@keystonehq/base-eth-keyring/-/base-eth-keyring-0.4.0.tgz#7667d2b6e38fc90553ce934c0c60c89329315b92" + integrity sha512-CDlRNGdrHDHtBS0pAdrsjNNbyi7tn7mGrwmgiGQ6F8rhYXDZ/TcvYV1AXlzCe0eFyjPdMGdl+PgZRwBpVRtpQQ== dependencies: "@ethereumjs/tx" "3.0.0" - "@keystonehq/bc-ur-registry-eth" "^0.8.2-alpha.0" + "@keystonehq/bc-ur-registry-eth" "^0.9.0" ethereumjs-util "^7.0.8" hdkey "^2.0.1" uuid "^8.3.2" -"@keystonehq/bc-ur-registry-eth@^0.8.2-alpha.0": - version "0.8.2-alpha.0" - resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry-eth/-/bc-ur-registry-eth-0.8.2-alpha.0.tgz#261bd34025f6d6404a739bfa1279c625b44e4d19" - integrity sha512-IOvDSDkXuEa+upaRViFPCtO1GGUNPHOP/w5ojXWRCRdWd5Gu4q6yleWWjwXgOF0xhTm0Nyz26XsYYBHfYF375A== +"@keystonehq/bc-ur-registry-eth@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@keystonehq/bc-ur-registry-eth/-/bc-ur-registry-eth-0.9.0.tgz#607428945029a06ec17ce3288caf53a0cbd8cc22" + integrity sha512-OVRT8Op+ZlOU9EBMxPBtQLrQZKzsV3DlfLq8P1T+Dq7WmGQNsRmQPchgju9qOlIIvmuAKaKdGXNN9W2qpTBAfA== dependencies: "@keystonehq/bc-ur-registry" "^0.5.0-alpha.5" ethereumjs-util "^7.0.8" @@ -1100,14 +1100,14 @@ base58check "^2.0.0" tslib "^2.3.0" -"@keystonehq/metamask-airgapped-keyring@^0.2.6-alpha.1": - version "0.2.6-alpha.1" - resolved "https://registry.yarnpkg.com/@keystonehq/metamask-airgapped-keyring/-/metamask-airgapped-keyring-0.2.6-alpha.1.tgz#72408aff6a43ff0accaaea97d956e8352cf14097" - integrity sha512-fRiaQn92qgPOvfQssDLjCwUsSaABxvZmdxbA2KR1Z33z73Sv8j3u5G92sJNUzCKUNvtlGKJZCLdgJqPaSrH3DQ== +"@keystonehq/metamask-airgapped-keyring@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@keystonehq/metamask-airgapped-keyring/-/metamask-airgapped-keyring-0.3.0.tgz#3de02b268b28d9f2e2e728a10cad8cfc17870c3c" + integrity sha512-CkiQGRPYM8CBeb8GsrrsTXpdHACl9NnoeWGQDY7DXGiy3s6u7WQ6TXal7K+wAHdU4asBzTaK2SNPZ/eIvGiAfg== dependencies: "@ethereumjs/tx" "^3.3.0" - "@keystonehq/base-eth-keyring" "^0.3.6-alpha.1" - "@keystonehq/bc-ur-registry-eth" "^0.8.2-alpha.0" + "@keystonehq/base-eth-keyring" "^0.4.0" + "@keystonehq/bc-ur-registry-eth" "^0.9.0" "@metamask/obs-store" "^7.0.0" rlp "^2.2.6" uuid "^8.3.2"