From 1243188790e07300993b921ec978bf8091611ada Mon Sep 17 00:00:00 2001 From: badi Date: Tue, 14 Mar 2023 08:48:31 +0100 Subject: [PATCH 1/6] feat: the ability to connect qr based hardware wallet --- package-lock.json | 823 +++++++++++++++++- package.json | 6 + src/composables/airGap.ts | 101 +++ src/composables/index.ts | 1 + src/composables/notifications.ts | 4 + src/icons/air-gap.svg | 4 + src/popup/components/AccountCard.vue | 20 + src/popup/components/AccountImportRow.vue | 75 ++ src/popup/components/AccountInfo.vue | 3 +- src/popup/components/Modals/AccountCreate.vue | 52 +- .../components/Modals/AirGapConfirmImport.vue | 191 ++++ src/popup/components/Modals/QrCodeReader.vue | 8 +- src/popup/locales/en.json | 17 +- src/popup/router/modals.ts | 5 + src/popup/utils/constants.ts | 2 + src/store/modules/accounts/airgap.js | 44 + src/store/modules/accounts/index.js | 3 +- src/styles/typography.scss | 7 + src/types/index.ts | 3 +- 19 files changed, 1349 insertions(+), 20 deletions(-) create mode 100644 src/composables/airGap.ts create mode 100644 src/icons/air-gap.svg create mode 100644 src/popup/components/AccountImportRow.vue create mode 100644 src/popup/components/Modals/AirGapConfirmImport.vue create mode 100644 src/store/modules/accounts/airgap.js diff --git a/package-lock.json b/package-lock.json index d7b906b50..7f7de6834 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,12 +15,18 @@ "@aeternity/ga-multisig-contract": "github:aeternity/ga-multisig-contract#b09c381c7845a92ea5471d1721b091cca943bfee", "@aeternity/hd-wallet": "^0.2.0", "@aeternity/ledger-app-api": "0.2.1", + "@airgap/aeternity": "^0.13.10", + "@airgap/coinlib-core": "^0.13.10", + "@airgap/serializer": "^0.13.10", "@fontsource/ibm-plex-mono": "^4.5.7", "@fontsource/ibm-plex-sans": "^4.5.7", + "@keystonehq/bc-ur-registry": "^0.5.4", "@ledgerhq/hw-transport-webusb": "^6.27.1", + "@ngraveio/bc-ur": "^1.1.6", "@vue/composition-api": "^1.0.3", "@zxing/library": "^0.19.1", "bignumber.js": "^9.0.2", + "bs58check": "^2.1.2", "camelcase-keys-deep": "^0.1.0", "cordova-android": "^10.1.1", "cordova-clipboard": "^1.3.0", @@ -415,6 +421,48 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/@airgap/aeternity": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/@airgap/aeternity/-/aeternity-0.13.10.tgz", + "integrity": "sha512-9qo7E6JI6jrq/T/SrS12vB9WTeUcLhb/WGYjJYAPbvwOGKw9fqGdDQWe/4UXdCF6QhOs27qmKZG6yCIADD+hMg==", + "peerDependencies": { + "@airgap/coinlib-core": "^0.13.10", + "@airgap/module-kit": "^0.13.10", + "@airgap/serializer": "^0.13.10", + "@stablelib/ed25519": "1.0.3" + } + }, + "node_modules/@airgap/coinlib-core": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/@airgap/coinlib-core/-/coinlib-core-0.13.10.tgz", + "integrity": "sha512-VNmDCSzZJh47z93ORbHEn6dBQ7VzlLtqqcRC4W/0jmpdse5VXuhvR5DhxcotehTkSQRLiGmn+PevnyKGenkZbQ==", + "dependencies": { + "@stablelib/blake2b": "^1.0.1", + "@stablelib/bytes": "^1.0.1", + "@stablelib/ed25519": "^1.0.3", + "@stablelib/nacl": "^1.0.4", + "@stablelib/utf8": "^1.0.1", + "long": "^5.2.0", + "protobufjs": "^6.11.2" + } + }, + "node_modules/@airgap/module-kit": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/@airgap/module-kit/-/module-kit-0.13.10.tgz", + "integrity": "sha512-nv1Qg+XYXa8pWHB9/M9pVQvB2Immq4utLFHPDcz9TftOcZ0giC7cQqik0zrH4aX7kfCCj7xqa1HzIhlXfyPikg==", + "peer": true, + "peerDependencies": { + "@airgap/coinlib-core": "^0.13.10" + } + }, + "node_modules/@airgap/serializer": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/@airgap/serializer/-/serializer-0.13.10.tgz", + "integrity": "sha512-HVTpd05G6PPj6/hnZs+oBL/cWP543AMxp93GHrg3KsWQPBFLvxpgxhrzCXYaPcXyxgSHSbOlRttOVOzgi8HEtw==", + "peerDependencies": { + "@airgap/coinlib-core": "^0.13.10" + } + }, "node_modules/@ampproject/remapping": { "version": "2.1.2", "license": "Apache-2.0", @@ -425,6 +473,11 @@ "node": ">=6.0.0" } }, + "node_modules/@apocentre/alias-sampling": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@apocentre/alias-sampling/-/alias-sampling-0.5.3.tgz", + "integrity": "sha512-7UDWIIF9hIeJqfKXkNIzkVandlwLf1FWTSdrb9iXvOP8oF544JRXQjCbiTmCv2c9n44n/FIWtehhBfNuAx2CZA==" + }, "node_modules/@azure/abort-controller": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", @@ -4784,6 +4837,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@keystonehq/bc-ur-registry": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@keystonehq/bc-ur-registry/-/bc-ur-registry-0.5.4.tgz", + "integrity": "sha512-z7bZe10I5k0zz9znmDTXh+o3Rzb5XsRVpwAzexubOaLxVdZ0F7aMbe2LoEsw766Hpox/7zARi7UGmLz5C8BAzA==", + "dependencies": { + "@ngraveio/bc-ur": "^1.1.5", + "bs58check": "^2.1.2", + "tslib": "^2.3.0" + } + }, "node_modules/@ledgerhq/devices": { "version": "4.78.0", "license": "Apache-2.0", @@ -4994,6 +5057,43 @@ "lodash": "^4.17.15" } }, + "node_modules/@ngraveio/bc-ur": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@ngraveio/bc-ur/-/bc-ur-1.1.6.tgz", + "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" + } + }, + "node_modules/@ngraveio/bc-ur/node_modules/assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "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" + } + }, + "node_modules/@ngraveio/bc-ur/node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/@node-ipc/js-queue": { "version": "2.0.3", "dev": true, @@ -5327,6 +5427,142 @@ "dev": true, "license": "MIT" }, + "node_modules/@stablelib/binary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", + "dependencies": { + "@stablelib/int": "^1.0.1" + } + }, + "node_modules/@stablelib/blake2b": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/blake2b/-/blake2b-1.0.1.tgz", + "integrity": "sha512-B3KyKoBAjkIFeH7romcF96i+pVFYk7K2SBQ1pZvaxV+epSBXJ+n0C66esUhyz6FF+5FbdQVm77C5fzGFcEZpKA==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/bytes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" + }, + "node_modules/@stablelib/constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" + }, + "node_modules/@stablelib/ed25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.3.tgz", + "integrity": "sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==", + "dependencies": { + "@stablelib/random": "^1.0.2", + "@stablelib/sha512": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" + }, + "node_modules/@stablelib/int": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" + }, + "node_modules/@stablelib/keyagreement": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", + "dependencies": { + "@stablelib/bytes": "^1.0.1" + } + }, + "node_modules/@stablelib/nacl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@stablelib/nacl/-/nacl-1.0.4.tgz", + "integrity": "sha512-PJ2U/MrkXSKUM8C4qFs87WeCNxri7KQwR8Cdwm9q2sweGuAtTvOJGuW0F3N+zn+ySLPJA98SYWSSpogMJ1gCmw==", + "dependencies": { + "@stablelib/poly1305": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1", + "@stablelib/x25519": "^1.0.3", + "@stablelib/xsalsa20": "^1.0.2" + } + }, + "node_modules/@stablelib/poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", + "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", + "dependencies": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/random": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/salsa20": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/salsa20/-/salsa20-1.0.2.tgz", + "integrity": "sha512-nfjKzw0KTKrrKBasEP+j7UP4I8Xudom8lVZIBCp0kQNARXq72IlSic0oabg2FC1NU68L4RdHrNJDd8bFwrphYA==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/sha512": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha512/-/sha512-1.0.1.tgz", + "integrity": "sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/utf8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/utf8/-/utf8-1.0.1.tgz", + "integrity": "sha512-FrYD1xadah/TtAP6VJ04lDD5h9rdDj/d8wH/jMYTtHqZBv9z2btdvEU8vTxdjdkFmo1b/BH+t3R1wi/mYhCCNg==" + }, + "node_modules/@stablelib/wipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" + }, + "node_modules/@stablelib/x25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", + "dependencies": { + "@stablelib/keyagreement": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/xsalsa20": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/xsalsa20/-/xsalsa20-1.0.2.tgz", + "integrity": "sha512-7XdBGbcNgBShmuhDXv1G1WPVCkjZdkb1oPMzSidO7Fve0MHntH6TjFkj5bfLI+aRE+61weO076vYpP/jmaAYog==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/salsa20": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, "node_modules/@stamp/compose": { "version": "1.0.2", "license": "MIT", @@ -5619,6 +5855,11 @@ "@types/lodash": "*" } }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "node_modules/@types/mdast": { "version": "3.0.10", "dev": true, @@ -10628,9 +10869,10 @@ } }, "node_modules/async": { - "version": "3.2.3", - "dev": true, - "license": "MIT" + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true }, "node_modules/async-each": { "version": "1.0.3", @@ -10692,6 +10934,17 @@ "url": "https://tidelift.com/funding/github/npm/autoprefixer" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "dev": true, @@ -11704,6 +11957,16 @@ "base-x": "^3.0.2" } }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, "node_modules/bser": { "version": "2.1.1", "license": "Apache-2.0", @@ -12155,6 +12418,11 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/cbor-sync": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cbor-sync/-/cbor-sync-1.0.4.tgz", + "integrity": "sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA==" + }, "node_modules/chai": { "version": "4.3.6", "dev": true, @@ -14706,6 +14974,14 @@ "typescript": ">=3" } }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dependencies": { + "buffer": "^5.1.0" + } + }, "node_modules/crc-32": { "version": "1.2.2", "dev": true, @@ -14717,6 +14993,29 @@ "node": ">=0.8" } }, + "node_modules/crc/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/crc32-stream": { "version": "4.0.2", "dev": true, @@ -16516,6 +16815,11 @@ "es6-symbol": "^3.1.1" } }, + "node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==" + }, "node_modules/es6-symbol": { "version": "3.1.3", "license": "ISC", @@ -18458,6 +18762,14 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/for-in": { "version": "1.0.2", "license": "MIT", @@ -18972,12 +19284,13 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "license": "MIT", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19420,6 +19733,17 @@ "node": ">=0.6.0" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/got": { "version": "9.6.0", "dev": true, @@ -21184,7 +21508,6 @@ }, "node_modules/is-arguments": { "version": "1.1.1", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -21410,6 +21733,20 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "license": "MIT", @@ -21449,6 +21786,21 @@ "dev": true, "license": "MIT" }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { "version": "2.0.2", "license": "MIT", @@ -21686,6 +22038,24 @@ "node": ">=0.10.0" } }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "license": "MIT" @@ -27096,6 +27466,11 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbi": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.2.5.tgz", + "integrity": "sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==" + }, "node_modules/jsbn": { "version": "0.1.1", "dev": true, @@ -28271,6 +28646,11 @@ "url": "https://tidelift.com/funding/github/npm/loglevel" } }, + "node_modules/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz", + "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" + }, "node_modules/longest-streak": { "version": "2.0.4", "dev": true, @@ -29915,7 +30295,6 @@ }, "node_modules/object-is": { "version": "1.1.5", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -32058,6 +32437,36 @@ "dev": true, "license": "ISC" }, + "node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/protobufjs/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "dev": true, @@ -40231,6 +40640,25 @@ "version": "2.0.0", "license": "ISC" }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "license": "ISC", @@ -41129,12 +41557,50 @@ "@aeternity/uuid": { "version": "0.0.1" }, + "@airgap/aeternity": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/@airgap/aeternity/-/aeternity-0.13.10.tgz", + "integrity": "sha512-9qo7E6JI6jrq/T/SrS12vB9WTeUcLhb/WGYjJYAPbvwOGKw9fqGdDQWe/4UXdCF6QhOs27qmKZG6yCIADD+hMg==", + "requires": {} + }, + "@airgap/coinlib-core": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/@airgap/coinlib-core/-/coinlib-core-0.13.10.tgz", + "integrity": "sha512-VNmDCSzZJh47z93ORbHEn6dBQ7VzlLtqqcRC4W/0jmpdse5VXuhvR5DhxcotehTkSQRLiGmn+PevnyKGenkZbQ==", + "requires": { + "@stablelib/blake2b": "^1.0.1", + "@stablelib/bytes": "^1.0.1", + "@stablelib/ed25519": "^1.0.3", + "@stablelib/nacl": "^1.0.4", + "@stablelib/utf8": "^1.0.1", + "long": "^5.2.0", + "protobufjs": "^6.11.2" + } + }, + "@airgap/module-kit": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/@airgap/module-kit/-/module-kit-0.13.10.tgz", + "integrity": "sha512-nv1Qg+XYXa8pWHB9/M9pVQvB2Immq4utLFHPDcz9TftOcZ0giC7cQqik0zrH4aX7kfCCj7xqa1HzIhlXfyPikg==", + "peer": true, + "requires": {} + }, + "@airgap/serializer": { + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/@airgap/serializer/-/serializer-0.13.10.tgz", + "integrity": "sha512-HVTpd05G6PPj6/hnZs+oBL/cWP543AMxp93GHrg3KsWQPBFLvxpgxhrzCXYaPcXyxgSHSbOlRttOVOzgi8HEtw==", + "requires": {} + }, "@ampproject/remapping": { "version": "2.1.2", "requires": { "@jridgewell/trace-mapping": "^0.3.0" } }, + "@apocentre/alias-sampling": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@apocentre/alias-sampling/-/alias-sampling-0.5.3.tgz", + "integrity": "sha512-7UDWIIF9hIeJqfKXkNIzkVandlwLf1FWTSdrb9iXvOP8oF544JRXQjCbiTmCv2c9n44n/FIWtehhBfNuAx2CZA==" + }, "@azure/abort-controller": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", @@ -44199,6 +44665,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@keystonehq/bc-ur-registry": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@keystonehq/bc-ur-registry/-/bc-ur-registry-0.5.4.tgz", + "integrity": "sha512-z7bZe10I5k0zz9znmDTXh+o3Rzb5XsRVpwAzexubOaLxVdZ0F7aMbe2LoEsw766Hpox/7zARi7UGmLz5C8BAzA==", + "requires": { + "@ngraveio/bc-ur": "^1.1.5", + "bs58check": "^2.1.2", + "tslib": "^2.3.0" + } + }, "@ledgerhq/devices": { "version": "4.78.0", "requires": { @@ -44366,6 +44842,45 @@ "lodash": "^4.17.15" } }, + "@ngraveio/bc-ur": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@ngraveio/bc-ur/-/bc-ur-1.1.6.tgz", + "integrity": "sha512-G+2XgjXde2IOcEQeCwR250aS43/Swi7gw0FuETgJy2c3HqF8f88SXDMsIGgJlZ8jXd0GeHR4aX0MfjXf523UZg==", + "requires": { + "@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" + }, + "dependencies": { + "assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + } + } + }, "@node-ipc/js-queue": { "version": "2.0.3", "dev": true, @@ -44586,6 +45101,142 @@ "version": "1.0.2", "dev": true }, + "@stablelib/binary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", + "requires": { + "@stablelib/int": "^1.0.1" + } + }, + "@stablelib/blake2b": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/blake2b/-/blake2b-1.0.1.tgz", + "integrity": "sha512-B3KyKoBAjkIFeH7romcF96i+pVFYk7K2SBQ1pZvaxV+epSBXJ+n0C66esUhyz6FF+5FbdQVm77C5fzGFcEZpKA==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/bytes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" + }, + "@stablelib/constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" + }, + "@stablelib/ed25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.3.tgz", + "integrity": "sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==", + "requires": { + "@stablelib/random": "^1.0.2", + "@stablelib/sha512": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" + }, + "@stablelib/int": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" + }, + "@stablelib/keyagreement": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", + "requires": { + "@stablelib/bytes": "^1.0.1" + } + }, + "@stablelib/nacl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@stablelib/nacl/-/nacl-1.0.4.tgz", + "integrity": "sha512-PJ2U/MrkXSKUM8C4qFs87WeCNxri7KQwR8Cdwm9q2sweGuAtTvOJGuW0F3N+zn+ySLPJA98SYWSSpogMJ1gCmw==", + "requires": { + "@stablelib/poly1305": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1", + "@stablelib/x25519": "^1.0.3", + "@stablelib/xsalsa20": "^1.0.2" + } + }, + "@stablelib/poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", + "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", + "requires": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/random": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/salsa20": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/salsa20/-/salsa20-1.0.2.tgz", + "integrity": "sha512-nfjKzw0KTKrrKBasEP+j7UP4I8Xudom8lVZIBCp0kQNARXq72IlSic0oabg2FC1NU68L4RdHrNJDd8bFwrphYA==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/sha512": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha512/-/sha512-1.0.1.tgz", + "integrity": "sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/utf8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/utf8/-/utf8-1.0.1.tgz", + "integrity": "sha512-FrYD1xadah/TtAP6VJ04lDD5h9rdDj/d8wH/jMYTtHqZBv9z2btdvEU8vTxdjdkFmo1b/BH+t3R1wi/mYhCCNg==" + }, + "@stablelib/wipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" + }, + "@stablelib/x25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", + "requires": { + "@stablelib/keyagreement": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/xsalsa20": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/xsalsa20/-/xsalsa20-1.0.2.tgz", + "integrity": "sha512-7XdBGbcNgBShmuhDXv1G1WPVCkjZdkb1oPMzSidO7Fve0MHntH6TjFkj5bfLI+aRE+61weO076vYpP/jmaAYog==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/salsa20": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, "@stamp/compose": { "version": "1.0.2", "requires": { @@ -44826,6 +45477,11 @@ "@types/lodash": "*" } }, + "@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "@types/mdast": { "version": "3.0.10", "dev": true, @@ -48417,7 +49073,9 @@ "dev": true }, "async": { - "version": "3.2.3", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "dev": true }, "async-each": { @@ -48454,6 +49112,11 @@ "postcss-value-parser": "^4.1.0" } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, "aws-sign2": { "version": "0.7.0", "dev": true @@ -49166,6 +49829,16 @@ "base-x": "^3.0.2" } }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, "bser": { "version": "2.1.1", "requires": { @@ -49450,6 +50123,11 @@ "version": "0.12.0", "dev": true }, + "cbor-sync": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cbor-sync/-/cbor-sync-1.0.4.tgz", + "integrity": "sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA==" + }, "chai": { "version": "4.3.6", "dev": true, @@ -51134,6 +51812,25 @@ "ts-node": "^10.7.0" } }, + "crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "requires": { + "buffer": "^5.1.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, "crc-32": { "version": "1.2.2", "dev": true @@ -52399,6 +53096,11 @@ "es6-symbol": "^3.1.1" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==" + }, "es6-symbol": { "version": "3.1.3", "requires": { @@ -53758,6 +54460,14 @@ "version": "1.15.1", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, "for-in": { "version": "1.0.2" }, @@ -54114,11 +54824,13 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.1", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" } }, "get-package-type": { @@ -54415,6 +55127,14 @@ "minimist": "^1.2.5" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "got": { "version": "9.6.0", "dev": true, @@ -55580,7 +56300,6 @@ }, "is-arguments": { "version": "1.1.1", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -55693,6 +56412,14 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==" }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-glob": { "version": "4.0.3", "requires": { @@ -55715,6 +56442,15 @@ "version": "1.0.1", "dev": true }, + "is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, "is-negative-zero": { "version": "2.0.2" }, @@ -55847,6 +56583,18 @@ "text-extensions": "^1.0.0" } }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0" }, @@ -60020,6 +60768,11 @@ "argparse": "^2.0.1" } }, + "jsbi": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.2.5.tgz", + "integrity": "sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==" + }, "jsbn": { "version": "0.1.1", "dev": true @@ -60828,6 +61581,11 @@ "version": "1.8.0", "dev": true }, + "long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz", + "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" + }, "longest-streak": { "version": "2.0.4", "dev": true @@ -61960,7 +62718,6 @@ }, "object-is": { "version": "1.1.5", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -63452,6 +64209,33 @@ "version": "1.2.4", "dev": true }, + "protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + } + } + }, "proxy-addr": { "version": "2.0.7", "dev": true, @@ -69026,6 +69810,19 @@ "which-module": { "version": "2.0.0" }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, "wide-align": { "version": "1.1.5", "requires": { diff --git a/package.json b/package.json index 6c9f2e647..3650c1653 100644 --- a/package.json +++ b/package.json @@ -32,12 +32,18 @@ "@aeternity/ga-multisig-contract": "github:aeternity/ga-multisig-contract#b09c381c7845a92ea5471d1721b091cca943bfee", "@aeternity/hd-wallet": "^0.2.0", "@aeternity/ledger-app-api": "0.2.1", + "@airgap/aeternity": "^0.13.10", + "@airgap/coinlib-core": "^0.13.10", + "@airgap/serializer": "^0.13.10", "@fontsource/ibm-plex-mono": "^4.5.7", "@fontsource/ibm-plex-sans": "^4.5.7", + "@keystonehq/bc-ur-registry": "^0.5.4", "@ledgerhq/hw-transport-webusb": "^6.27.1", + "@ngraveio/bc-ur": "^1.1.6", "@vue/composition-api": "^1.0.3", "@zxing/library": "^0.19.1", "bignumber.js": "^9.0.2", + "bs58check": "^2.1.2", "camelcase-keys-deep": "^0.1.0", "cordova-android": "^10.1.1", "cordova-clipboard": "^1.3.0", diff --git a/src/composables/airGap.ts b/src/composables/airGap.ts new file mode 100644 index 000000000..626047de3 --- /dev/null +++ b/src/composables/airGap.ts @@ -0,0 +1,101 @@ +import { decode } from '@aeternity/aepp-sdk/es/tx/builder/helpers'; +import { UR, URDecoder, UREncoder } from '@ngraveio/bc-ur'; +import bs58check from 'bs58check'; +import { IACMessageType, SerializerV3 } from '@airgap/serializer'; +import type { + AccountShareResponse, + IACMessageDefinitionObjectV3, +} from '@airgap/serializer'; +import { AeternityAddress } from '@airgap/aeternity'; +import type { IAccount, IDefaultComposableOptions } from '../types'; +import { ACCOUNT_AIR_GAP_WALLET } from '../popup/utils'; + +// eslint-disable-next-line no-unused-vars +export function useAirGap({ store }: IDefaultComposableOptions) { + /** + * Decodes a serialized data string that conforms to the "Uniform Resource" format (UR). + * The function first decodes the UR string using the URDecoder class, then decodes the + * resulting CBOR data, and finally deserializes the decoded data using a SerializerV3 instance. + * + * @param serializedData A string containing the serialized UR data to decode. + * + * @returns The deserialized data, + * or null if the input data is not in the expected format or decoding fails. + */ + async function decodeURSerializedData( + serializedData: string, + ): Promise { + if (!serializedData.toUpperCase().startsWith('UR:')) { + return []; + } + + const decoder = new URDecoder(); + decoder.receivePart(serializedData); + + if (!decoder.isComplete() || !decoder.isSuccess()) { + return []; + } + + const decoded = decoder.resultUR(); + const combinedData = decoded.decodeCBOR(); + const resultUr = bs58check.encode(combinedData); + + const serializer = SerializerV3.getInstance(); + const parsedData: IACMessageDefinitionObjectV3[] = await serializer.deserialize(resultUr); + + return parsedData; + } + + /** + * Encodes an array of IAC message definition objects into a Uniform Resource (UR) format. + */ + async function encodeIACMessageDefinitionObjects(data: IACMessageDefinitionObjectV3[]) { + const serializer = SerializerV3.getInstance(); + const serializedData = await serializer.serialize(data); + + const buffer = bs58check.decode(serializedData); + const ur = UR.fromBuffer(buffer); + const encoder = new UREncoder(ur); + + return encoder; + } + + /** + * Extracts shared addresses groups from encoded UR Data. + * @param serializedData + * @returns IAccount[] + */ + async function extractAccountShareResponseData( + serializedData: string, + ): Promise { + const decodedData = await decodeURSerializedData(serializedData); + + if (!decodedData) { + return []; + } + + return decodedData + .filter((item) => item.type === IACMessageType.AccountShareResponse) + .map((item) => { + const address = AeternityAddress.from( + (item.payload as AccountShareResponse).publicKey, + ).asString(); + const publicKey = Buffer.from(decode(address, 'ak')); + + return { + address, + publicKey, + name: '', + showed: true, + type: ACCOUNT_AIR_GAP_WALLET, + isOffline: true, + } as IAccount; + }); + } + + return { + decodeURSerializedData, + encodeIACMessageDefinitionObjects, + extractAccountShareResponseData, + }; +} diff --git a/src/composables/index.ts b/src/composables/index.ts index fa91cefe9..e8f73381e 100644 --- a/src/composables/index.ts +++ b/src/composables/index.ts @@ -23,3 +23,4 @@ export * from './transactionTokens'; export * from './transactionAndTokenFilter'; export * from './ui'; export * from './viewport'; +export * from './airGap'; diff --git a/src/composables/notifications.ts b/src/composables/notifications.ts index 7cf318b09..d208357ea 100644 --- a/src/composables/notifications.ts +++ b/src/composables/notifications.ts @@ -15,6 +15,7 @@ import { fetchJson, postJson, fetchRespondChallenge, + ACCOUNT_HD_WALLET, } from '../popup/utils'; import { useSdk } from './sdk'; import { useAccounts } from './accounts'; @@ -75,6 +76,9 @@ export function useNotifications({ ); async function fetchAllNotifications(): Promise { + if (activeAccount.value.type !== ACCOUNT_HD_WALLET) { + return []; + } const fetchUrl = `${activeNetwork.value.backendUrl}/notification/user/${activeAccount.value.address}`; const [responseChallenge, sdk] = await Promise.all([ fetchJson(fetchUrl), diff --git a/src/icons/air-gap.svg b/src/icons/air-gap.svg new file mode 100644 index 000000000..d444f9275 --- /dev/null +++ b/src/icons/air-gap.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/popup/components/AccountCard.vue b/src/popup/components/AccountCard.vue index de56e2e82..6b8a37d9e 100644 --- a/src/popup/components/AccountCard.vue +++ b/src/popup/components/AccountCard.vue @@ -9,6 +9,7 @@ :name="account.name" :idx="account.idx" avatar-borderless + :is-air-gap="isAirGapAccount" /> @@ -21,6 +22,10 @@ :current-account="account" :selected="selected" /> + @@ -34,18 +39,22 @@ import { import type { IAccount } from '../../types'; import { ROUTE_ACCOUNT_DETAILS } from '../router/routeNames'; import { useBalances } from '../../composables'; +import { ACCOUNT_AIR_GAP_WALLET } from '../utils'; import AccountInfo from './AccountInfo.vue'; import BalanceInfo from './BalanceInfo.vue'; import AccountCardTotalTokens from './AccountCardTotalTokens.vue'; import AccountCardBase from './AccountCardBase.vue'; +import AirGapIcon from '../../icons/air-gap.svg?vue-component'; + export default defineComponent({ components: { AccountCardBase, AccountCardTotalTokens, AccountInfo, BalanceInfo, + AirGapIcon, }, props: { account: { type: Object as PropType, required: true }, @@ -55,11 +64,22 @@ export default defineComponent({ const { balance } = useBalances({ store: root.$store }); const numericBalance = computed(() => balance.value.toNumber()); + const isAirGapAccount = computed((): boolean => props.account.type === ACCOUNT_AIR_GAP_WALLET); return { numericBalance, + isAirGapAccount, ROUTE_ACCOUNT_DETAILS, }; }, }); + + diff --git a/src/popup/components/AccountImportRow.vue b/src/popup/components/AccountImportRow.vue new file mode 100644 index 000000000..22226f4df --- /dev/null +++ b/src/popup/components/AccountImportRow.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/popup/components/AccountInfo.vue b/src/popup/components/AccountInfo.vue index 1a996611d..d0b76c023 100644 --- a/src/popup/components/AccountInfo.vue +++ b/src/popup/components/AccountInfo.vue @@ -31,7 +31,7 @@ data-cy="account-name-number" class="account-name" > - {{ $t('pages.account.heading') }} {{ idx + 1 }} + {{ isAirGap ? $t('common.airGap') : $t('pages.account.heading') }} {{ idx + 1 }}
+ + + + diff --git a/src/popup/components/Modals/QrCodeReader.vue b/src/popup/components/Modals/QrCodeReader.vue index 2b0c939dc..d0df48c16 100644 --- a/src/popup/components/Modals/QrCodeReader.vue +++ b/src/popup/components/Modals/QrCodeReader.vue @@ -10,7 +10,6 @@
- {{ title }} {{ $t('modals.qrCodeReader.grantPermission') }} @@ -68,6 +67,7 @@ export default { }, props: { title: { type: String, required: true }, + heading: { type: String, required: false, default: null }, resolve: { type: Function, required: true }, reject: { type: Function, required: true }, }, @@ -236,6 +236,12 @@ export default { } } + .heading { + @extend %face-sans-19-medium; + + color: variables.$color-white; + } + .subtitle { @extend %face-sans-16-medium; diff --git a/src/popup/locales/en.json b/src/popup/locales/en.json index 43e868bbe..53244148c 100644 --- a/src/popup/locales/en.json +++ b/src/popup/locales/en.json @@ -37,7 +37,8 @@ "totalMultisig": "Total in multisig vaults", "tx": "Tx", "you": "You", - "max": "MAX" + "max": "MAX", + "airGap": "AirGap" }, "connectionStatus": { "offline": "You are offline. Go online to get real time data.", @@ -198,6 +199,20 @@ "thirdPoint": "Z = number of authorized signers.", "description": "If X=Y the multisig consensus has been reached. The transaction proposal has been approved and the transaction can be sent by any of the authorized signers." }, + "importAirGapAccount": { + "btnText": "Pair QR Wallet", + "btnSubtitle": "Connect QR-based Hardware Wallet", + "scanTitle": "Scan QR code", + "scanDescription": "from your AirGap vault", + + "importConfirmDialog": { + "title": "Select accounts to import from AirGap", + "selectAll": "Select all", + "search": "Search for account", + "importAccounts": "Import Accounts", + "noAccountsFound": "There are no accounts found." + } + }, "removeAccount": { "title": "Are you sure you want to remove this account?", "msg": "This action will remove your account from the wallet and will delete the extension storage. Make sure you have backed up your seed phrase before proceeding. This action cannot be undone!" diff --git a/src/popup/router/modals.ts b/src/popup/router/modals.ts index d8c1c976c..8df315a67 100644 --- a/src/popup/router/modals.ts +++ b/src/popup/router/modals.ts @@ -24,12 +24,14 @@ import { MODAL_MULTISIG_VAULT_CREATE, MODAL_MULTISIG_PROPOSAL_CONFIRM_ACTION, MODAL_ACCOUNT_SELECT_OPTIONS, + MODAL_AIR_GAP_CONFIRM_IMPORT, } from '../utils/constants'; import { useModals } from '../../composables'; import Default from '../components/Modals/Default.vue'; import AccountCreate from '../components/Modals/AccountCreate.vue'; import AccountImport from '../components/Modals/AccountImport.vue'; +import AirGapConfirmImport from '../components/Modals/AirGapConfirmImport.vue'; import ClaimSuccess from '../components/Modals/ClaimSuccess.vue'; import SpendSuccess from '../components/Modals/SpendSuccess.vue'; import Confirm from '../components/Modals/Confirm.vue'; @@ -64,6 +66,9 @@ export default () => { registerModal(MODAL_ACCOUNT_IMPORT, { component: AccountImport, }); + registerModal(MODAL_AIR_GAP_CONFIRM_IMPORT, { + component: AirGapConfirmImport, + }); registerModal(MODAL_CLAIM_SUCCESS, { component: ClaimSuccess, }); diff --git a/src/popup/utils/constants.ts b/src/popup/utils/constants.ts index e05a7b271..1c9d5c70e 100644 --- a/src/popup/utils/constants.ts +++ b/src/popup/utils/constants.ts @@ -101,6 +101,7 @@ export const STUB_TOKEN_CONTRACT_ADDRESS = 'ct_T6MWNrowGVC9dyTDksCBrCCSaeK3hzBMM export const ACCOUNT_HD_WALLET = 'hd-wallet'; export const ACCOUNT_LEDGER_WALLET = 'ledger'; +export const ACCOUNT_AIR_GAP_WALLET = 'airgap'; /** * Default `networkId` values returned by the Node after establishing the connection. @@ -407,6 +408,7 @@ export const MODAL_DEFAULT = 'default'; export const MODAL_ACCOUNT_CREATE = 'account-create'; export const MODAL_MULTISIG_VAULT_CREATE = 'multisig-vault-create'; export const MODAL_ACCOUNT_IMPORT = 'import-account'; +export const MODAL_AIR_GAP_CONFIRM_IMPORT = 'air-gap-confirm-import'; export const MODAL_CLAIM_SUCCESS = 'claim-success'; export const MODAL_SPEND_SUCCESS = 'spend-success'; export const MODAL_CONFIRM = 'confirm'; diff --git a/src/store/modules/accounts/airgap.js b/src/store/modules/accounts/airgap.js new file mode 100644 index 000000000..c7b288931 --- /dev/null +++ b/src/store/modules/accounts/airgap.js @@ -0,0 +1,44 @@ +import { MODAL_DEFAULT, ACCOUNT_AIR_GAP_WALLET } from '../../../popup/utils'; + +export default { + namespaced: true, + + account: { + type: ACCOUNT_AIR_GAP_WALLET, + }, + + getters: { + nextIdx: (state, getters, rootState, rootGetters) => Math.max( + ...rootGetters['accounts/getByType'](ACCOUNT_AIR_GAP_WALLET).map(({ idx }) => idx), + -1, + ) + 1, + }, + + actions: { + async import({ getters: { nextIdx }, commit, rootState }, account) { + commit('accounts/add', { + ...account, + type: ACCOUNT_AIR_GAP_WALLET, + idx: nextIdx, + }, { root: true }); + commit('accounts/setActiveIdx', rootState.accounts.list.length - 1, { root: true }); + }, + + async ensureCurrentAccountAvailable({ rootGetters: { account }, dispatch }) { + const address = await dispatch('request', { name: 'getAddress', args: [account.idx] }); + if (account.address !== address) { + if (!process.env.IS_EXTENSION) { + dispatch('modals/open', { name: MODAL_DEFAULT, icon: 'alert', title: 'account not found' }, { root: true }); + } + throw new Error('Account not found'); + } + }, + + sign: () => Promise.reject(new Error('AirGap Sign Not implemented yet')), + signTransaction: () => Promise.reject(new Error('AirGap signTransaction Not implemented yet')), + + async signTransactionFromAccount({ dispatch }, { txBase64 }) { + return dispatch('signTransaction', { txBase64 }); + }, + }, +}; diff --git a/src/store/modules/accounts/index.js b/src/store/modules/accounts/index.js index 60a0194c8..39c043c7a 100644 --- a/src/store/modules/accounts/index.js +++ b/src/store/modules/accounts/index.js @@ -3,9 +3,10 @@ import Vue from 'vue'; import hdWallet from './hdWallet'; import ledger from './ledger'; +import airgap from './airgap'; import { ACCOUNT_HD_WALLET } from '../../../popup/utils'; -const modules = { hdWallet, ledger }; +const modules = { hdWallet, ledger, airgap }; export default { namespaced: true, diff --git a/src/styles/typography.scss b/src/styles/typography.scss index b2e908474..abc8aef35 100644 --- a/src/styles/typography.scss +++ b/src/styles/typography.scss @@ -86,6 +86,13 @@ line-height: 24px; } +%face-sans-19-medium { + font-family: $font-sans; + font-weight: 500; + font-size: 19px; + line-height: 24px; +} + %face-sans-19-regular { font-family: $font-sans; font-weight: 400; diff --git a/src/types/index.ts b/src/types/index.ts index 487ace938..f904bb311 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -145,9 +145,10 @@ export interface IAccount { idx?: number name: string // .chain publicKey: Uint8Array - secretKey: Uint8Array + secretKey?: Uint8Array showed: boolean type: string + isOffline?: boolean; } /** From d037054e15086c47a81956b5defd1d357102aaa7 Mon Sep 17 00:00:00 2001 From: badi Date: Fri, 24 Mar 2023 07:34:10 +0100 Subject: [PATCH 2/6] feat(airGap): send transaction flow --- src/composables/accounts.ts | 10 +- src/composables/airGap.ts | 99 +++++++++- src/popup/components/Modals/TransferSend.vue | 86 ++++++++- .../OpenTransferSendModalButton.vue | 2 + src/popup/components/QrCode.vue | 6 +- src/popup/components/StatusIcon.vue | 5 +- src/popup/components/TemplateRenderer.vue | 34 ++++ .../components/TransferQRCodeGenerator.vue | 94 ++++++++++ src/popup/components/TransferRawTxReview.vue | 173 ++++++++++++++++++ src/popup/components/TransferReview.vue | 78 +++++++- src/popup/components/TransferSendForm.vue | 5 +- src/popup/locales/en.json | 17 +- src/popup/pages/AccountDetails.vue | 4 +- src/popup/pages/Dashboard.vue | 7 +- .../pages/FungibleTokens/TokenContainer.vue | 3 + src/popup/utils/constants.ts | 2 + src/types/index.ts | 2 +- 17 files changed, 600 insertions(+), 27 deletions(-) create mode 100644 src/popup/components/TransferQRCodeGenerator.vue create mode 100644 src/popup/components/TransferRawTxReview.vue diff --git a/src/composables/accounts.ts b/src/composables/accounts.ts index d70c4e7b8..a5ed38dbb 100644 --- a/src/composables/accounts.ts +++ b/src/composables/accounts.ts @@ -1,6 +1,11 @@ import { computed } from '@vue/composition-api'; import type { IAccount, IDefaultComposableOptions, IFormSelectOption } from '../types'; -import { FAUCET_URL, buildSimplexLink, getAccountNameToDisplay } from '../popup/utils'; +import { + FAUCET_URL, + ACCOUNT_AIR_GAP_WALLET, + buildSimplexLink, + getAccountNameToDisplay, +} from '../popup/utils'; export function useAccounts({ store }: IDefaultComposableOptions) { // TODO in the future the state of the accounts should be stored in this composable @@ -12,6 +17,8 @@ export function useAccounts({ store }: IDefaultComposableOptions) { () => activeAccount.value && Object.keys(activeAccount.value).length > 0, ); + const isAirGap = computed((): boolean => activeAccount.value.type === ACCOUNT_AIR_GAP_WALLET); + /** * Accounts data formatted as the form select options */ @@ -67,5 +74,6 @@ export function useAccounts({ store }: IDefaultComposableOptions) { getAccountByAddress, setActiveAccountByAddress, setActiveAccountByIdx, + isAirGap, }; } diff --git a/src/composables/airGap.ts b/src/composables/airGap.ts index 626047de3..5a46236cf 100644 --- a/src/composables/airGap.ts +++ b/src/composables/airGap.ts @@ -5,10 +5,13 @@ import { IACMessageType, SerializerV3 } from '@airgap/serializer'; import type { AccountShareResponse, IACMessageDefinitionObjectV3, + TransactionSignResponse, + TransactionSignRequest, } from '@airgap/serializer'; import { AeternityAddress } from '@airgap/aeternity'; +import { MainProtocolSymbols } from '@airgap/coinlib-core'; import type { IAccount, IDefaultComposableOptions } from '../types'; -import { ACCOUNT_AIR_GAP_WALLET } from '../popup/utils'; +import { ACCOUNT_AIR_GAP_WALLET, handleUnknownError } from '../popup/utils'; // eslint-disable-next-line no-unused-vars export function useAirGap({ store }: IDefaultComposableOptions) { @@ -47,17 +50,45 @@ export function useAirGap({ store }: IDefaultComposableOptions) { } /** - * Encodes an array of IAC message definition objects into a Uniform Resource (UR) format. + * Encodes an array of IACMessageDefinitionObjectV3 objects into a UR string. + * @param data - The array of IACMessageDefinitionObjectV3 objects to encode. + * @returns The UR string or null if an error occurs. */ async function encodeIACMessageDefinitionObjects(data: IACMessageDefinitionObjectV3[]) { - const serializer = SerializerV3.getInstance(); - const serializedData = await serializer.serialize(data); + try { + const serializer = SerializerV3.getInstance(); + const serializedData = await serializer.serialize(data); + + const buffer = await bs58check.decode(serializedData); + const ur = UR.fromBuffer(buffer); + + // Set the chunk sizes for single-chunk and multi-chunk encoding. + const SETTINGS_SERIALIZER_SINGLE_CHUNK_SIZE = 500; - const buffer = bs58check.decode(serializedData); - const ur = UR.fromBuffer(buffer); - const encoder = new UREncoder(ur); + // Create a UR encoder for single-chunk encoding. + const singleEncoder = new UREncoder( + ur, + SETTINGS_SERIALIZER_SINGLE_CHUNK_SIZE, + ); + // If the UR requires multi-chunk encoding, + // create a new UR encoder with the appropriate chunk size. + if (singleEncoder.fragmentsLength !== 1) { + // TODO:: handle when it's multi fragments. + // const SETTINGS_SERIALIZER_MULTI_CHUNK_SIZE = 250; + // const multiEncoder = new UREncoder( + // ur, + // SETTINGS_SERIALIZER_MULTI_CHUNK_SIZE, + // ); + return null; + } - return encoder; + // Encode the UR and return the UR string in upper case. + const urString = await singleEncoder.nextPart(); + return urString.toUpperCase(); + } catch (error) { + handleUnknownError(error); + return null; + } } /** @@ -88,14 +119,64 @@ export function useAirGap({ store }: IDefaultComposableOptions) { name: '', showed: true, type: ACCOUNT_AIR_GAP_WALLET, - isOffline: true, + airGapPublicKey: (item.payload as AccountShareResponse).publicKey, } as IAccount; }); } + /** + * Extracts the signed transaction response data from a serialized string + * and returns the transaction object. + * @param serializedData - The serialized string to extract data from. + * @returns The transaction object or null if no transaction object is found. + */ + async function extractSignedTransactionResponseData( + serializedData: string, + ): Promise { + const decodedData = await decodeURSerializedData(serializedData); + + if (!decodedData) { + return null; + } + + const payload = decodedData.find( + (item) => item.type === IACMessageType.TransactionSignResponse, + )?.payload as TransactionSignResponse; + + return payload?.transaction || null; + } + + async function generateEncodedTransactionSignRequestUR( + publicKey: string, + transaction: string, + networkId: string, + ): Promise { + const id = Math.floor(Math.random() * (99999999 - 10000000 + 1) + 10000000); + const callbackURL = 'superhero://?d='; + const payload: TransactionSignRequest = { + callbackURL, + publicKey, + transaction: { + networkId, + transaction, + }, + }; + const messageDefinitionObject: IACMessageDefinitionObjectV3 = { + id, + payload, + protocol: MainProtocolSymbols.AE, + type: IACMessageType.TransactionSignRequest, + }; + const encodedUR = await encodeIACMessageDefinitionObjects([messageDefinitionObject]); + + return encodedUR || null; + } + return { decodeURSerializedData, encodeIACMessageDefinitionObjects, extractAccountShareResponseData, + generateEncodedTransactionSignRequestUR, + extractSignedTransactionResponseData, }; } diff --git a/src/popup/components/Modals/TransferSend.vue b/src/popup/components/Modals/TransferSend.vue index e9e579ab0..590e11365 100644 --- a/src/popup/components/Modals/TransferSend.vue +++ b/src/popup/components/Modals/TransferSend.vue @@ -12,7 +12,9 @@ :is="currentStepConfig.component" ref="currentRenderedComponent" v-model="transferData" + :tx-raw="txRaw" :is-multisig="isMultisig" + :is-air-gap="isAirGap" :is-address-chain="isAddressChain" :is-address-url="isAddressUrl" @success="currentStepConfig.onSuccess" @@ -22,6 +24,15 @@