├── .gitignore ├── .vscode └── settings.json ├── useWalletIntegration_test ├── favicon.ico ├── 254.d328b436.iframe.bundle.js ├── 337.fbcdadec.iframe.bundle.js ├── 467.a671473b.iframe.bundle.js ├── 563.ed109dbc.iframe.bundle.js ├── main.581657bf.iframe.bundle.js.LICENSE.txt ├── 632.1d4e9c61.iframe.bundle.js.LICENSE.txt ├── 51.ea37875c.iframe.bundle.js.LICENSE.txt ├── 0.e5489f12ab94aa497491.manager.bundle.js.LICENSE.txt ├── 897.551867db.iframe.bundle.js.LICENSE.txt ├── 8.65ec2749796fb05c258c.manager.bundle.js.LICENSE.txt ├── 745.930e5d67.iframe.bundle.js ├── project.json ├── 863.d238e479.iframe.bundle.js.LICENSE.txt ├── 10.398dd7a0522c1ff2b3a8.manager.bundle.js ├── 807.1bf665ea.iframe.bundle.js.LICENSE.txt ├── 9.acd0ef9064e0667433ac.manager.bundle.js.LICENSE.txt ├── 171.e966548c.iframe.bundle.js.LICENSE.txt ├── vendors~main.7c47903ea43e951c3707.manager.bundle.js.LICENSE.txt ├── main.3fb8cb266a67ec5355cf.manager.bundle.js.LICENSE.txt ├── index.html ├── 527.a6a24b7a.iframe.bundle.js.LICENSE.txt ├── 701.872cb274.iframe.bundle.js ├── runtime~main.8e5cf3a9715a0d32d390.manager.bundle.js ├── runtime~main.d4fd3c81.iframe.bundle.js ├── 7.a1c5467faea0833b53d1.manager.bundle.js ├── 551.177b36e6.iframe.bundle.js ├── 72.04920903.iframe.bundle.js ├── iframe.html └── 522.4a558ff9.iframe.bundle.js ├── replit.nix ├── SECURITY.md ├── patches └── bignumber.js+9.1.1.patch ├── .github └── workflows │ └── dependency-review.yml ├── snap.manifest.json ├── package.json ├── src ├── verifyArgs.js ├── Scan.js ├── HTTPClient.js ├── Utils.js ├── AlgoWallet.js ├── Arcs.js ├── Swapper.js ├── index.js ├── WalletFuncs.js ├── Accounts.js └── TxnVerifier.js ├── sdk └── index_bundle.js.LICENSE.txt ├── images └── logo.svg ├── README.md └── replit_zip_error_log.txt /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /useWalletIntegration_test/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algorandfoundation/algo-metamask/HEAD/useWalletIntegration_test/favicon.ico -------------------------------------------------------------------------------- /useWalletIntegration_test/254.d328b436.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | (self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[254,563,467,337],{"?a449":function(){}}]); -------------------------------------------------------------------------------- /useWalletIntegration_test/337.fbcdadec.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | (self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[337,563,254,467],{"?a449":function(){}}]); -------------------------------------------------------------------------------- /useWalletIntegration_test/467.a671473b.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | (self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[467,563,254,337],{"?a449":function(){}}]); -------------------------------------------------------------------------------- /useWalletIntegration_test/563.ed109dbc.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | (self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[563,254,467,337],{"?a449":function(){}}]); -------------------------------------------------------------------------------- /replit.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: { 2 | deps = [ 3 | pkgs.nodejs-16_x 4 | pkgs.nodePackages.typescript-language-server 5 | pkgs.yarn 6 | pkgs.replitPackages.jest 7 | ]; 8 | } -------------------------------------------------------------------------------- /useWalletIntegration_test/main.581657bf.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ 2 | -------------------------------------------------------------------------------- /useWalletIntegration_test/632.1d4e9c61.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * The buffer module from node.js, for the browser. 3 | * 4 | * @author Feross Aboukhadijeh 5 | * @license MIT 6 | */ 7 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 10.0.0 | :white_check_mark: | 8 | | <10.0.0 | :x: | 9 | 10 | # contact 11 | paulrfears@gmail.com -------------------------------------------------------------------------------- /useWalletIntegration_test/51.ea37875c.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Prism: Lightweight, robust, elegant syntax highlighting 3 | * 4 | * @license MIT 5 | * @author Lea Verou 6 | * @namespace 7 | * @public 8 | */ 9 | -------------------------------------------------------------------------------- /useWalletIntegration_test/0.e5489f12ab94aa497491.manager.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * Prism: Lightweight, robust, elegant syntax highlighting 3 | * 4 | * @license MIT 5 | * @author Lea Verou 6 | * @namespace 7 | * @public 8 | */ 9 | -------------------------------------------------------------------------------- /useWalletIntegration_test/897.551867db.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * OverlayScrollbars 3 | * https://github.com/KingSora/OverlayScrollbars 4 | * 5 | * Version: 1.13.0 6 | * 7 | * Copyright KingSora | Rene Haas. 8 | * https://github.com/KingSora 9 | * 10 | * Released under the MIT license. 11 | * Date: 02.08.2020 12 | */ 13 | -------------------------------------------------------------------------------- /useWalletIntegration_test/8.65ec2749796fb05c258c.manager.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * OverlayScrollbars 3 | * https://github.com/KingSora/OverlayScrollbars 4 | * 5 | * Version: 1.13.0 6 | * 7 | * Copyright KingSora | Rene Haas. 8 | * https://github.com/KingSora 9 | * 10 | * Released under the MIT license. 11 | * Date: 02.08.2020 12 | */ 13 | -------------------------------------------------------------------------------- /useWalletIntegration_test/745.930e5d67.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[745],{"./node_modules/react-dom/client.js":function(__unused_webpack_module,exports,__webpack_require__){var m=__webpack_require__("./node_modules/react-dom/index.js");exports.createRoot=m.createRoot,exports.hydrateRoot=m.hydrateRoot}}]); -------------------------------------------------------------------------------- /useWalletIntegration_test/project.json: -------------------------------------------------------------------------------- 1 | {"generatedAt":1684848715838,"builder":{"name":"webpack5"},"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":false,"refCount":0,"packageManager":{"type":"yarn","version":"1.22.19"},"storybookVersion":"6.5.12","language":"typescript","storybookPackages":{"@storybook/addon-actions":{"version":"6.5.12"},"@storybook/builder-webpack5":{"version":"6.5.12"},"@storybook/manager-webpack5":{"version":"6.5.12"},"@storybook/react":{"version":"6.5.12"}},"framework":{"name":"react"},"addons":{"@storybook/addon-links":{"version":"6.5.12"},"@storybook/addon-essentials":{"version":"6.5.12"},"@storybook/preset-scss":{"version":"1.0.3"}}} 2 | -------------------------------------------------------------------------------- /patches/bignumber.js+9.1.1.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/bignumber.js/bignumber.js b/node_modules/bignumber.js/bignumber.js 2 | index a420e66..d69978d 100644 3 | --- a/node_modules/bignumber.js/bignumber.js 4 | +++ b/node_modules/bignumber.js/bignumber.js 5 | @@ -2443,7 +2443,7 @@ 6 | if (coeffToString(t.c).slice(0, s) === (n = coeffToString(r.c)).slice(0, s)) { 7 | 8 | // The exponent of r may here be one less than the final result exponent, 9 | - // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits 10 | + 11 | // are indexed correctly. 12 | if (r.e < e) --s; 13 | n = n.slice(s - 3, s + 1); 14 | -------------------------------------------------------------------------------- /useWalletIntegration_test/863.d238e479.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! ***************************************************************************** 2 | Copyright (c) Microsoft Corporation. 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any 5 | purpose with or without fee is hereby granted. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 9 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 11 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 12 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 13 | PERFORMANCE OF THIS SOFTWARE. 14 | ***************************************************************************** */ 15 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. 4 | # 5 | # Source repository: https://github.com/actions/dependency-review-action 6 | # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement 7 | name: 'Dependency Review' 8 | on: [pull_request] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | dependency-review: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: 'Checkout Repository' 18 | uses: actions/checkout@v3 19 | - name: 'Dependency Review' 20 | uses: actions/dependency-review-action@v2 21 | -------------------------------------------------------------------------------- /useWalletIntegration_test/10.398dd7a0522c1ff2b3a8.manager.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[10],{824:function(module,exports){module.exports=function(e,n){return n=n||{},new Promise((function(t,r){var s=new XMLHttpRequest,o=[],u=[],i={},a=function(){return{ok:2==(s.status/100|0),statusText:s.statusText,status:s.status,url:s.responseURL,text:function(){return Promise.resolve(s.responseText)},json:function(){return Promise.resolve(s.responseText).then(JSON.parse)},blob:function(){return Promise.resolve(new Blob([s.response]))},clone:a,headers:{keys:function(){return o},entries:function(){return u},get:function(e){return i[e.toLowerCase()]},has:function(e){return e.toLowerCase()in i}}}};for(var l in s.open(n.method||"get",e,!0),s.onload=function(){s.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm,(function(e,n,t){o.push(n=n.toLowerCase()),u.push([n,t]),i[n]=i[n]?i[n]+","+t:t})),t(a())},s.onerror=r,s.withCredentials="include"==n.credentials,n.headers)s.setRequestHeader(l,n.headers[l]);s.send(n.body||null)}))}}}]); -------------------------------------------------------------------------------- /snap.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "10.0.2", 3 | "description": "Algorand on Metamask", 4 | "proposedName": "Algorand Wallet", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/algorandfoundation/algo-metamask" 8 | }, 9 | "source": { 10 | "shasum": "Ac+HbVc2OlKU9zIGvp7JzHfuyNh4u1hiE3EC/tHIER0=", 11 | "location": { 12 | "npm": { 13 | "filePath": "dist/bundle.js", 14 | "iconPath": "images/logo.svg", 15 | "packageName": "@algorandfoundation/algorand-metamask-snap", 16 | "registry": "https://registry.npmjs.org" 17 | } 18 | } 19 | }, 20 | "initialPermissions": { 21 | "snap_dialog": {}, 22 | "endowment:network-access": {}, 23 | "snap_getBip44Entropy": [ 24 | { 25 | "coinType": 283 26 | } 27 | ], 28 | "snap_notify": {}, 29 | "snap_manageState": {}, 30 | "endowment:rpc": { 31 | "dapps": true, 32 | "snaps": false 33 | }, 34 | "endowment:ethereum-provider": {} 35 | }, 36 | "manifestVersion": "0.1" 37 | } 38 | -------------------------------------------------------------------------------- /useWalletIntegration_test/807.1bf665ea.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright Google Inc. All Rights Reserved. 4 | * 5 | * Use of this source code is governed by an MIT-style license that can be 6 | * found in the LICENSE file at https://angular.io/license 7 | */ 8 | 9 | /** 10 | * @license 11 | * Copyright Google Inc. All Rights Reserved. 12 | * 13 | * Use of this source code is governed by an MIT-style license that can be 14 | * found in the LICENSE file at https://angular.io/license 15 | */ 16 | 17 | /** 18 | * @license 19 | * Copyright Google Inc. All Rights Reserved. 20 | * 21 | * Use of this source code is governed by an MIT-style license that can be 22 | * found in the LICENSE file at https://angular.io/license 23 | */ 24 | 25 | /** 26 | * @license 27 | * Copyright Google Inc. All Rights Reserved. 28 | * 29 | * Use of this source code is governed by an MIT-style license that can be 30 | * found in the LICENSE file at https://angular.io/license 31 | */ 32 | -------------------------------------------------------------------------------- /useWalletIntegration_test/9.acd0ef9064e0667433ac.manager.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright Google Inc. All Rights Reserved. 4 | * 5 | * Use of this source code is governed by an MIT-style license that can be 6 | * found in the LICENSE file at https://angular.io/license 7 | */ 8 | 9 | /** 10 | * @license 11 | * Copyright Google Inc. All Rights Reserved. 12 | * 13 | * Use of this source code is governed by an MIT-style license that can be 14 | * found in the LICENSE file at https://angular.io/license 15 | */ 16 | 17 | /** 18 | * @license 19 | * Copyright Google Inc. All Rights Reserved. 20 | * 21 | * Use of this source code is governed by an MIT-style license that can be 22 | * found in the LICENSE file at https://angular.io/license 23 | */ 24 | 25 | /** 26 | * @license 27 | * Copyright Google Inc. All Rights Reserved. 28 | * 29 | * Use of this source code is governed by an MIT-style license that can be 30 | * found in the LICENSE file at https://angular.io/license 31 | */ 32 | -------------------------------------------------------------------------------- /useWalletIntegration_test/171.e966548c.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! ***************************************************************************** 2 | Copyright (c) Microsoft Corporation. 3 | 4 | Permission to use, copy, modify, and/or distribute this software for any 5 | purpose with or without fee is hereby granted. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 9 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 11 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 12 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 13 | PERFORMANCE OF THIS SOFTWARE. 14 | ***************************************************************************** */ 15 | 16 | /** 17 | * [js-sha3]{@link https://github.com/emn178/js-sha3} 18 | * 19 | * @version 0.8.0 20 | * @author Chen, Yi-Cyuan [emn178@gmail.com] 21 | * @copyright Chen, Yi-Cyuan 2015-2018 22 | * @license MIT 23 | */ 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algorandfoundation/algorand-metamask-snap", 3 | "version": "10.0.2", 4 | "description": "Snap for interacting with the Algorand ecosystem via Metamask. Algorand is a scalable layer-1 blockchain powered by the Pure Proof-of-Stake consensus mechanism with quick block times and instant finality.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "build": "yarn mm-snap build", 8 | "test": "yarn build && yarn serve", 9 | "postinstall": "patch-package", 10 | "testUseWallet": "npx mm-snap build && npx mm-snap serve --root=useWalletIntegration_test/" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/algorandfoundation/algo-metamask" 15 | }, 16 | "author": "", 17 | "license": "MIT", 18 | "dependencies": { 19 | "@babel/runtime": "^7.17.2", 20 | "@metamask/key-tree": "^6.0.0", 21 | "@metamask/snaps-ui": "^0.29.0", 22 | "algosdk": "1.14.0", 23 | "async": "^3.2.4", 24 | "async.js": "^0.9.5", 25 | "bignumber.js": "^9.1.1", 26 | "buffer": "^6.0.3", 27 | "crypto-js": "^4.1.1", 28 | "global": "^4.4.0", 29 | "nvm": "^0.0.4", 30 | "querystring": "^0.2.1", 31 | "url-search-params-polyfill": "^8.1.1" 32 | }, 33 | "devDependencies": { 34 | "@metamask/snaps-cli": "^0.32.2", 35 | "patch-package": "^6.4.7", 36 | "postinstall-postinstall": "^2.1.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/verifyArgs.js: -------------------------------------------------------------------------------- 1 | import Utils from "./Utils" 2 | export default function verifyArgs(walletTransaction, first){ 3 | let sign = true 4 | let message = "" 5 | let groupMessage = "" 6 | 7 | if(walletTransaction.hasOwnProperty("groupMessage")){ 8 | if(first === true){ 9 | groupMessage = walletTransaction.groupMessage; 10 | } 11 | else{ 12 | return Utils.throwError(4300, "groupMessage is only allowed to be specified on the first Transaction") 13 | } 14 | } 15 | 16 | if(walletTransaction.hasOwnProperty("msig")){ 17 | return Utils.throwError(4300, "msig is not supported by snapAlgo") 18 | } 19 | if(walletTransaction.hasOwnProperty("message")){ 20 | message = walletTransaction.message; 21 | } 22 | if(walletTransaction.hasOwnProperty("addrs")){ 23 | return Utils.throwError(4300, "opperation unsupported by snapAlgo"); 24 | } 25 | if(walletTransaction.hasOwnProperty("signers")){ 26 | if(isArray(walletTransaction.signers)){ 27 | if(walletTransaction.signer.length < 1){ 28 | sign = false 29 | } 30 | else{ 31 | //reject 32 | return Utils.throwError( 33 | 4300, 34 | "The Wallet does not support non-empty signers array" 35 | ) 36 | } 37 | } 38 | else{ 39 | return Utils.throwError(4300, "wallet Signers must be undefined or if the transaction is not to be signed an empty array") 40 | } 41 | } 42 | return {sign:sign, error:false, message:message, groupMessage:groupMessage} 43 | } -------------------------------------------------------------------------------- /sdk/index_bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * Sizzle CSS Selector Engine v2.3.6 3 | * https://sizzlejs.com/ 4 | * 5 | * Copyright JS Foundation and other contributors 6 | * Released under the MIT license 7 | * https://js.foundation/ 8 | * 9 | * Date: 2021-02-16 10 | */ 11 | 12 | /*! 13 | * jQuery JavaScript Library v3.6.0 14 | * https://jquery.com/ 15 | * 16 | * Includes Sizzle.js 17 | * https://sizzlejs.com/ 18 | * 19 | * Copyright OpenJS Foundation and other contributors 20 | * Released under the MIT license 21 | * https://jquery.org/license 22 | * 23 | * Date: 2021-03-02T17:08Z 24 | */ 25 | 26 | /*! 27 | * jQuery UI :data 1.13.1 28 | * http://jqueryui.com 29 | * 30 | * Copyright jQuery Foundation and other contributors 31 | * Released under the MIT license. 32 | * http://jquery.org/license 33 | */ 34 | 35 | /*! 36 | * jQuery UI Draggable 1.13.1 37 | * http://jqueryui.com 38 | * 39 | * Copyright jQuery Foundation and other contributors 40 | * Released under the MIT license. 41 | * http://jquery.org/license 42 | */ 43 | 44 | /*! 45 | * jQuery UI Mouse 1.13.1 46 | * http://jqueryui.com 47 | * 48 | * Copyright jQuery Foundation and other contributors 49 | * Released under the MIT license. 50 | * http://jquery.org/license 51 | */ 52 | 53 | /*! 54 | * jQuery UI Scroll Parent 1.13.1 55 | * http://jqueryui.com 56 | * 57 | * Copyright jQuery Foundation and other contributors 58 | * Released under the MIT license. 59 | * http://jquery.org/license 60 | */ 61 | 62 | /*! 63 | * jQuery UI Widget 1.13.1 64 | * http://jqueryui.com 65 | * 66 | * Copyright jQuery Foundation and other contributors 67 | * Released under the MIT license. 68 | * http://jquery.org/license 69 | */ 70 | -------------------------------------------------------------------------------- /useWalletIntegration_test/vendors~main.7c47903ea43e951c3707.manager.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /*! 8 | * https://github.com/es-shims/es5-shim 9 | * @license es5-shim Copyright 2009-2020 by contributors, MIT License 10 | * see https://github.com/es-shims/es5-shim/blob/master/LICENSE 11 | */ 12 | 13 | /*! 14 | * https://github.com/paulmillr/es6-shim 15 | * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com) 16 | * and contributors, MIT License 17 | * es6-shim: v0.35.4 18 | * see https://github.com/paulmillr/es6-shim/blob/0.35.3/LICENSE 19 | * Details and documentation: 20 | * https://github.com/paulmillr/es6-shim/ 21 | */ 22 | 23 | /*! 24 | * isobject 25 | * 26 | * Copyright (c) 2014-2017, Jon Schlinkert. 27 | * Released under the MIT License. 28 | */ 29 | 30 | /** @license React v0.19.1 31 | * scheduler.production.min.js 32 | * 33 | * Copyright (c) Facebook, Inc. and its affiliates. 34 | * 35 | * This source code is licensed under the MIT license found in the 36 | * LICENSE file in the root directory of this source tree. 37 | */ 38 | 39 | /** @license React v16.14.0 40 | * react-dom.production.min.js 41 | * 42 | * Copyright (c) Facebook, Inc. and its affiliates. 43 | * 44 | * This source code is licensed under the MIT license found in the 45 | * LICENSE file in the root directory of this source tree. 46 | */ 47 | 48 | /** @license React v16.14.0 49 | * react.production.min.js 50 | * 51 | * Copyright (c) Facebook, Inc. and its affiliates. 52 | * 53 | * This source code is licensed under the MIT license found in the 54 | * LICENSE file in the root directory of this source tree. 55 | */ 56 | -------------------------------------------------------------------------------- /useWalletIntegration_test/main.3fb8cb266a67ec5355cf.manager.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /*! 8 | * Fuse.js v3.6.1 - Lightweight fuzzy-search (http://fusejs.io) 9 | * 10 | * Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me) 11 | * All Rights Reserved. Apache Software License 2.0 12 | * 13 | * http://www.apache.org/licenses/LICENSE-2.0 14 | */ 15 | 16 | /*! ***************************************************************************** 17 | Copyright (c) Microsoft Corporation. 18 | 19 | Permission to use, copy, modify, and/or distribute this software for any 20 | purpose with or without fee is hereby granted. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 23 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 24 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 25 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 26 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 27 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 28 | PERFORMANCE OF THIS SOFTWARE. 29 | ***************************************************************************** */ 30 | 31 | /*! store2 - v2.13.1 - 2021-12-20 32 | * Copyright (c) 2021 Nathan Bubna; Licensed (MIT OR GPL-3.0) */ 33 | 34 | /** 35 | * React Router DOM v6.0.2 36 | * 37 | * Copyright (c) Remix Software Inc. 38 | * 39 | * This source code is licensed under the MIT license found in the 40 | * LICENSE.md file in the root directory of this source tree. 41 | * 42 | * @license MIT 43 | */ 44 | 45 | /** 46 | * React Router v6.0.2 47 | * 48 | * Copyright (c) Remix Software Inc. 49 | * 50 | * This source code is licensed under the MIT license found in the 51 | * LICENSE.md file in the root directory of this source tree. 52 | * 53 | * @license MIT 54 | */ 55 | -------------------------------------------------------------------------------- /src/Scan.js: -------------------------------------------------------------------------------- 1 | import Utils from './Utils'; 2 | import Accounts from './Accounts'; 3 | 4 | /* 5 | This checks with a remote server to see if there is a known vulnerability in this version of snapalgo 6 | If a vulnerability is found a course of action is taken depending on the serverity of the vulnerability 7 | */ 8 | 9 | export default async function Scan(version, url){ 10 | const combinedURL = url+version+".json" 11 | let actions; 12 | try{ 13 | const msg = await fetch(combinedURL) 14 | actions = await msg.json() 15 | } 16 | catch(e){ 17 | console.error("no warning file for this version"); 18 | return true 19 | } 20 | if(!actions.action){ 21 | return true 22 | } 23 | for(let warning of actions.warnings){ 24 | const anwser = await Utils.sendConfirmation(warning[0], warning[1], warning[2]); 25 | if(!anwser){ 26 | return false 27 | } 28 | } 29 | if(actions.getMnemonics){ 30 | const accountLibary = new Accounts(wallet); 31 | const accountObject = await accountLibary.getAccounts(); 32 | const addresses = Object.keys(accountObject); 33 | await Utils.sendConfirmation( 34 | "Critical Vulnerability", 35 | "A severe Vulnerabillity detected", 36 | "Your accounts are vurnerable. Update as soon as possible We will show your account passphrases now. copy them down, then import them into another wallet and move your funds"); 37 | await Utils.sendConfirmation("further Info", "Update","When an update becomes available you can update and import your new accounts at https://snapalgo.io/importaccount") 38 | for(let addr of addresses){ 39 | const name = accountObject[addr].name; 40 | await Utils.sendConfirmation( 41 | "get Account Mnemonic", 42 | "we will now display display mnemonic", 43 | `We are now going to display the mnemonic for Account ${name} with the Address ${addresses}, write it down and move funds out of this account as soon as possible` 44 | ); 45 | const keyPair = await accountLibary.unlockAccount(addr); 46 | const mnemonic = await accountLibary.getMnemonic(keyPair); 47 | await Utils.sendConfirmation(name, addr, mnemonic); 48 | 49 | 50 | } 51 | } 52 | return actions.useable; 53 | } -------------------------------------------------------------------------------- /useWalletIntegration_test/index.html: -------------------------------------------------------------------------------- 1 | Webpack App
-------------------------------------------------------------------------------- /src/HTTPClient.js: -------------------------------------------------------------------------------- 1 | 2 | const querystring = require('querystring'); 3 | 4 | export default class HTTPClient{ 5 | constructor(){ 6 | 7 | this.urlTable = { 8 | "algod":{ 9 | "mainnet-v1.0": "https://mainnet-api.algonode.cloud", 10 | "testnet-v1.0": "https://testnet-api.algonode.cloud", 11 | "betanet-v1.0": "https://betanet-api.algonode.cloud" 12 | }, 13 | "index":{ 14 | "mainnet-v1.0": "https://mainnet-idx.algonode.cloud", 15 | "testnet-v1.0": "https://testnet-idx.algonode.cloud", 16 | "betanet-v1.0": "https://betanet-idx.algonode.cloud" 17 | } 18 | } 19 | 20 | } 21 | get(type, network){ 22 | const baseHTTPClient = {} 23 | baseHTTPClient.get = (relativePath, query, requestHeaders) => { 24 | if(query){ 25 | query = querystring.stringify(query); 26 | if(query.length > 0){ 27 | query = "?"+query; 28 | } 29 | 30 | } 31 | else{ 32 | query = '' 33 | } 34 | if(!requestHeaders){ 35 | requestHeaders = {} 36 | } 37 | return fetch(this.urlTable[type][network]+relativePath+query, { 38 | method: "get", 39 | headers: requestHeaders, 40 | }) 41 | .then(async (res)=>{ 42 | let output = {}; 43 | 44 | output.status = await res.status 45 | output.body = new Uint8Array(await res.arrayBuffer()); 46 | output.headers = await res.headers 47 | return output; 48 | }) 49 | 50 | } 51 | baseHTTPClient.post = (relativePath, data, query, requestHeaders) => { 52 | if(!requestHeaders){ 53 | requestHeaders = {} 54 | } 55 | if(!data){ 56 | data = {} 57 | } 58 | if(query){ 59 | query = querystring.stringify(query); 60 | if(query.length > 0){ 61 | query = "?"+query; 62 | } 63 | } 64 | else{ 65 | query = '' 66 | } 67 | return fetch(this.urlTable[type][network]+relativePath+query, { 68 | method: "post", 69 | headers: requestHeaders, 70 | body: new Uint8Array(data) 71 | }) 72 | .then(async (res)=>{ 73 | let output = {} 74 | output.status = await res.status 75 | output.body = new Uint8Array(await res.arrayBuffer()); 76 | output.headers = await res.headers 77 | return output 78 | }) 79 | } 80 | 81 | return baseHTTPClient; 82 | } 83 | 84 | } -------------------------------------------------------------------------------- /src/Utils.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Class for utility functions 4 | 5 | wallet is a global in the metamask context 6 | */ 7 | import { panel, text, heading, divider, copyable } from '@metamask/snaps-ui'; 8 | export default class Utils { 9 | 10 | static throwError(code, msg){ 11 | if(code === undefined){ 12 | code = 0 13 | } 14 | //metamask overrides Error codes 15 | //This function encodes an arc complient error code 16 | //into the error message, and is then seperated by the SDK 17 | console.error(JSON.stringify(msg)); 18 | throw new Error(`${code}\n${msg}`); 19 | } 20 | 21 | static async notify(message){ 22 | try{ 23 | await snap.request({ 24 | method: 'snap_notify', 25 | params: { 26 | type: 'inApp', 27 | message: message, 28 | }, 29 | }); 30 | 31 | const result = await snap.request({ 32 | method: 'snap_notify', 33 | params: { 34 | type: 'native', 35 | message: message, 36 | }, 37 | }); 38 | return true; 39 | } 40 | catch(e){ 41 | console.error(e); 42 | await Utils.sendConfirmation("alert", "notifcation", message); 43 | return false; 44 | } 45 | 46 | 47 | } 48 | 49 | static async sendConfirmation(prompt, description, textAreaContent){ 50 | if(!textAreaContent){ 51 | textAreaContent = "" 52 | } 53 | const confirm= await snap.request({ 54 | method: 'snap_dialog', 55 | params: { 56 | type: 'confirmation', 57 | content: panel([ 58 | heading(prompt), 59 | divider(), 60 | text(description), 61 | divider(), 62 | text(textAreaContent), 63 | ]), 64 | }, 65 | }); 66 | 67 | return confirm; 68 | } 69 | 70 | static async sendAlert(title, info){ 71 | const alert = await snap.request({ 72 | method: 'snap_dialog', 73 | params:{ 74 | type: 'alert', 75 | content: panel([ 76 | heading(title), 77 | divider(), 78 | text(info) 79 | ]) 80 | } 81 | }) 82 | return alert; 83 | } 84 | 85 | static async balanceDisplay(address, balance){ 86 | const alert = await snap.request({ 87 | method: 'snap_dialog', 88 | params:{ 89 | type: 'alert', 90 | content: panel([ 91 | heading("Account"), 92 | copyable(address), 93 | divider(), 94 | heading("Balance"), 95 | text(balance+" Algos") 96 | ]) 97 | } 98 | }) 99 | return alert; 100 | } 101 | 102 | static async displayPanel(panel, type="confirmation"){ 103 | const disp = await snap.request({ 104 | method: 'snap_dialog', 105 | params:{ 106 | type: type, 107 | content: panel 108 | } 109 | }) 110 | return disp 111 | } 112 | 113 | 114 | } -------------------------------------------------------------------------------- /src/AlgoWallet.js: -------------------------------------------------------------------------------- 1 | import Utils from "./Utils"; 2 | import HTTPClient from "./HTTPClient"; 3 | const algosdk = require('algosdk/dist/cjs'); 4 | 5 | export default class AlgoWallet{ 6 | constructor(Account){ 7 | this.testnet = false; 8 | this.IdTable = { 9 | "mainnet-v1.0":"wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", 10 | "testnet-v1.0": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", 11 | "betanet-v1.0": "mFgazF+2uRS1tMiL9dsj01hJGySEmPN28B/TjjvpVW0=" 12 | }; 13 | this.network = "mainnet-v1.0"; 14 | this.genisisHash = "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="; 15 | this.Account = Account; 16 | this.sk = this.Account.sk; 17 | this.addr = this.Account.addr; 18 | 19 | 20 | } 21 | 22 | /* 23 | 24 | ------------------------------------------ Getters ------------------------------------------------------- 25 | 26 | */ 27 | getGenesisId(){ 28 | return this.network; 29 | } 30 | getGenesisHash(){ 31 | return this.genisisHash; 32 | } 33 | getAccount(){ 34 | return this.Account; 35 | } 36 | getTestnet(){ 37 | return this.testnet; 38 | } 39 | 40 | getAddress(){ 41 | return this.Account.addr; 42 | } 43 | 44 | getName(){ 45 | return this.Account.name; 46 | } 47 | 48 | getSK(){ 49 | return this.Account.sk; 50 | } 51 | 52 | getIndexer(){ 53 | let indexerBaseClient = new HTTPClient().get("index", this.network); 54 | return new algosdk.Indexer(indexerBaseClient); 55 | } 56 | 57 | getAlgod(){ 58 | let algodBaseClient = new HTTPClient().get("algod", this.network); 59 | return new algosdk.Algodv2(algodBaseClient) 60 | } 61 | 62 | /* 63 | 64 | ------------------------------------------ Setters ------------------------------------------------------- 65 | 66 | */ 67 | 68 | setTestnet(testnet){ 69 | this.testnet = testnet; 70 | if(testnet){ 71 | this.network = "testnet-v1.0"; 72 | this.genisisHash = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="; 73 | } 74 | } 75 | setGenesisId(genesisId){ 76 | //check for validity 77 | if(!(genesisId in this.IdTable)){ 78 | Utils.throwError("Unsupported genesis id", 4200); 79 | } 80 | //set GenesisHash and GenesisId 81 | this.network = genesisId; 82 | this.genisisHash = this.IdTable[genesisId]; 83 | //setTestnet 84 | if(this.network === "testnet-v1.0"){ 85 | this.testnet = true; 86 | } 87 | else{ 88 | this.testnet = false; 89 | } 90 | } 91 | setGenesisHash(genesisHash){ 92 | this.genisisHash = genesisHash; 93 | 94 | //check for validity 95 | if(!Object.values(this.IdTable).includes(genesisHash)){ 96 | Utils.throwError("Unsupported genesis hash", 4200); 97 | } 98 | 99 | //set GenesisId 100 | const network = Object.keys(this.IdTable).find(key => this.IdTable[key] === genesisHash); 101 | this.network = network; 102 | 103 | //set Testnet 104 | if(genesisHash === "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="){ 105 | this.testnet = true; 106 | } 107 | else{ 108 | this.testnet = false; 109 | } 110 | 111 | } 112 | } -------------------------------------------------------------------------------- /useWalletIntegration_test/527.a6a24b7a.iframe.bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * [hi-base32]{@link https://github.com/emn178/hi-base32} 3 | * 4 | * @version 0.5.0 5 | * @author Chen, Yi-Cyuan [emn178@gmail.com] 6 | * @copyright Chen, Yi-Cyuan 2015-2018 7 | * @license MIT 8 | */ 9 | 10 | /* 11 | * [js-sha512]{@link https://github.com/emn178/js-sha512} 12 | * 13 | * @version 0.8.0 14 | * @author Chen, Yi-Cyuan [emn178@gmail.com] 15 | * @copyright Chen, Yi-Cyuan 2014-2018 16 | * @license MIT 17 | */ 18 | 19 | /* 20 | object-assign 21 | (c) Sindre Sorhus 22 | @license MIT 23 | */ 24 | 25 | /*! 26 | * The buffer module from node.js, for the browser. 27 | * 28 | * @author Feross Aboukhadijeh 29 | * @license MIT 30 | */ 31 | 32 | /*! 33 | * The buffer module from node.js, for the browser. 34 | * 35 | * @author Feross Aboukhadijeh 36 | * @license MIT 37 | */ 38 | 39 | /*! 40 | * https://github.com/es-shims/es5-shim 41 | * @license es5-shim Copyright 2009-2020 by contributors, MIT License 42 | * see https://github.com/es-shims/es5-shim/blob/master/LICENSE 43 | */ 44 | 45 | /*! 46 | * is-plain-object 47 | * 48 | * Copyright (c) 2014-2017, Jon Schlinkert. 49 | * Released under the MIT License. 50 | */ 51 | 52 | /*! 53 | * isobject 54 | * 55 | * Copyright (c) 2014-2017, Jon Schlinkert. 56 | * Released under the MIT License. 57 | */ 58 | 59 | /*! For license information please see index_bundle.js.LICENSE.txt */ 60 | 61 | /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ 62 | 63 | /** 64 | * @license React 65 | * react-dom.production.min.js 66 | * 67 | * Copyright (c) Facebook, Inc. and its affiliates. 68 | * 69 | * This source code is licensed under the MIT license found in the 70 | * LICENSE file in the root directory of this source tree. 71 | */ 72 | 73 | /** 74 | * @license React 75 | * react-jsx-runtime.production.min.js 76 | * 77 | * Copyright (c) Facebook, Inc. and its affiliates. 78 | * 79 | * This source code is licensed under the MIT license found in the 80 | * LICENSE file in the root directory of this source tree. 81 | */ 82 | 83 | /** 84 | * @license React 85 | * react.production.min.js 86 | * 87 | * Copyright (c) Facebook, Inc. and its affiliates. 88 | * 89 | * This source code is licensed under the MIT license found in the 90 | * LICENSE file in the root directory of this source tree. 91 | */ 92 | 93 | /** 94 | * @license React 95 | * scheduler.production.min.js 96 | * 97 | * Copyright (c) Facebook, Inc. and its affiliates. 98 | * 99 | * This source code is licensed under the MIT license found in the 100 | * LICENSE file in the root directory of this source tree. 101 | */ 102 | 103 | /** 104 | * @license React 105 | * use-sync-external-store-shim.production.min.js 106 | * 107 | * Copyright (c) Facebook, Inc. and its affiliates. 108 | * 109 | * This source code is licensed under the MIT license found in the 110 | * LICENSE file in the root directory of this source tree. 111 | */ 112 | 113 | /** 114 | * @license React 115 | * use-sync-external-store-shim/with-selector.production.min.js 116 | * 117 | * Copyright (c) Facebook, Inc. and its affiliates. 118 | * 119 | * This source code is licensed under the MIT license found in the 120 | * LICENSE file in the root directory of this source tree. 121 | */ 122 | 123 | /** @license React v17.0.2 124 | * react-is.production.min.js 125 | * 126 | * Copyright (c) Facebook, Inc. and its affiliates. 127 | * 128 | * This source code is licensed under the MIT license found in the 129 | * LICENSE file in the root directory of this source tree. 130 | */ 131 | 132 | //! stable.js 0.1.8, https://github.com/Two-Screen/stable 133 | 134 | //! © 2018 Angry Bytes and contributors. MIT licensed. 135 | -------------------------------------------------------------------------------- /useWalletIntegration_test/701.872cb274.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[701],{"./node_modules/@storybook/preview-web/dist/esm/renderDocs.js":function(__unused_webpack_module,__webpack_exports__,__webpack_require__){__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{renderDocs:function(){return renderDocs},unmountDocs:function(){return unmountDocs}});__webpack_require__("./node_modules/regenerator-runtime/runtime.js"),__webpack_require__("./node_modules/core-js/modules/es.object.to-string.js"),__webpack_require__("./node_modules/core-js/modules/es.promise.js");var react=__webpack_require__("./node_modules/react/index.js"),react_dom=__webpack_require__("./node_modules/react-dom/index.js"),wrapper={fontSize:"14px",letterSpacing:"0.2px",margin:"10px 0"},main={margin:"auto",padding:30,borderRadius:10,background:"rgba(0,0,0,0.03)"},heading={textAlign:"center"},NoDocs=function NoDocs(){return react.createElement("div",{style:wrapper,className:"sb-nodocs sb-wrapper"},react.createElement("div",{style:main},react.createElement("h1",{style:heading},"No Docs"),react.createElement("p",null,"Sorry, but there are no docs for the selected story. To add them, set the story's ",react.createElement("code",null,"docs")," parameter. If you think this is an error:"),react.createElement("ul",null,react.createElement("li",null,"Please check the story definition."),react.createElement("li",null,"Please check the Storybook config."),react.createElement("li",null,"Try reloading the page.")),react.createElement("p",null,"If the problem persists, check the browser console, or the terminal you've run Storybook from.")))};function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _asyncToGenerator(fn){return function(){var self=this,args=arguments;return new Promise((function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)}))}}function renderDocs(story,docsContext,element,callback){return function renderDocsAsync(_x,_x2,_x3){return _renderDocsAsync.apply(this,arguments)}(story,docsContext,element).then(callback)}function _renderDocsAsync(){return(_renderDocsAsync=_asyncToGenerator(regeneratorRuntime.mark((function _callee(story,docsContext,element){var _docs$getContainer,_docs$getPage,docs,DocsContainer,Page,docsElement;return regeneratorRuntime.wrap((function _callee$(_context){for(;;)switch(_context.prev=_context.next){case 0:if(!(null!=(docs=story.parameters.docs)&&docs.getPage||null!=docs&&docs.page)||(null!=docs&&docs.getContainer||null!=docs&&docs.container)){_context.next=3;break}throw new Error("No `docs.container` set, did you run `addon-docs/preset`?");case 3:if(_context.t1=docs.container,_context.t1){_context.next=8;break}return _context.next=7,null===(_docs$getContainer=docs.getContainer)||void 0===_docs$getContainer?void 0:_docs$getContainer.call(docs);case 7:_context.t1=_context.sent;case 8:if(_context.t0=_context.t1,_context.t0){_context.next=11;break}_context.t0=function(_ref){var children=_ref.children;return react.createElement(react.Fragment,null,children)};case 11:if(DocsContainer=_context.t0,_context.t3=docs.page,_context.t3){_context.next=17;break}return _context.next=16,null===(_docs$getPage=docs.getPage)||void 0===_docs$getPage?void 0:_docs$getPage.call(docs);case 16:_context.t3=_context.sent;case 17:if(_context.t2=_context.t3,_context.t2){_context.next=20;break}_context.t2=NoDocs;case 20:return Page=_context.t2,docsElement=react.createElement(DocsContainer,{key:story.componentId,context:docsContext},react.createElement(Page,null)),_context.next=24,new Promise((function(resolve){react_dom.render(docsElement,element,resolve)}));case 24:case"end":return _context.stop()}}),_callee)})))).apply(this,arguments)}function unmountDocs(element){react_dom.unmountComponentAtNode(element)}NoDocs.displayName="NoDocs"}}]); -------------------------------------------------------------------------------- /useWalletIntegration_test/runtime~main.8e5cf3a9715a0d32d390.manager.bundle.js: -------------------------------------------------------------------------------- 1 | !function(modules){function webpackJsonpCallback(data){for(var moduleId,chunkId,chunkIds=data[0],moreModules=data[1],executeModules=data[2],i=0,resolves=[];i Buffer.from(stxB64, "base64")) 104 | const ogTxn = algosdk.decodeSignedTransaction(stxns[0]).txn; 105 | if(ogTxn.genesisID === "testnet-v1.0"){ 106 | this.wallet.setTestnet(true); 107 | } 108 | const algod = this.wallet.getAlgod() 109 | const result = (await algod.sendRawTransaction(stxns).do()) 110 | const txId = result.txId; 111 | if(txId === undefined){ 112 | await Utils.sendConfirmation("Invalid Transaction", "Invalid Transaction", result.message); 113 | Utils.throwError(4300, result.message); 114 | } 115 | try{ 116 | await algosdk.waitForConfirmation(algod, txId, 4) 117 | Utils.notify("transaction was successful \n"+result['confirmed-round']); 118 | } 119 | catch(e){ 120 | Utils.notify("transaction submission failed"); 121 | } 122 | return txId; 123 | } 124 | 125 | async signAndPostTxns(txns, originString){ 126 | const signedTxns = await this.signTxns(txns, originString); 127 | let txId = await this.postTxns(signedTxns); 128 | return txId; 129 | } 130 | } -------------------------------------------------------------------------------- /useWalletIntegration_test/runtime~main.d4fd3c81.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var deferred,leafPrototypes,getProto,inProgress,__webpack_modules__={},__webpack_module_cache__={};function __webpack_require__(moduleId){var cachedModule=__webpack_module_cache__[moduleId];if(void 0!==cachedModule)return cachedModule.exports;var module=__webpack_module_cache__[moduleId]={id:moduleId,loaded:!1,exports:{}};return __webpack_modules__[moduleId].call(module.exports,module,module.exports,__webpack_require__),module.loaded=!0,module.exports}__webpack_require__.m=__webpack_modules__,__webpack_require__.amdO={},deferred=[],__webpack_require__.O=function(result,chunkIds,fn,priority){if(!chunkIds){var notFulfilled=1/0;for(i=0;i=priority)&&Object.keys(__webpack_require__.O).every((function(key){return __webpack_require__.O[key](chunkIds[j])}))?chunkIds.splice(j--,1):(fulfilled=!1,priority0&&deferred[i-1][2]>priority;i--)deferred[i]=deferred[i-1];deferred[i]=[chunkIds,fn,priority]},__webpack_require__.n=function(module){var getter=module&&module.__esModule?function(){return module.default}:function(){return module};return __webpack_require__.d(getter,{a:getter}),getter},getProto=Object.getPrototypeOf?function(obj){return Object.getPrototypeOf(obj)}:function(obj){return obj.__proto__},__webpack_require__.t=function(value,mode){if(1&mode&&(value=this(value)),8&mode)return value;if("object"==typeof value&&value){if(4&mode&&value.__esModule)return value;if(16&mode&&"function"==typeof value.then)return value}var ns=Object.create(null);__webpack_require__.r(ns);var def={};leafPrototypes=leafPrototypes||[null,getProto({}),getProto([]),getProto(getProto)];for(var current=2&mode&&value;"object"==typeof current&&!~leafPrototypes.indexOf(current);current=getProto(current))Object.getOwnPropertyNames(current).forEach((function(key){def[key]=function(){return value[key]}}));return def.default=function(){return value},__webpack_require__.d(ns,def),ns},__webpack_require__.d=function(exports,definition){for(var key in definition)__webpack_require__.o(definition,key)&&!__webpack_require__.o(exports,key)&&Object.defineProperty(exports,key,{enumerable:!0,get:definition[key]})},__webpack_require__.f={},__webpack_require__.e=function(chunkId){return Promise.all(Object.keys(__webpack_require__.f).reduce((function(promises,key){return __webpack_require__.f[key](chunkId,promises),promises}),[]))},__webpack_require__.u=function(chunkId){return chunkId+"."+{51:"ea37875c",72:"04920903",171:"e966548c",206:"5e9b0308",229:"241d6a2b",254:"d328b436",337:"fbcdadec",339:"cfe76cf2",467:"a671473b",522:"4a558ff9",551:"177b36e6",563:"ed109dbc",627:"d69b7e80",632:"1d4e9c61",652:"1b16d8d0",668:"65f4a9e9",701:"872cb274",745:"930e5d67",807:"1bf665ea",863:"d238e479",897:"551867db",915:"676a7baa",928:"b98e9010",935:"dd787e1b"}[chunkId]+".iframe.bundle.js"},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=function(module){return(module=Object.create(module)).children||(module.children=[]),Object.defineProperty(module,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+module.id)}}),module},__webpack_require__.o=function(obj,prop){return Object.prototype.hasOwnProperty.call(obj,prop)},inProgress={},__webpack_require__.l=function(url,done,key,chunkId){if(inProgress[url])inProgress[url].push(done);else{var script,needAttach;if(void 0!==key)for(var scripts=document.getElementsByTagName("script"),i=0;i 2 | 4 | 7 | 8 | 10 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/Swapper.js: -------------------------------------------------------------------------------- 1 | import Utils from './Utils'; 2 | 3 | const BigNumber = require('bignumber.js'); 4 | async function postData(url = '', data = {}) { 5 | const response = await fetch(url, { 6 | method: 'POST', 7 | mode: 'cors', 8 | credentials: 'include', 9 | headers:{ 10 | 'Content-Type':'application/json' 11 | }, 12 | body: JSON.stringify(data) 13 | }); 14 | 15 | return await response.json() 16 | } 17 | 18 | const chains = { 19 | "bsc":{ 20 | type:"imported", 21 | changeNowName: "bnbbsc", 22 | data: 23 | { 24 | chainId: "0x38", 25 | chainName: "Binance Smart Chain", 26 | nativeCurrency: { 27 | name: "Binance Smart Chain", 28 | symbol: "BSC", 29 | decimals: 18 30 | }, 31 | rpcUrls: ["https://bsc-dataseed.binance.org/"], 32 | blockExplorerUrls: ["https://bscscan.com"], 33 | iconUrls: ["https://bitbill.oss-accelerate.aliyuncs.com/pics/coins/bsc.svg"] 34 | } 35 | }, 36 | "eth":{ 37 | type:"native", 38 | changeNowName: "eth", 39 | data:{ 40 | chainId:"0x1", 41 | chainName: "Ethereum", 42 | nativeCurrency:{ 43 | name: "Ether", 44 | symbol: "ETH", 45 | decimals: 18 46 | } 47 | } 48 | }, 49 | "algo":{ 50 | type:"snap", 51 | changeNowName: "algo", 52 | data:{ 53 | chainName: "Algorand", 54 | nativeCurrency:{ 55 | name:"Algo", 56 | symbol:"AlGO", 57 | decimals: 6 58 | } 59 | } 60 | } 61 | } 62 | 63 | export default class Swapper{ 64 | static tickers = {'algo':'algo', 'bsc':'bnbbsc', 'eth':'eth'} 65 | constructor(snap, ethereum, algoWallet, walletFuncs){ 66 | this.snap = snap; 67 | this.ethereum = ethereum 68 | this.algoWallet = algoWallet; 69 | this.walletFuncs = walletFuncs 70 | this.url = "https://y6ha2w3noelczmwztfidtarc3q0lrrgi.lambda-url.us-east-2.on.aws/"; 71 | } 72 | 73 | static toSmallestUnit(amount, ticker){ 74 | amount = new BigNumber(amount); 75 | const output = amount.times(new BigNumber(10).exponentiatedBy(chains[ticker].data.nativeCurrency.decimals)).toFixed() 76 | return output; 77 | } 78 | 79 | async sendEvm(to, wei, ticker){ 80 | await this.switchChain(ticker); 81 | const amount = '0x'+BigInt(wei).toString(16); 82 | if(this.ethereum.selectedAddress === null){ 83 | await this.ethereum.request({ method: 'eth_requestAccounts' }); 84 | } 85 | const transactionParameters = { 86 | nonce: '0x00', // ignored by MetaMask 87 | to: to, // Required except during contract publications. 88 | from: this.ethereum.selectedAddress, // must match user's active address. 89 | value: amount, // Only required to send ether to the recipient from the initiating external account. 90 | chainId: chains[ticker].data.chainId, // Used to prevent transaction reuse across blockchains. Auto-filled by MetaMask. 91 | }; 92 | const txHash = await this.ethereum.request({ 93 | method: 'eth_sendTransaction', 94 | params: [transactionParameters], 95 | }); 96 | return txHash; 97 | 98 | } 99 | 100 | async sendSnap(to, amount, ticker){ 101 | amount = BigInt(amount); 102 | if(ticker === "algo"){ 103 | await this.walletFuncs.transfer(to, amount); 104 | } 105 | } 106 | 107 | async switchChain(symbol){ 108 | try{ 109 | await this.ethereum.request({ 110 | method: 'wallet_switchEthereumChain', 111 | params: [{ chainId: chains[symbol].data.chainId }], 112 | }); 113 | return true; 114 | } 115 | catch(e){ 116 | if (e.code === 4902) { 117 | if(chains[symbol].type === "imported"){ 118 | await this.ethereum.request({ 119 | method: 'wallet_addEthereumChain', 120 | params: [ 121 | chains[symbol].data 122 | ], 123 | }); 124 | await this.ethereum.request({ 125 | method: 'wallet_switchEthereumChain', 126 | params: [{ chainId: chains[symbol].data.chainId }], 127 | }); 128 | return true; 129 | } 130 | } 131 | return e; 132 | } 133 | 134 | 135 | 136 | } 137 | 138 | async getMin(from, to){ 139 | from = from.toLowerCase(); 140 | to = to.toLowerCase(); 141 | let data = await postData(this.url, { 142 | "action":"getMin", 143 | "from":chains[from].changeNowName, 144 | "to":chains[to].changeNowName, 145 | }) 146 | return data.body; 147 | } 148 | 149 | async getSwapHistory(){ 150 | const state = await this.snap.request({ 151 | method: 'snap_manageState', 152 | params: {operation: 'get'}, 153 | }); 154 | return state.Accounts[state.currentAccountId].swaps; 155 | } 156 | 157 | async getStatus(transactionId){ 158 | let data = await postData(this.url, { 159 | "action":"status", 160 | "id": transactionId 161 | }) 162 | return data.body; 163 | } 164 | 165 | 166 | async preSwap(from, to, amount){ 167 | if(this.algoWallet.testnet){ 168 | return Utils.throwError(4300, "Swapping can only be done on the mainnet"); 169 | } 170 | from = from.toLowerCase(); 171 | to = to.toLowerCase(); 172 | if(!(from in chains)){ 173 | return Utils.throwError(500, "unsupported Ticker"); 174 | } 175 | if(!(to in chains)){ 176 | return Utils.throwError(500, "unsupported Ticker"); 177 | } 178 | let data = await postData(this.url, { 179 | "action":"preSwap", 180 | "from":chains[from].changeNowName, 181 | "to":chains[to].changeNowName, 182 | "amount":amount 183 | }) 184 | return data.body; 185 | } 186 | 187 | async swap(from, to, amount, email){ 188 | if(this.algoWallet.testnet){ 189 | return Utils.throwError(4300, "swapping can only be done on the mainnet"); 190 | } 191 | from = from.toLowerCase(); 192 | to = to.toLowerCase(); 193 | if(!(from in chains)){ 194 | Utils.throwError(500, "unsupported Ticker"); 195 | } 196 | if(!(to in chains)){ 197 | Utils.throwError(500, "unsupported Ticker"); 198 | } 199 | let outputAddress = null; 200 | if(chains[to].type === "snap"){ 201 | outputAddress = this.algoWallet.getAddress() 202 | } 203 | else if(chains[to].type === "imported" || chains[to].type === "native"){ 204 | if(chains[to].type === "imported"){ 205 | await this.switchChain(to); 206 | } 207 | const ethAccounts = await this.ethereum.request({ method: 'eth_requestAccounts' }); 208 | const ethAccount = ethAccounts[0]; 209 | outputAddress = ethAccount 210 | } 211 | let swapData = await postData(this.url, { 212 | "action":"swap", 213 | "from":chains[from].changeNowName, 214 | "to":chains[to].changeNowName, 215 | "amount":amount, 216 | "addr": outputAddress, 217 | "email": email?email:"" 218 | }) 219 | if(swapData.body.error === "true"){ 220 | Utils.throwError(500, JSON.stringify(swapData.body)); 221 | } 222 | 223 | swapData.body.link = "https://changenow.io/exchange/txs/"+ swapData.body.id; 224 | swapData.body.timeStamp = String(new Date()); 225 | const swapConfirmation = await Utils.sendConfirmation( 226 | "Confirm Swap", 227 | "Would you like to confirm this swap", 228 | `Would you like to to swap ${amount} ${swapData.body.fromCurrency} for an estimated ${swapData.body.amount} ${swapData.body.toCurrency}` 229 | ); 230 | if(!swapConfirmation){ 231 | return Utils.throwError(4300, "User Rejected Request"); 232 | } 233 | if(swapData.body.error){ 234 | return Utils.throwError(500, "Error in Swap") 235 | } 236 | const sendAmount = Swapper.toSmallestUnit(amount, from); 237 | if(chains[from].type === "imported" || chains[from].type === "native"){ 238 | await this.sendEvm(swapData.body.payinAddress, sendAmount, from, outputAddress); 239 | } 240 | if(chains[from].type === "snap"){ 241 | await this.sendSnap(swapData.body.payinAddress, sendAmount, from); 242 | } 243 | 244 | 245 | let state = await this.snap.request({ 246 | method: 'snap_manageState', 247 | params: {operation: 'get'}, 248 | }); 249 | if(state.Accounts[state.currentAccountId].swaps == undefined){ 250 | console.error("swap history for this address is undefined"); 251 | state.Accounts[state.currentAccountId].swaps = [swapData.body] 252 | } 253 | else{ 254 | state.Accounts[state.currentAccountId].swaps.unshift(swapData.body) 255 | } 256 | await this.snap.request({ 257 | method: 'snap_manageState', 258 | params: {operation:'update', newState:state} 259 | }) 260 | return swapData.body; 261 | } 262 | 263 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | import Accounts from './Accounts'; 3 | import AlgoWallet from './AlgoWallet'; 4 | import WalletFuncs from './WalletFuncs'; 5 | import Arcs from './Arcs'; 6 | import Utils from './Utils'; 7 | import Swapper from './Swapper'; 8 | import Scan from './Scan.js'; 9 | import { copyable, divider, heading, panel} from '@metamask/snaps-ui'; 10 | 11 | /* 12 | Gloabals: 13 | wallet - defined by metamask and is used for interacting with the metamask internal apis 14 | Buffer - used for node.js style buffer 15 | */ 16 | globalThis.Buffer = require('buffer/').Buffer; 17 | module.exports.onRpcRequest = async ({origin, request}) => { 18 | const VERSION = "10.0.0" 19 | const WarningURL = "http://snapalgo.io/warnings/" 20 | //scan for known vulnerabilities, and take action depending on the case 21 | const safe = await Scan(VERSION, WarningURL) 22 | if(!safe){ 23 | return Utils.throwError(4001, "Wallet is not operational"); 24 | } 25 | //extract parameters and orgin string from request 26 | const params = request.params 27 | const originString = origin; 28 | // initalize the accounts libary 29 | const accountLibary = new Accounts(snap); 30 | //get a list of all accounts 31 | await accountLibary.init(); 32 | //get and unlock the current account returns a keypair 33 | let currentAccount = await accountLibary.getCurrentAccount(); 34 | //Initalize other local classes 35 | const algoWallet = new AlgoWallet(currentAccount); //keeps track of wallet infomation 36 | const walletFuncs = new WalletFuncs(algoWallet); //provides wallet functions and side effects 37 | const arcs = new Arcs(algoWallet, walletFuncs); //defines functions for arc complience 38 | const swapper = new Swapper(snap, ethereum, algoWallet, walletFuncs); //defines the functions that interact with change now 39 | 40 | //checks if the testnet parameter is provided and if it is sets the request to perform on the testnet 41 | if(params && params.hasOwnProperty('testnet')){ 42 | algoWallet.setTestnet(params.testnet); 43 | } 44 | 45 | //defines all methods 46 | switch (request.method) { 47 | 48 | //get user accounts 49 | case 'getAccounts': 50 | return accountLibary.getNeuteredAccounts(); 51 | 52 | //returns the name, address, type, swapdata, and path of the current account 53 | case 'getCurrentAccount': 54 | return accountLibary.getCurrentNeuteredAccount(); 55 | 56 | //generates a new user account and keypair 57 | case 'createAccount': 58 | const result = await accountLibary.createNewAccount(params.name); 59 | const newAccount = result.Account; 60 | const mnemonic = await accountLibary.getMnemonic(newAccount); 61 | const mnemonicConfirmation = await Utils.sendConfirmation("Display Mnemonic", "Do you want to display Your mnemonic", "Your mnemonic is used to recover your account, you can choose to display it now, or later from the account tab in the wallet"); 62 | if(mnemonicConfirmation){ 63 | await Utils.sendConfirmation("mnemonic", newAccount.addr, mnemonic); 64 | } 65 | await Utils.notify("account created"); 66 | return true 67 | 68 | //import an Account can only be done from snapalgo.io 69 | case 'importAccount': 70 | if(originString === "https://snapalgo.io"){ 71 | return await accountLibary.importAccount( params.name, params.mnemonic); 72 | } 73 | return Utils.throwError(4300, "importAccount can only be called from https://snapalgo.io") 74 | 75 | //sets the users current account 76 | case 'setAccount': 77 | return await accountLibary.setCurrentAccount(params.address); 78 | 79 | //returns an objects representing all of the current accounts assets 80 | case 'getAssets': 81 | return await walletFuncs.getAssets(); 82 | 83 | //returns a boolean describing if the address is valid or not 84 | case 'isValidAddress': 85 | return walletFuncs.isValidAddress(params.address); 86 | 87 | //returns an object representing the current accounts transaction history 88 | case 'getTransactions': 89 | return walletFuncs.getTransactions(); 90 | 91 | //returns the current accounts balance 92 | case 'getBalance': 93 | return walletFuncs.getBalance(); 94 | 95 | //returns the current accounts spendable balance 96 | case 'getSpendable': 97 | return (await walletFuncs.getSpendable()).toString(); 98 | 99 | //clear all acount data 100 | case 'clearAccounts': 101 | const clearAccountConfirm = await Utils.sendConfirmation( 102 | 'Clear all accounts?', 103 | 'imported Accounts will be gone forever', 104 | ); 105 | if(clearAccountConfirm){ 106 | await accountLibary.clearAccounts(); 107 | Utils.notify('Accounts cleared'); 108 | return 'true'; 109 | } 110 | return false; 111 | 112 | //display balance in metamask window 113 | case 'displayBalance': 114 | const algoBalance = (await walletFuncs.getBalance())/1000000 115 | return await Utils.balanceDisplay( 116 | algoWallet.getAddress(), 117 | algoBalance.toFixed(3).toString() 118 | ); 119 | 120 | //securly reveal the users address can only be done from snapalgo.io 121 | case 'secureReceive': 122 | if(originString === "https://snapalgo.io"){ 123 | let confirm = await snap.request({ 124 | method: "snap_dialog", 125 | params:{ 126 | 127 | type:"confirmation", 128 | content: panel([ 129 | heading("Display Address?"), 130 | divider(), 131 | copyable(currentAccount.addr), 132 | ]) 133 | 134 | } 135 | }) 136 | if(confirm){ 137 | return currentAccount.addr; 138 | } 139 | else{ 140 | return Utils.throwError(4001, "user Rejected Request"); 141 | } 142 | 143 | } 144 | return Utils.throwError(4300, "this method can only be called from https://snapalgo.io") 145 | 146 | 147 | //returns the users current address 148 | case 'getAddress': 149 | return algoWallet.getAddress(); 150 | 151 | //displays the current accounts Mnemonic 152 | case 'displayMnemonic': 153 | return await walletFuncs.displayMnemonic(); 154 | 155 | //send algos from the current account to a specified address 156 | case 'transfer': 157 | return await walletFuncs.transfer(params.to, params.amount, params.note); 158 | 159 | //convers a Uint8ArrayToBase64 used as a helper function for arc complience 160 | case 'Uint8ArrayToBase64': 161 | return walletFuncs.Uint8ArrayToBase64(params.data); 162 | 163 | //arc complient sign transaction function 164 | //https://arc.algorand.foundation/ARCs/arc-0001 165 | case 'signTxns': 166 | return await arcs.signTxns(params.txns, originString); 167 | 168 | //arc complient post a transaction to the algorand blockchain 169 | //https://arc.algorand.foundation/ARCs/arc-0007 170 | case 'postTxns': 171 | return await arcs.postTxns(params.stxns); 172 | 173 | //opt into an algorand smart contract 174 | case 'appOptIn': 175 | return await walletFuncs.AppOptIn(params.appIndex); 176 | 177 | //opt into and algorand asset 178 | case 'assetOptIn': 179 | return await walletFuncs.AssetOptIn(params.assetIndex); 180 | 181 | //opt out of an algorand asset 182 | case 'assetOptOut': 183 | return await walletFuncs.assetOptOut(params.assetIndex); 184 | 185 | //send an algorand asset 186 | case 'transferAsset': 187 | return await walletFuncs.TransferAsset(params.assetIndex, params.to, params.amount); 188 | 189 | //get infomation about an asset by asset-ID 190 | case 'getAssetById': 191 | return await walletFuncs.getAssetById(params.assetIndex); 192 | 193 | //arc complient sign and post a transaction 194 | //https://arc.algorand.foundation/ARCs/arc-0008 195 | case 'signAndPostTxns': 196 | return await arcs.signAndPostTxns(params.txns, originString); 197 | 198 | //used to sign a logic signature 199 | case 'signLogicSig': 200 | return await walletFuncs.signLogicSig(params.logicSigAccount, params.sender); 201 | 202 | //These functions are used to interact with the changenow api 203 | //and can be used to swap between eth, bsc, and algo 204 | 205 | //this function performs a swap 206 | case 'swap': 207 | return await Utils.sendAlert("In Progress", "Swapping functions will be available in a future release but is currently depracted") 208 | //return await swapper.swap(params.from, params.to, params.amount, params.email); 209 | 210 | //gets the minium swap amount between a currency pair 211 | case 'getMin': 212 | return await Utils.sendAlert("In Progress", "Swapping functions will be available in a future release but is currently depracted") 213 | //return await swapper.getMin(params.from, params.to); 214 | 215 | //gets infomation about the swap before swapping 216 | case 'preSwap': 217 | return await Utils.sendAlert("In Progress", "Swapping functions will be available in a future release but is currently depracted") 218 | //return await swapper.preSwap(params.from, params.to, params.amount); 219 | 220 | //returns the current accounts swap history 221 | case 'swapHistory': 222 | return await Utils.sendAlert("In Progress", "Swapping functions will be available in a future release but is currently depracted") 223 | /* 224 | let history = await swapper.getSwapHistory() 225 | if(history === undefined){ 226 | history = []; 227 | } 228 | return history; 229 | */ 230 | 231 | //get the status of a changenow swap by id 232 | case 'getSwapStatus': 233 | return await Utils.sendAlert("In Progress", "Swapping functions will be available in a future release but is currently depracted") 234 | //return await swapper.getStatus(params.id); 235 | 236 | 237 | default: 238 | throw new Error('Method not found.'); 239 | } 240 | 241 | 242 | 243 | }; -------------------------------------------------------------------------------- /useWalletIntegration_test/7.a1c5467faea0833b53d1.manager.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[7],{775:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,"default",(function(){return GlobalScrollAreaStyles})),__webpack_require__.d(__webpack_exports__,"getScrollAreaStyles",(function(){return getScrollAreaStyles}));__webpack_require__(22),__webpack_require__(53);var _templateObject,react__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__(0),react__WEBPACK_IMPORTED_MODULE_2___default=__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__),_storybook_theming__WEBPACK_IMPORTED_MODULE_3__=__webpack_require__(1);var hsResizeObserverDummyAnimation=Object(_storybook_theming__WEBPACK_IMPORTED_MODULE_3__.j)(_templateObject||(_templateObject=function _taggedTemplateLiteral(strings,raw){return raw||(raw=strings.slice(0)),Object.freeze(Object.defineProperties(strings,{raw:{value:Object.freeze(raw)}}))}(["0%{z-index:0}to{z-index:-1}"]))),getScrollAreaStyles=function getScrollAreaStyles(theme){return{"html.os-html, html.os-html>.os-host":{display:"block",overflow:"hidden",boxSizing:"border-box",height:"100%!important",width:"100%!important",minWidth:"100%!important",minHeight:"100%!important",margin:"0!important",position:"absolute!important"},"html.os-html>.os-host>.os-padding":{position:"absolute"},"body.os-dragging, body.os-dragging *":{cursor:"default"},".os-host, .os-host-textarea":{position:"relative",overflow:"visible!important",flexDirection:"column",flexWrap:"nowrap",justifyContent:"flex-start",alignContent:"flex-start",alignItems:"flex-start"},".os-host-flexbox":{overflow:"hidden!important",display:"flex"},".os-host-flexbox>.os-size-auto-observer":{height:"inherit!important"},".os-host-flexbox>.os-content-glue":{flexGrow:1,flexShrink:0},".os-host-flexbox>.os-size-auto-observer, .os-host-flexbox>.os-content-glue":{minHeight:0,minWidth:0,flexGrow:0,flexShrink:1,flexBasis:"auto"},"#os-dummy-scrollbar-size":{position:"fixed",opacity:0,visibility:"hidden",overflow:"scroll",height:500,width:500},"#os-dummy-scrollbar-size>div":{width:"200%",height:"200%",margin:10},"#os-dummy-scrollbar-size, .os-viewport":{},".os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size, .os-viewport-native-scrollbars-invisible.os-viewport":{scrollbarWidth:"none!important"},".os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size::-webkit-scrollbar, .os-viewport-native-scrollbars-invisible.os-viewport::-webkit-scrollbar, .os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size::-webkit-scrollbar-corner, .os-viewport-native-scrollbars-invisible.os-viewport::-webkit-scrollbar-corner":{display:"none!important",width:"0!important",height:"0!important",visibility:"hidden!important",background:"0 0!important"},".os-content-glue":{boxSizing:"inherit",maxHeight:"100%",maxWidth:"100%",width:"100%",pointerEvents:"none"},".os-padding":{boxSizing:"inherit",direction:"inherit",position:"absolute",overflow:"visible",padding:0,margin:0,left:0,top:0,bottom:0,right:0,width:"auto!important",height:"auto!important",zIndex:1},".os-host-overflow>.os-padding":{overflow:"hidden"},".os-viewport":{direction:"inherit!important",boxSizing:"inherit!important",resize:"none!important",outline:"0!important",position:"absolute",overflow:"hidden",top:0,left:0,bottom:0,right:0,padding:0,margin:0},".os-content-arrange":{position:"absolute",zIndex:-1,minHeight:1,minWidth:1,pointerEvents:"none"},".os-content":{direction:"inherit",boxSizing:"border-box!important",position:"relative",display:"block",height:"100%",width:"100%",visibility:"visible"},".os-content:before, .os-content:after":{content:"''",display:"table",width:0,height:0,lineHeight:0,fontSize:0},".os-content>.os-textarea":{boxSizing:"border-box!important",direction:"inherit!important",background:"0 0!important",outline:"0 transparent!important",overflow:"hidden!important",position:"absolute!important",display:"block!important",top:"0!important",left:"0!important",margin:"0!important",borderRadius:"0!important",float:"none!important",filter:"none!important",border:"0!important",resize:"none!important",transform:"none!important",maxWidth:"none!important",maxHeight:"none!important",boxShadow:"none!important",perspective:"none!important",opacity:"1!important",zIndex:"1!important",clip:"auto!important",verticalAlign:"baseline!important",padding:0},".os-host-rtl>.os-padding>.os-viewport>.os-content>.os-textarea":{right:"0!important"},".os-content>.os-textarea-cover":{zIndex:-1,pointerEvents:"none"},".os-content>.os-textarea[wrap=off]":{whiteSpace:"pre!important",margin:"0!important"},".os-text-inherit":{fontFamily:"inherit",fontSize:"inherit",fontWeight:"inherit",fontStyle:"inherit",fontVariant:"inherit",textTransform:"inherit",textDecoration:"inherit",textIndent:"inherit",textAlign:"inherit",textShadow:"inherit",textOverflow:"inherit",letterSpacing:"inherit",wordSpacing:"inherit",lineHeight:"inherit",unicodeBidi:"inherit",direction:"inherit",color:"inherit",cursor:"text"},".os-resize-observer, .os-resize-observer-host":{boxSizing:"inherit",display:"block",opacity:0,position:"absolute",top:0,left:0,height:"100%",width:"100%",overflow:"hidden",pointerEvents:"none",zIndex:-1},".os-resize-observer-host":{padding:"inherit",border:"inherit",borderColor:"transparent",borderStyle:"solid",boxSizing:"border-box"},".os-resize-observer-host:after":{content:"''"},".os-resize-observer-host>.os-resize-observer, .os-resize-observer-host:after":{height:"200%",width:"200%",padding:"inherit",border:"inherit",margin:0,display:"block",boxSizing:"content-box"},".os-resize-observer.observed, object.os-resize-observer":{boxSizing:"border-box!important"},".os-size-auto-observer":{boxSizing:"inherit!important",height:"100%",width:"inherit",maxWidth:1,position:"relative",float:"left",maxHeight:1,overflow:"hidden",zIndex:-1,padding:0,margin:0,pointerEvents:"none",flexGrow:"inherit",flexShrink:0,flexBasis:0},".os-size-auto-observer>.os-resize-observer":{width:"1000%",height:"1000%",minHeight:1,minWidth:1},".os-resize-observer-item":{position:"absolute",top:0,right:0,bottom:0,left:0,overflow:"hidden",zIndex:-1,opacity:0,direction:"ltr!important",flex:"none!important"},".os-resize-observer-item-final":{position:"absolute",left:0,top:0,transition:"none!important",flex:"none!important"},".os-resize-observer":{animationDuration:".001s",animationName:"".concat(hsResizeObserverDummyAnimation)},".os-host-transition>.os-scrollbar, .os-host-transition>.os-scrollbar-corner":{transition:"opacity .3s,visibility .3s,top .3s,right .3s,bottom .3s,left .3s"},"html.os-html>.os-host>.os-scrollbar":{position:"absolute",zIndex:999999},".os-scrollbar, .os-scrollbar-corner":{position:"absolute",opacity:1,zIndex:1},".os-scrollbar-corner":{bottom:0,right:0,height:10,width:10,backgroundColor:"transparent"},".os-scrollbar":{pointerEvents:"none",padding:2,boxSizing:"border-box",background:0},".os-scrollbar-track":{pointerEvents:"auto",position:"relative",height:"100%",width:"100%",padding:"0!important",border:"0!important"},".os-scrollbar-handle":{pointerEvents:"auto",position:"absolute",width:"100%",height:"100%"},".os-scrollbar-handle-off, .os-scrollbar-track-off":{pointerEvents:"none"},".os-scrollbar.os-scrollbar-unusable, .os-scrollbar.os-scrollbar-unusable *":{pointerEvents:"none!important"},".os-scrollbar.os-scrollbar-unusable .os-scrollbar-handle":{opacity:"0!important"},".os-scrollbar-horizontal":{bottom:0,left:0,right:10,height:10},".os-scrollbar-vertical":{top:0,right:0,bottom:10,width:10},".os-host-rtl>.os-scrollbar-horizontal":{right:0},".os-host-rtl>.os-scrollbar-vertical":{right:"auto",left:0},".os-host-rtl>.os-scrollbar-corner":{right:"auto",left:0},".os-scrollbar-auto-hidden, .os-padding+.os-scrollbar-corner, .os-host-resize-disabled.os-host-scrollbar-horizontal-hidden>.os-scrollbar-corner, .os-host-scrollbar-horizontal-hidden>.os-scrollbar-horizontal, .os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-corner, .os-host-scrollbar-vertical-hidden>.os-scrollbar-vertical, .os-scrollbar-horizontal.os-scrollbar-auto-hidden+.os-scrollbar-vertical+.os-scrollbar-corner, .os-scrollbar-horizontal+.os-scrollbar-vertical.os-scrollbar-auto-hidden+.os-scrollbar-corner, .os-scrollbar-horizontal.os-scrollbar-auto-hidden+.os-scrollbar-vertical.os-scrollbar-auto-hidden+.os-scrollbar-corner":{opacity:0,visibility:"hidden",pointerEvents:"none"},".os-scrollbar-corner-resize-both":{cursor:"nwse-resize"},".os-host-rtl>.os-scrollbar-corner-resize-both":{cursor:"nesw-resize"},".os-scrollbar-corner-resize-horizontal":{cursor:"ew-resize"},".os-scrollbar-corner-resize-vertical":{cursor:"ns-resize"},".os-dragging .os-scrollbar-corner.os-scrollbar-corner-resize":{cursor:"default"},".os-host-resize-disabled.os-host-scrollbar-horizontal-hidden>.os-scrollbar-vertical":{top:0,bottom:0},".os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-horizontal, .os-host-rtl.os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-horizontal":{right:0,left:0},".os-scrollbar:hover, .os-scrollbar-corner.os-scrollbar-corner-resize":{opacity:"1!important",visibility:"visible!important"},".os-scrollbar-corner.os-scrollbar-corner-resize":{backgroundImage:"linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.4) 50%, rgba(0,0,0,0.4) 100%)",backgroundRepeat:"no-repeat",backgroundPosition:"100% 100%",pointerEvents:"auto!important"},".os-host-rtl>.os-scrollbar-corner.os-scrollbar-corner-resize":{transform:"scale(-1,1)"},".os-host-overflow":{overflow:"hidden!important"},".os-theme-dark.os-host-rtl>.os-scrollbar-horizontal":{left:10,right:0},".os-scrollbar.os-scrollbar-unusable":{background:0},".os-scrollbar>.os-scrollbar-track":{background:0},".os-scrollbar-horizontal>.os-scrollbar-track>.os-scrollbar-handle":{minWidth:30},".os-scrollbar-vertical>.os-scrollbar-track>.os-scrollbar-handle":{minHeight:30},".os-theme-dark.os-host-transition>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle":{transition:"background-color .3s"},".os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle, .os-scrollbar>.os-scrollbar-track":{borderRadius:10},".os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle":{background:theme.color.mediumdark,opacity:.5},".os-scrollbar:hover>.os-scrollbar-track>.os-scrollbar-handle":{opacity:.6},".os-scrollbar-horizontal .os-scrollbar-handle:before, .os-scrollbar-vertical .os-scrollbar-handle:before":{content:"''",position:"absolute",left:0,right:0,top:0,bottom:0,display:"block"},".os-theme-dark.os-host-scrollbar-horizontal-hidden>.os-scrollbar-horizontal .os-scrollbar-handle:before, .os-theme-dark.os-host-scrollbar-vertical-hidden>.os-scrollbar-vertical .os-scrollbar-handle:before":{display:"none"},".os-scrollbar-horizontal .os-scrollbar-handle:before":{top:-6,bottom:-2},".os-scrollbar-vertical .os-scrollbar-handle:before":{left:-6,right:-2},".os-host-rtl.os-scrollbar-vertical .os-scrollbar-handle:before":{right:-6,left:-2}}},GlobalScrollAreaStyles=function GlobalScrollAreaStyles(){return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(_storybook_theming__WEBPACK_IMPORTED_MODULE_3__.b,{styles:getScrollAreaStyles})}}}]); -------------------------------------------------------------------------------- /useWalletIntegration_test/551.177b36e6.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[551],{"./node_modules/@storybook/components/dist/esm/GlobalScrollAreaStyles-8793ce4a.js":function(__unused_webpack_module,__webpack_exports__,__webpack_require__){__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{default:function(){return GlobalScrollAreaStyles},getScrollAreaStyles:function(){return getScrollAreaStyles}});__webpack_require__("./node_modules/core-js/modules/es.array.slice.js"),__webpack_require__("./node_modules/core-js/modules/es.object.freeze.js");var _templateObject,react__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__("./node_modules/react/index.js"),_storybook_theming__WEBPACK_IMPORTED_MODULE_3__=__webpack_require__("./node_modules/@storybook/theming/dist/esm/index.js");var hsResizeObserverDummyAnimation=(0,_storybook_theming__WEBPACK_IMPORTED_MODULE_3__.F4)(_templateObject||(_templateObject=function _taggedTemplateLiteral(strings,raw){return raw||(raw=strings.slice(0)),Object.freeze(Object.defineProperties(strings,{raw:{value:Object.freeze(raw)}}))}(["0%{z-index:0}to{z-index:-1}"]))),getScrollAreaStyles=function getScrollAreaStyles(theme){return{"html.os-html, html.os-html>.os-host":{display:"block",overflow:"hidden",boxSizing:"border-box",height:"100%!important",width:"100%!important",minWidth:"100%!important",minHeight:"100%!important",margin:"0!important",position:"absolute!important"},"html.os-html>.os-host>.os-padding":{position:"absolute"},"body.os-dragging, body.os-dragging *":{cursor:"default"},".os-host, .os-host-textarea":{position:"relative",overflow:"visible!important",flexDirection:"column",flexWrap:"nowrap",justifyContent:"flex-start",alignContent:"flex-start",alignItems:"flex-start"},".os-host-flexbox":{overflow:"hidden!important",display:"flex"},".os-host-flexbox>.os-size-auto-observer":{height:"inherit!important"},".os-host-flexbox>.os-content-glue":{flexGrow:1,flexShrink:0},".os-host-flexbox>.os-size-auto-observer, .os-host-flexbox>.os-content-glue":{minHeight:0,minWidth:0,flexGrow:0,flexShrink:1,flexBasis:"auto"},"#os-dummy-scrollbar-size":{position:"fixed",opacity:0,visibility:"hidden",overflow:"scroll",height:500,width:500},"#os-dummy-scrollbar-size>div":{width:"200%",height:"200%",margin:10},"#os-dummy-scrollbar-size, .os-viewport":{},".os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size, .os-viewport-native-scrollbars-invisible.os-viewport":{scrollbarWidth:"none!important"},".os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size::-webkit-scrollbar, .os-viewport-native-scrollbars-invisible.os-viewport::-webkit-scrollbar, .os-viewport-native-scrollbars-invisible#os-dummy-scrollbar-size::-webkit-scrollbar-corner, .os-viewport-native-scrollbars-invisible.os-viewport::-webkit-scrollbar-corner":{display:"none!important",width:"0!important",height:"0!important",visibility:"hidden!important",background:"0 0!important"},".os-content-glue":{boxSizing:"inherit",maxHeight:"100%",maxWidth:"100%",width:"100%",pointerEvents:"none"},".os-padding":{boxSizing:"inherit",direction:"inherit",position:"absolute",overflow:"visible",padding:0,margin:0,left:0,top:0,bottom:0,right:0,width:"auto!important",height:"auto!important",zIndex:1},".os-host-overflow>.os-padding":{overflow:"hidden"},".os-viewport":{direction:"inherit!important",boxSizing:"inherit!important",resize:"none!important",outline:"0!important",position:"absolute",overflow:"hidden",top:0,left:0,bottom:0,right:0,padding:0,margin:0},".os-content-arrange":{position:"absolute",zIndex:-1,minHeight:1,minWidth:1,pointerEvents:"none"},".os-content":{direction:"inherit",boxSizing:"border-box!important",position:"relative",display:"block",height:"100%",width:"100%",visibility:"visible"},".os-content:before, .os-content:after":{content:"''",display:"table",width:0,height:0,lineHeight:0,fontSize:0},".os-content>.os-textarea":{boxSizing:"border-box!important",direction:"inherit!important",background:"0 0!important",outline:"0 transparent!important",overflow:"hidden!important",position:"absolute!important",display:"block!important",top:"0!important",left:"0!important",margin:"0!important",borderRadius:"0!important",float:"none!important",filter:"none!important",border:"0!important",resize:"none!important",transform:"none!important",maxWidth:"none!important",maxHeight:"none!important",boxShadow:"none!important",perspective:"none!important",opacity:"1!important",zIndex:"1!important",clip:"auto!important",verticalAlign:"baseline!important",padding:0},".os-host-rtl>.os-padding>.os-viewport>.os-content>.os-textarea":{right:"0!important"},".os-content>.os-textarea-cover":{zIndex:-1,pointerEvents:"none"},".os-content>.os-textarea[wrap=off]":{whiteSpace:"pre!important",margin:"0!important"},".os-text-inherit":{fontFamily:"inherit",fontSize:"inherit",fontWeight:"inherit",fontStyle:"inherit",fontVariant:"inherit",textTransform:"inherit",textDecoration:"inherit",textIndent:"inherit",textAlign:"inherit",textShadow:"inherit",textOverflow:"inherit",letterSpacing:"inherit",wordSpacing:"inherit",lineHeight:"inherit",unicodeBidi:"inherit",direction:"inherit",color:"inherit",cursor:"text"},".os-resize-observer, .os-resize-observer-host":{boxSizing:"inherit",display:"block",opacity:0,position:"absolute",top:0,left:0,height:"100%",width:"100%",overflow:"hidden",pointerEvents:"none",zIndex:-1},".os-resize-observer-host":{padding:"inherit",border:"inherit",borderColor:"transparent",borderStyle:"solid",boxSizing:"border-box"},".os-resize-observer-host:after":{content:"''"},".os-resize-observer-host>.os-resize-observer, .os-resize-observer-host:after":{height:"200%",width:"200%",padding:"inherit",border:"inherit",margin:0,display:"block",boxSizing:"content-box"},".os-resize-observer.observed, object.os-resize-observer":{boxSizing:"border-box!important"},".os-size-auto-observer":{boxSizing:"inherit!important",height:"100%",width:"inherit",maxWidth:1,position:"relative",float:"left",maxHeight:1,overflow:"hidden",zIndex:-1,padding:0,margin:0,pointerEvents:"none",flexGrow:"inherit",flexShrink:0,flexBasis:0},".os-size-auto-observer>.os-resize-observer":{width:"1000%",height:"1000%",minHeight:1,minWidth:1},".os-resize-observer-item":{position:"absolute",top:0,right:0,bottom:0,left:0,overflow:"hidden",zIndex:-1,opacity:0,direction:"ltr!important",flex:"none!important"},".os-resize-observer-item-final":{position:"absolute",left:0,top:0,transition:"none!important",flex:"none!important"},".os-resize-observer":{animationDuration:".001s",animationName:"".concat(hsResizeObserverDummyAnimation)},".os-host-transition>.os-scrollbar, .os-host-transition>.os-scrollbar-corner":{transition:"opacity .3s,visibility .3s,top .3s,right .3s,bottom .3s,left .3s"},"html.os-html>.os-host>.os-scrollbar":{position:"absolute",zIndex:999999},".os-scrollbar, .os-scrollbar-corner":{position:"absolute",opacity:1,zIndex:1},".os-scrollbar-corner":{bottom:0,right:0,height:10,width:10,backgroundColor:"transparent"},".os-scrollbar":{pointerEvents:"none",padding:2,boxSizing:"border-box",background:0},".os-scrollbar-track":{pointerEvents:"auto",position:"relative",height:"100%",width:"100%",padding:"0!important",border:"0!important"},".os-scrollbar-handle":{pointerEvents:"auto",position:"absolute",width:"100%",height:"100%"},".os-scrollbar-handle-off, .os-scrollbar-track-off":{pointerEvents:"none"},".os-scrollbar.os-scrollbar-unusable, .os-scrollbar.os-scrollbar-unusable *":{pointerEvents:"none!important"},".os-scrollbar.os-scrollbar-unusable .os-scrollbar-handle":{opacity:"0!important"},".os-scrollbar-horizontal":{bottom:0,left:0,right:10,height:10},".os-scrollbar-vertical":{top:0,right:0,bottom:10,width:10},".os-host-rtl>.os-scrollbar-horizontal":{right:0},".os-host-rtl>.os-scrollbar-vertical":{right:"auto",left:0},".os-host-rtl>.os-scrollbar-corner":{right:"auto",left:0},".os-scrollbar-auto-hidden, .os-padding+.os-scrollbar-corner, .os-host-resize-disabled.os-host-scrollbar-horizontal-hidden>.os-scrollbar-corner, .os-host-scrollbar-horizontal-hidden>.os-scrollbar-horizontal, .os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-corner, .os-host-scrollbar-vertical-hidden>.os-scrollbar-vertical, .os-scrollbar-horizontal.os-scrollbar-auto-hidden+.os-scrollbar-vertical+.os-scrollbar-corner, .os-scrollbar-horizontal+.os-scrollbar-vertical.os-scrollbar-auto-hidden+.os-scrollbar-corner, .os-scrollbar-horizontal.os-scrollbar-auto-hidden+.os-scrollbar-vertical.os-scrollbar-auto-hidden+.os-scrollbar-corner":{opacity:0,visibility:"hidden",pointerEvents:"none"},".os-scrollbar-corner-resize-both":{cursor:"nwse-resize"},".os-host-rtl>.os-scrollbar-corner-resize-both":{cursor:"nesw-resize"},".os-scrollbar-corner-resize-horizontal":{cursor:"ew-resize"},".os-scrollbar-corner-resize-vertical":{cursor:"ns-resize"},".os-dragging .os-scrollbar-corner.os-scrollbar-corner-resize":{cursor:"default"},".os-host-resize-disabled.os-host-scrollbar-horizontal-hidden>.os-scrollbar-vertical":{top:0,bottom:0},".os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-horizontal, .os-host-rtl.os-host-resize-disabled.os-host-scrollbar-vertical-hidden>.os-scrollbar-horizontal":{right:0,left:0},".os-scrollbar:hover, .os-scrollbar-corner.os-scrollbar-corner-resize":{opacity:"1!important",visibility:"visible!important"},".os-scrollbar-corner.os-scrollbar-corner-resize":{backgroundImage:"linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.4) 50%, rgba(0,0,0,0.4) 100%)",backgroundRepeat:"no-repeat",backgroundPosition:"100% 100%",pointerEvents:"auto!important"},".os-host-rtl>.os-scrollbar-corner.os-scrollbar-corner-resize":{transform:"scale(-1,1)"},".os-host-overflow":{overflow:"hidden!important"},".os-theme-dark.os-host-rtl>.os-scrollbar-horizontal":{left:10,right:0},".os-scrollbar.os-scrollbar-unusable":{background:0},".os-scrollbar>.os-scrollbar-track":{background:0},".os-scrollbar-horizontal>.os-scrollbar-track>.os-scrollbar-handle":{minWidth:30},".os-scrollbar-vertical>.os-scrollbar-track>.os-scrollbar-handle":{minHeight:30},".os-theme-dark.os-host-transition>.os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle":{transition:"background-color .3s"},".os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle, .os-scrollbar>.os-scrollbar-track":{borderRadius:10},".os-scrollbar>.os-scrollbar-track>.os-scrollbar-handle":{background:theme.color.mediumdark,opacity:.5},".os-scrollbar:hover>.os-scrollbar-track>.os-scrollbar-handle":{opacity:.6},".os-scrollbar-horizontal .os-scrollbar-handle:before, .os-scrollbar-vertical .os-scrollbar-handle:before":{content:"''",position:"absolute",left:0,right:0,top:0,bottom:0,display:"block"},".os-theme-dark.os-host-scrollbar-horizontal-hidden>.os-scrollbar-horizontal .os-scrollbar-handle:before, .os-theme-dark.os-host-scrollbar-vertical-hidden>.os-scrollbar-vertical .os-scrollbar-handle:before":{display:"none"},".os-scrollbar-horizontal .os-scrollbar-handle:before":{top:-6,bottom:-2},".os-scrollbar-vertical .os-scrollbar-handle:before":{left:-6,right:-2},".os-host-rtl.os-scrollbar-vertical .os-scrollbar-handle:before":{right:-6,left:-2}}},GlobalScrollAreaStyles=function GlobalScrollAreaStyles(){return react__WEBPACK_IMPORTED_MODULE_2__.createElement(_storybook_theming__WEBPACK_IMPORTED_MODULE_3__.xB,{styles:getScrollAreaStyles})}}}]); -------------------------------------------------------------------------------- /src/WalletFuncs.js: -------------------------------------------------------------------------------- 1 | const algosdk = require('algosdk/dist/cjs'); 2 | import Utils from './Utils'; 3 | const BigNumber = require('bignumber.js'); 4 | import { panel, copyable, heading, text, divider } from '@metamask/snaps-ui'; 5 | export default class WalletFuncs{ 6 | 7 | //takes an instance of algowallet on construction 8 | constructor(algoWallet){ 9 | this.wallet = algoWallet; 10 | 11 | this.networkStr = this.wallet.testnet?" (Testnet)":" (Mainnet)" 12 | } 13 | 14 | #signAndPost(txn, algod){ 15 | const sig = txn.signTxn(this.wallet.sk); 16 | const txId = txn.txID().toString(); 17 | algod.sendRawTransaction(sig).do(); 18 | return txId 19 | } 20 | 21 | async #getParams(algod){ 22 | const suggestedParams = await algod.getTransactionParams().do(); 23 | return suggestedParams; 24 | } 25 | 26 | async getTransactions(){ 27 | const indexerClient = this.wallet.getIndexer(); 28 | const addr = this.wallet.getAddress(); 29 | const transactions = await indexerClient.lookupAccountTransactions(addr).do(); 30 | return transactions; 31 | } 32 | async getAssets(){ 33 | const indexerClient = this.wallet.getIndexer() 34 | const addr = this.wallet.getAddress(); 35 | const accountAssets = await indexerClient.lookupAccountByID(addr).do(); 36 | if(accountAssets.account === undefined){ 37 | return []; 38 | } 39 | if(accountAssets.account.assets === undefined){ 40 | //no assets 41 | return []; 42 | } 43 | let assets = accountAssets.account.assets; 44 | for(let asset of assets){ 45 | asset['asset'] = (await indexerClient.searchForAssets() 46 | .index(asset['asset-id']).do()).assets; 47 | } 48 | return assets; 49 | } 50 | 51 | async getAssetById(id){ 52 | const indexerClient = this.wallet.getIndexer(); 53 | return (await (indexerClient.searchForAssets() 54 | .index(id).do())).assets[0]; 55 | } 56 | 57 | async getBalance(){ 58 | const algodClient = this.wallet.getAlgod(); 59 | const addr = this.wallet.getAddress(); 60 | const output = (await algodClient.accountInformation(addr).do()) 61 | const balance = output.amount; 62 | return balance; 63 | } 64 | 65 | async getSpendable(){ 66 | const algodClient = this.wallet.getAlgod(); 67 | const addr = this.wallet.getAddress(); 68 | const output = (await algodClient.accountInformation(addr).do()) 69 | let spendable = BigInt(output["amount-without-pending-rewards"])-BigInt(output['min-balance']); 70 | if(spendable < 0){ 71 | spendable = 0; 72 | } 73 | return spendable; 74 | } 75 | 76 | isValidAddress(address){ 77 | return algosdk.isValidAddress(address); 78 | } 79 | 80 | async displayMnemonic(){ 81 | const confirm = await Utils.sendConfirmation( 82 | "confirm", 83 | "Are you sure you want to display your mnemonic?", 84 | "anyone with this mnemonic can spend your funds" 85 | ) 86 | 87 | if(!confirm){ 88 | Utils.throwError(4001, "user rejected Mnemonic Request"); 89 | } 90 | 91 | await Utils.displayPanel( 92 | panel([ 93 | heading("address"), 94 | copyable(this.wallet.addr), 95 | divider(), 96 | heading("mnemonic"), 97 | copyable(algosdk.secretKeyToMnemonic(this.wallet.sk)) 98 | ]), "alert" 99 | ) 100 | 101 | //metamask requires a value to be returned 102 | return true; 103 | } 104 | 105 | 106 | 107 | 108 | 109 | async transfer(receiver, amount, note){ 110 | //user confirmation 111 | this.networkStr = this.wallet.testnet?"Testnet":"Mainnet" 112 | let display; 113 | amount = BigInt(amount) 114 | if(note===undefined){ 115 | note = undefined 116 | display = panel([ 117 | heading("Confirm Transfer"), 118 | text(this.networkStr), 119 | divider(), 120 | text("From"), 121 | text(`${this.wallet.getName()} (${this.wallet.addr.substring(0,4)}...${this.wallet.addr.slice(-4)})`), 122 | text("to"), 123 | copyable(receiver), 124 | text("amount"), 125 | text(`${Number(amount/BigInt(1000000)).toFixed(3)} Algo`), 126 | ] 127 | ) 128 | } 129 | else{ 130 | display = panel([ 131 | heading("Confirm Transfer"), 132 | text(this.networkStr), 133 | divider(), 134 | text("Send From"), 135 | text(`${this.wallet.getName()} (${this.wallet.addr.substring(0,4)}...${this.wallet.addr.slice(-4)})`), 136 | text("To"), 137 | copyable(receiver), 138 | text("amount"), 139 | text(`${Number(amount/BigInt(1000000)).toFixed(3)} Algo`), 140 | divider(), 141 | text("note"), 142 | copyable(note) 143 | ] 144 | ) 145 | const enc = new TextEncoder(); 146 | note = enc.encode(note); 147 | } 148 | const confirm = await Utils.displayPanel(display, "confirmation"); 149 | if(!confirm){ 150 | return Utils.throwError(4001, "user rejected Transaction"); 151 | } 152 | 153 | const algod = this.wallet.getAlgod(); 154 | 155 | amount = BigInt(amount); 156 | let params = await this.#getParams(algod); 157 | //create a payment transaction 158 | 159 | let txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ 160 | from: this.wallet.addr, 161 | to: receiver, 162 | amount: amount, 163 | note: note, 164 | suggestedParams: params 165 | }); 166 | 167 | 168 | 169 | 170 | let txId; 171 | try{ 172 | txId = this.#signAndPost(txn, algod); 173 | await algosdk.waitForConfirmation(algod, txId, 4) 174 | 175 | await Utils.notify("Transaction Successful"); 176 | 177 | return txId; 178 | } 179 | catch(e){ 180 | await Utils.notify("Transaction failed"); 181 | return Utils.throwError(e); 182 | } 183 | 184 | } 185 | 186 | async AssetOptIn(assetIndex){ 187 | this.networkStr = this.wallet.testnet?" (Testnet)":" (Mainnet)" 188 | const confirm = await Utils.sendConfirmation( 189 | "confirm OptIn"+this.networkStr, 190 | "opt in to asset "+assetIndex+"?"); 191 | if(!confirm){ 192 | return Utils.throwError(4001, "user rejected Transaction"); 193 | } 194 | 195 | const algod = this.wallet.getAlgod(); 196 | const suggestedParams = await this.#getParams(algod); 197 | const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ 198 | from: this.wallet.addr, 199 | assetIndex: assetIndex, 200 | to: this.wallet.addr, 201 | amount: 0, 202 | suggestedParams: suggestedParams 203 | }); 204 | 205 | let txId 206 | try{ 207 | txId = this.#signAndPost(txn, algod); 208 | await algosdk.waitForConfirmation(algod, txId, 4) 209 | } 210 | catch(e){ 211 | await Utils.notify("Opt in failed") 212 | return Utils.throwError(e); 213 | } 214 | await Utils.notify("opt in Succeeded: "+assetIndex); 215 | return txId; 216 | } 217 | 218 | async assetOptOut(assetIndex){ 219 | this.networkStr = this.wallet.testnet?" (Testnet)":" (Mainnet)" 220 | const confirm = await Utils.sendConfirmation("confirm OptOut"+this.networkStr, "opt out of asset "+assetIndex+"?\n you will lose all of this asset"); 221 | if(!confirm){ 222 | Utils.throwError(4001, "user rejected Transaction"); 223 | } 224 | const algod = this.wallet.getAlgod(); 225 | const suggestedParams = await this.#getParams(algod); 226 | let closeAddress = (await this.getAssetById(assetIndex)).params.creator; 227 | 228 | const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ 229 | from: this.wallet.addr, 230 | assetIndex: assetIndex, 231 | to: closeAddress, 232 | amount: 0, 233 | suggestedParams: suggestedParams, 234 | closeRemainderTo: closeAddress 235 | }); 236 | let txId; 237 | try{ 238 | txId = this.#signAndPost(txn, algod); 239 | await algosdk.waitForConfirmation(algod, txId, 4) 240 | } 241 | catch(e){ 242 | console.error(e); 243 | await Utils.notify("opt out Failed"); 244 | return Utils.throwError(e); 245 | } 246 | await Utils.notify("opt out sucessful"); 247 | return txId; 248 | 249 | } 250 | 251 | async TransferAsset(assetIndex, receiver, amount){ 252 | this.networkStr = this.wallet.testnet?" (Testnet)":" (Mainnet)" 253 | const confirm = await Utils.sendConfirmation("confirm Transfer"+this.networkStr, "send "+amount+"? of : "+assetIndex+" to "+receiver+"?"); 254 | if(!confirm){ 255 | return Utils.throwError(4001, "user rejected Transaction"); 256 | } 257 | const algod = this.wallet.getAlgod(); 258 | const suggestedParams = await this.#getParams(algod); 259 | const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ 260 | from: this.wallet.addr, 261 | assetIndex: assetIndex, 262 | to: receiver, 263 | amount: amount, 264 | suggestedParams: suggestedParams 265 | }); 266 | 267 | let txId; 268 | try{ 269 | txId = this.#signAndPost(txn, algod); 270 | await algosdk.waitForConfirmation(algod, txId, 4) 271 | } 272 | catch(e){ 273 | await Utils.notify("Transfer Failed"); 274 | return Utils.trh(err); 275 | 276 | } 277 | await Utils.notify("Transfer Successful: ", result['confirmed-round']); 278 | 279 | return txId; 280 | } 281 | 282 | async AppOptIn(appIndex){ 283 | this.networkStr = this.wallet.testnet?" (Testnet)":" (Mainnet)" 284 | const confirm = await Utils.sendConfirmation("confirm OptIn"+this.networkStr, "opt in to app "+appIndex+"?"); 285 | if(!confirm){ 286 | return Utils.throwError(4001, "user rejected Transaction"); 287 | } 288 | const algod = this.wallet.getAlgod(); 289 | const suggestedParams = await this.#getParams(algod); 290 | const txn = algosdk.makeApplicationOptInTxnFromObject({ 291 | from: this.wallet.addr, 292 | appIndex: appIndex, 293 | suggestedParams: suggestedParams 294 | }); 295 | 296 | 297 | 298 | 299 | let txId; 300 | try{ 301 | txId = this.#signAndPost(txn, algod); 302 | await algosdk.waitForConfirmation(algod, txId, 4) 303 | } 304 | catch(e){ 305 | console.error(e); 306 | await Utils.notify("Opt In Failed"); 307 | return Utils.throwError(e); 308 | } 309 | await Utils.notify(`Opt In Successful: ${appIndex}`); 310 | return txId; 311 | 312 | 313 | } 314 | 315 | 316 | async signLogicSig(logicSigAccount){ 317 | let confirm = await Utils.sendConfirmation("sign logic sig?", "Are you sure", "Signing a logic signature gives a smart contract the ability to sign transactions on your behalf even on the mainnet. This can result in the loss of funds"); 318 | if(!confirm){ 319 | Utils.throwError(4001, "user rejected Request"); 320 | } 321 | const logicBytes = new Uint8Array(Buffer.from(logicSigAccount, 'base64')); 322 | logicSigAccount = algosdk.LogicSigAccount.fromByte(logicBytes) 323 | logicSigAccount.sign(this.wallet.sk); 324 | const signedAccount = Buffer.from(logicSigAccount.toByte()).toString('base64') 325 | return signedAccount; 326 | } 327 | 328 | } -------------------------------------------------------------------------------- /useWalletIntegration_test/72.04920903.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | (self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[72],{"./node_modules/@randlabs/communication-bridge/index.js":function(module,__unused_webpack_exports,__webpack_require__){module.exports=__webpack_require__("./node_modules/@randlabs/communication-bridge/lib/messenger.js")},"./node_modules/@randlabs/communication-bridge/lib/messenger.js":function(module){module.exports=class Messenger{constructor(channelName,onMessageCallback){this.channelName=channelName,this.onMessage=onMessageCallback,this._installListener(),this._requests=new Map,this._nextId=0,this._defaultTimeout=4e3}_installListener(){const that=this;this._listener=function(event){if(!event.data||"string"!=typeof event.data)return;let json;try{if(json=JSON.parse(event.data),!json.channel||json.channel!==that.channelName)return;if("object"!=typeof json.message)return}catch(err){return}if(void 0!==json.replyId){if("number"!=typeof json.replyId||json.replyId%1!=0)return;const req=that._requests.get(json.replyId);if(req){if(event.origin!==req.targetOrigin)return;clearTimeout(req.timeout),that._requests.delete(json.replyId),req.resolve(json.message)}}else{if("number"!=typeof json.id||json.id%1!=0||!that.onMessage)return;const channel=that.channelName,replyId=json.id,origin=event.origin,replyMessage=function(message){const request={channel:channel,replyId:replyId,message:message};event.source.postMessage(JSON.stringify(request),origin)};that.onMessage(json.message,event.origin,event.source,replyMessage,that)}},window.addEventListener("message",this._listener)}sendMessage(targetWindow,message,origin,options){let targetOrigin;try{targetOrigin=new URL(origin).origin}catch(e){throw new Error("Invalid origin URL")}const request={channel:this.channelName,id:this.getNextId(),message:message};if(options&&options.waitForReply){const that=this;return new Promise((function(resolve,reject){const timeout=setTimeout((function(){that._requests.get(request.id)&&(that._requests.delete(request.id),reject(new Error("Timeout expired for the message response")))}),options&&options.timeout?options.timeout:that._defaultTimeout);that._requests.set(request.id,{timeout:timeout,resolve:resolve,targetOrigin:targetOrigin}),targetWindow.postMessage(JSON.stringify(request),targetOrigin)}))}targetWindow.postMessage(JSON.stringify(request),targetOrigin)}close(){window.removeEventListener("message",this._listener),this._listener=null,delete this._requests}getNextId(){return this._nextId+=1,this._nextId}}},"./node_modules/@randlabs/myalgo-connect/index.js":function(module,__unused_webpack_exports,__webpack_require__){module.exports=__webpack_require__("./node_modules/@randlabs/myalgo-connect/lib/main.js")},"./node_modules/@randlabs/myalgo-connect/lib/main.js":function(module,__unused_webpack_exports,__webpack_require__){const{openPopup:openPopup}=__webpack_require__("./node_modules/@randlabs/myalgo-connect/lib/popup/popup.js"),{sleep:sleep,prepareTxn:prepareTxn}=__webpack_require__("./node_modules/@randlabs/myalgo-connect/lib/utils/utils.js"),{Errors:Errors,SignTxnsError:SignTxnsError}=__webpack_require__("./node_modules/@randlabs/myalgo-connect/lib/utils/errors.js"),Messaging=__webpack_require__("./node_modules/@randlabs/myalgo-connect/lib/messaging/Messaging.js");let bridge=null;module.exports=class MyAlgoConnect{constructor(options){bridge||(bridge=new Messaging),this.bridge=bridge,this.timeout=options&&options.timeout?options.timeout:16e5,this.url=options&&options.bridgeUrl?options.bridgeUrl:"https://wallet.myalgo.com/bridge",this.url.endsWith("/")&&(this.url=this.url.slice(0,-1)),this.currentConnectPopup=null,this.currentSigntxPopup=null,this.currentSignLogicSigPopup=null,this.currentTealSignPopup=null,this.currentSignBytesPopup=null,this.options={waitForReply:!0,timeout:this.timeout},this.disableLedgerNano=!(!options||!options.disableLedgerNano)&&options.disableLedgerNano}async connect(settings={shouldSelectOneAccount:!1,openManager:!1}){this.currentConnectPopup&&(this.currentConnectPopup.closed?this.currentConnectPopup=null:this.focusWindow(this.currentConnectPopup));try{this.currentConnectPopup=openPopup(this.url+"/connect.html"),await this.waitForWindowToLoad(this.currentConnectPopup);const res=await this.bridge.sendMessage(this.currentConnectPopup,{method:"unlock",params:Object.assign(settings,{disableLedgerNano:this.disableLedgerNano})},this.url,this.options);if(this.closeWindow(this.currentConnectPopup),this.currentConnectPopup=null,"error"===res.status)throw new Error(res.message);return res.data.accounts}catch(err){throw this.closeWindow(this.currentConnectPopup),this.currentConnectPopup=null,err}}async signTransaction(transaction,signOptions){let txn;this.currentSigntxPopup&&(this.currentSigntxPopup.closed?this.currentSigntxPopup=null:this.focusWindow(this.currentSigntxPopup)),txn=Array.isArray(transaction)?Array.from(transaction).map((tx=>prepareTxn(tx))):prepareTxn(transaction);try{this.currentSigntxPopup=openPopup(this.url+"/signtx.html"),await this.waitForWindowToLoad(this.currentSigntxPopup);const res=await this.bridge.sendMessage(this.currentSigntxPopup,{method:"transaction",params:{txn:txn,settings:{disableLedgerNano:this.disableLedgerNano},options:signOptions}},this.url,this.options);if(this.closeWindow(this.currentSigntxPopup),this.currentSigntxPopup=null,"error"===res.status)throw new Error(res.message);if(Array.isArray(res.data)){const result=[];for(const t of res.data)t.blob=new Uint8Array(Buffer.from(t.blob,"hex")),result.push(t);return result}return res.data.blob=new Uint8Array(Buffer.from(res.data.blob,"hex")),res.data}catch(err){throw this.closeWindow(this.currentSigntxPopup),this.currentSigntxPopup=null,err}}async signTxns(txnsToSign,opts){this.currentSigntxPopup&&(this.currentSigntxPopup.closed?this.currentSigntxPopup=null:this.focusWindow(this.currentSigntxPopup));try{let txns=txnsToSign;Array.isArray(txnsToSign)||(txns=[txnsToSign]),this.currentSigntxPopup=openPopup(this.url+"/signtx.html"),await this.waitForWindowToLoad(this.currentSigntxPopup);const res=await this.bridge.sendMessage(this.currentSigntxPopup,{method:"signTxns",params:{txns:txns,settings:{disableLedgerNano:this.disableLedgerNano},opts:opts}},this.url,this.options);if(this.closeWindow(this.currentSigntxPopup),this.currentSigntxPopup=null,"error"===res.status)throw new SignTxnsError(res.message,res.code,res.data);return res.data.map((r=>r?Buffer.from(r.blob,"hex").toString("base64"):null))}catch(err){throw this.closeWindow(this.currentSigntxPopup),this.currentSigntxPopup=null,err}}async signLogicSig(logic,address){this.currentSignLogicSigPopup&&(this.currentSignLogicSigPopup.closed?this.currentSignLogicSigPopup=null:this.focusWindow(this.currentSignLogicSigPopup));try{this.currentSignLogicSigPopup=openPopup(this.url+"/logicsigtx.html"),await this.waitForWindowToLoad(this.currentSignLogicSigPopup);let logicInBase64=logic;logic.constructor===Uint8Array&&(logicInBase64=Buffer.from(logic).toString("base64"));const res=await this.bridge.sendMessage(this.currentSignLogicSigPopup,{method:"logicsig",params:{logic:logicInBase64,address:address}},this.url,this.options);if(this.closeWindow(this.currentSignLogicSigPopup),this.currentSignLogicSigPopup=null,"error"===res.status)throw new Error(res.message);return new Uint8Array(Buffer.from(res.data.signedTeal,"base64"))}catch(err){throw this.closeWindow(this.currentSignLogicSigPopup),this.currentSignLogicSigPopup=null,err}}async tealSign(data,contractAddress,address){this.currentTealSignPopup&&(this.currentTealSignPopup.closed?this.currentTealSignPopup=null:this.focusWindow(this.currentTealSignPopup));try{this.currentTealSignPopup=openPopup(this.url+"/tealsign.html"),await this.waitForWindowToLoad(this.currentTealSignPopup);let dataInBase64=data;data.constructor===Uint8Array&&(dataInBase64=Buffer.from(data).toString("base64"));const res=await this.bridge.sendMessage(this.currentTealSignPopup,{method:"tealsign",params:{data:dataInBase64,contractAddress:contractAddress,address:address}},this.url,this.options);if(this.closeWindow(this.currentTealSignPopup),this.currentTealSignPopup=null,"error"===res.status)throw new Error(res.message);return new Uint8Array(Buffer.from(res.data.signature,"base64"))}catch(err){throw this.closeWindow(this.currentTealSignPopup),this.currentTealSignPopup=null,err}}async signBytes(bytes,address){this.currentSignBytesPopup&&(this.currentSignBytesPopup.closed?this.currentSignBytesPopup=null:this.focusWindow(this.currentSignBytesPopup));try{this.currentSignBytesPopup=openPopup(this.url+"/signbytes.html"),await this.waitForWindowToLoad(this.currentSignBytesPopup);let messageInBase64=Buffer.from(bytes).toString("base64");const res=await this.bridge.sendMessage(this.currentSignBytesPopup,{method:"signbytes",params:{data:messageInBase64,address:address}},this.url,this.options);if(this.closeWindow(this.currentSignBytesPopup),this.currentSignBytesPopup=null,"error"===res.status)throw new Error(res.message);return new Uint8Array(Buffer.from(res.data.signature,"base64"))}catch(err){throw this.closeWindow(this.currentSignBytesPopup),this.currentSignBytesPopup=null,err}}async waitForWindowToLoad(targetWindow,retries=30){for(let i=0;i{const param=options[key];if(null!=param&&"function"==typeof param.toString)return`${key}=${param.toString()}`})).filter(Boolean).join(",");let win;try{win=window.open(url,name,params)}catch(err){throw new Error(`${WINDOW_NOT_OPENED} - ${err.stack||err.message}`)}if(!win||window.closed)throw new Error(`${WINDOW_NOT_OPENED} - blocked`);return win}}},"./node_modules/@randlabs/myalgo-connect/lib/utils/errors.js":function(module){class SignTxnsError extends Error{constructor(message,code,data){super(message),this.code=code,this.data=data}}module.exports={ERRORS:{WINDOW_NOT_LOADED:"Window not loaded",WINDOW_IS_OPENED:"Windows is opened",WINDOW_NOT_OPENED:"Can not open popup window",INVALID_WINDOW:"Invalid window"},SignTxnsError:SignTxnsError}},"./node_modules/@randlabs/myalgo-connect/lib/utils/utils.js":function(module){module.exports={sleep:function sleep(msec=200){return new Promise((resolve=>setTimeout(resolve,msec)))},prepareTxn:function prepareTxn(transaction){if(transaction.constructor===Uint8Array)return Buffer.from(transaction).toString("base64");if("string"==typeof transaction)return transaction;const txn=Object.assign({},transaction);if(txn.note&&txn.note.constructor===Uint8Array&&(txn.note=Buffer.from(txn.note).toString("base64")),txn.assetMetadataHash&&txn.assetMetadataHash.constructor===Uint8Array&&(txn.assetMetadataHash=Buffer.from(txn.assetMetadataHash).toString("base64")),txn.group&&txn.group.constructor===Uint8Array&&(txn.group=Buffer.from(txn.group).toString("base64")),"appl"===txn.type&&txn.appApprovalProgram&&txn.appApprovalProgram.constructor===Uint8Array&&(txn.appApprovalProgram=Buffer.from(txn.appApprovalProgram).toString("base64")),"appl"===txn.type&&txn.appClearProgram&&txn.appClearProgram.constructor===Uint8Array&&(txn.appClearProgram=Buffer.from(txn.appClearProgram).toString("base64")),"appl"===txn.type&&txn.appArgs&&txn.appArgs.length>0)for(let i=0;i npx mm-snap build 10 | 11 | compiles the src folder into a functional version of the snap 12 | ### serving 13 | > npx mm-snap serve 14 | 15 | Serves index.html on port 3000 16 | ### sdk 17 | It is possible to use an sdk to simplify using snapalgo. 18 | [repository](https://github.com/Kyraview/SnapAlgoSDK) 19 | This creates a floating wallet on the dapp for better user experence. 20 | As well as creating an easier developer experence by not requiring the 21 | developer to call raw rpc functions. 22 | 23 | ### Connect and Install 24 | Add and Call the below function to connect to the wallet. 25 | If the user does not have the snap installed, but has metamask flask installed this code will automaticly install it for them. **This code snippet can be added to any website with 0 depenancies otheer than metamask flask** 26 | 27 | ```javascript 28 | async function connect () { 29 | await window.ethereum.request({ 30 | method: 'wallet_requestSnaps', 31 | params: { 32 | 'npm:@algorandfoundation/algorand-metamask-snap': {}, 33 | }, 34 | }); 35 | } 36 | ``` 37 | 38 | ### Calling RPC Methods 39 | Below is an example call to the snap that transacts 1000 microalgos to an entered public address. Again this can be run with 0 dependency other than metamask flask 40 | --- 41 | All methods can be called with the param: 42 | testnet: (bool) 43 | if the method does not depend on the testnet it is ignored 44 | if the method can be used with testnet, testnet is then used instead 45 | --- 46 | ```javascript 47 | const address = prompt("Please enter your recipient Address"); 48 | const response = await window.ethereum.request({ 49 | method: 'wallet_invokeSnap', 50 | params: { 51 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 52 | request: { 53 | method: 'transfer', 54 | params: { 55 | to: address, 56 | amount: 1000, 57 | testnet: false 58 | } 59 | }, 60 | }, 61 | }); 62 | ``` 63 | ### Available RPC Methods 64 | 65 | --- 66 | ## Account functions 67 | These functions handle getting infomation about a users account, assets, balance, and history 68 | --- 69 | 70 | ### displayBalance 71 | Displays the users current balance in a metamask flask popup 72 | 73 | ```javascript 74 | await window.ethereum.request({ 75 | method: 'wallet_invokeSnap', 76 | params: { 77 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 78 | request: { 79 | method: 'displayBalance', 80 | }, 81 | }, 82 | }); 83 | ``` 84 | ### getBalance 85 | returns the users current balance 86 | ```javascript 87 | await window.ethereum.request({ 88 | method: 'wallet_invokeSnap', 89 | params: { 90 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 91 | request: { 92 | method: 'getBalance', 93 | }, 94 | }, 95 | }); 96 | ``` 97 | ### getAddress 98 | returns the public address of the wallet 99 | ```javascript 100 | let address = await window.ethereum.request({ 101 | method: 'wallet_invokeSnap', 102 | params: { 103 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 104 | request: { 105 | method: 'getAddress', 106 | }, 107 | }, 108 | }); 109 | ``` 110 | 111 | ### transfer 112 | transfers a number of algos to a specified address 113 | ```javascript 114 | const address = prompt("Please enter your address"); 115 | const response = await window.ethereum.request({ 116 | method: 'wallet_invokeSnap', 117 | params: { 118 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 119 | request: { 120 | method: 'transfer', 121 | params: { 122 | to: address, 123 | amount: 1000 124 | } 125 | }, 126 | }, 127 | }); 128 | ``` 129 | ### displayMnemonic 130 | displays the wallets algorand mnemonic in a secure metamask window 131 | ```javascript 132 | await window.ethereum.request({ 133 | method: 'wallet_invokeSnap', 134 | params: { 135 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 136 | request: { 137 | method: 'displayMnemonic' 138 | }, 139 | }, 140 | }); 141 | ``` 142 | ### getTransactions 143 | returns a list of javascript objects containing transaction data 144 | ```javascript 145 | await window.ethereum.request({ 146 | method: 'wallet_invokeSnap', 147 | params: { 148 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 149 | request: { 150 | method: 'getTransactions' 151 | }, 152 | }, 153 | }); 154 | ``` 155 | ### getAssets 156 | returns a list of the current accounts assets 157 | ```javascript 158 | await window.ethereum.request({ 159 | method: 'wallet_invokeSnap', 160 | params: { 161 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 162 | request: { 163 | method: 'getAssets' 164 | }, 165 | }, 166 | }); 167 | ``` 168 | ### getAccounts 169 | returns an object containing all of the algorand accounts on a users metamask 170 | ```javascript 171 | await window.ethereum.request({ 172 | method: 'wallet_invokeSnap', 173 | params: { 174 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 175 | request: { 176 | method: 'getAccounts' 177 | }, 178 | }, 179 | }); 180 | ``` 181 | ### getCurrentAccount 182 | returns the users current Account 183 | ```javascript 184 | await window.ethereum.request({ 185 | method: 'wallet_invokeSnap', 186 | params: { 187 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 188 | request: { 189 | method: 'getCurrentAccount' 190 | }, 191 | }, 192 | }); 193 | ``` 194 | ### setCurrentAccount 195 | sets the Users Current Account 196 | takes an algorand address as a parameter and throws an error if the address is not contained in the users wallet 197 | returns the users current Account 198 | ```javascript 199 | await window.ethereum.request({ 200 | method: 'wallet_invokeSnap', 201 | params: { 202 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 203 | request: { 204 | method: 'setAccount', 205 | params: { 206 | address: 'address' 207 | } 208 | }, 209 | }, 210 | }); 211 | ``` 212 | *** 213 | ## Arc Complience Functions 214 | these functions are used ARC complient ways to sign arbitray transactions 215 | *** 216 | 217 | ### signTxns 218 | sign an array of [WalletTransaction](https://arc.algorand.foundation/ARCs/arc-0001) objects 219 | returns an array of signed b64 algorand transactions 220 | ```javascript 221 | await window.ethereum.request({ 222 | method: 'wallet_invokeSnap', 223 | params: { 224 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 225 | request: { 226 | method: 'signTxns', 227 | params: { 228 | txns:[WalletTransaction] 229 | } 230 | }, 231 | }, 232 | }); 233 | ``` 234 | 235 | ### postTxns 236 | takes an array of b64 signed algorand transactions. Like the output of signTxns and sends them to the algorand blockchain. 237 | ```javascript 238 | await window.ethereum.request({ 239 | method: 'wallet_invokeSnap', 240 | params: { 241 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 242 | request: { 243 | method: 'postTxns', 244 | params: { 245 | stxns: ["b64SignedTxn"] 246 | } 247 | }, 248 | }, 249 | }); 250 | ``` 251 | 252 | ### signAndPostTxns 253 | takes an array of [WalletTransaction](https://arc.algorand.foundation/ARCs/arc-0001) objects and signs then posts them to the algorand blockchain 254 | ```javascript 255 | await window.ethereum.request({ 256 | method: 'wallet_invokeSnap', 257 | params: { 258 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 259 | request: { 260 | method: 'signAndPostTxns', 261 | params: { 262 | txns: [WalletTransaction] 263 | } 264 | }, 265 | }, 266 | }); 267 | ``` 268 | 269 | 270 | *** 271 | ## Asset Functions 272 | the functions are used to interact with algorand assets 273 | *** 274 | ### assetOptIn 275 | opts into an algorand asset 276 | ```javascript 277 | await window.ethereum.request({ 278 | method: 'wallet_invokeSnap', 279 | params: { 280 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 281 | request: { 282 | method: 'assetOptIn', 283 | params: { 284 | assetIndex: int 285 | } 286 | }, 287 | }, 288 | }); 289 | ``` 290 | 291 | ### assetOptOut 292 | opts out of an algorand asset 293 | ```javascript 294 | await window.ethereum.request({ 295 | method: 'wallet_invokeSnap', 296 | params: { 297 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 298 | request: { 299 | method: 'assetOptOut', 300 | params: { 301 | assetIndex: int 302 | } 303 | }, 304 | }, 305 | }); 306 | ``` 307 | ### transferAsset 308 | sends an algorand asset to another wallet that is opted into the given asset 309 | ```javascript 310 | await window.ethereum.request({ 311 | method: 'wallet_invokeSnap', 312 | params: { 313 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 314 | request: { 315 | method: 'transferAsset', 316 | params: { 317 | assetIndex: int, 318 | to: "algorandAddress", 319 | amount: string 320 | } 321 | }, 322 | }, 323 | }); 324 | ``` 325 | 326 | 327 | *** 328 | ## swapping functions 329 | These functions are used to swap crypto between 330 | Algorand, Etherum, and Binance Smart Chain 331 | The ticker values are 332 | algo | eth | bsc 333 | 334 | *** 335 | 336 | ### get Minimum 337 | get minimum input amount for a specific swap 338 | ```javascript 339 | async function getMin(){ 340 | const result = await window.ethereum.request({ 341 | method: 'wallet_invokeSnap', 342 | params: { 343 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 344 | request: { 345 | method: 'getMin', 346 | params: { 347 | from: 'eth' | 'bsc' | 'algo', 348 | to: 'eth' | 'bsc' | 'algo', 349 | } 350 | }, 351 | }, 352 | }); 353 | 354 | return result; 355 | } 356 | ``` 357 | ### preSwap 358 | Get infomation about a swap without actually swapping 359 | ```javascript 360 | async function preSwap(){ 361 | const result = await window.ethereum.request({ 362 | method: 'wallet_invokeSnap', 363 | params: { 364 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 365 | request: { 366 | method: 'preSwap', 367 | params: { 368 | from: 'eth' | 'bsc' | 'algo', 369 | to: 'eth' | 'bsc' | 'algo', 370 | amount: Number(amount) //done in base units i.e. eth not wei 371 | } 372 | }, 373 | }, 374 | }); 375 | 376 | return result; 377 | } 378 | ``` 379 | 380 | ### swap 381 | swap currencies 382 | this will automatically send send the required currency to the exchange and use the selected address to receive the cash 383 | uses changenow 384 | ```javascript 385 | async function swap(){ 386 | const result = await window.ethereum.request({ 387 | method: 'wallet_invokeSnap', 388 | params: { 389 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 390 | request: { 391 | method: 'swap', 392 | params: { 393 | from: 'eth' | 'bsc' | 'algo', 394 | to: 'eth' | 'bsc' | 'algo', 395 | amount: Number(amount) //done in base units i.e. eth not wei 396 | email: String("emailAddress@example.com") //completely optional 397 | } 398 | }, 399 | }, 400 | }); 401 | 402 | return result; 403 | } 404 | ``` 405 | 406 | ### swapHistory 407 | the method returns an array of swap objects that give info about a swap performed by a given wallet. 408 | ```javascript 409 | async function swapHistory(){ 410 | const result = await window.ethereum.request({ 411 | method: 'wallet_invokeSnap', 412 | params: { 413 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 414 | request: { 415 | method: 'swapHistory', 416 | }, 417 | }, 418 | }); 419 | 420 | return result; 421 | } 422 | ``` 423 | 424 | ### getSwapStatus 425 | this method returns a status object of swap given the swaps id that can be obtained from swap history 426 | ```javascript 427 | async function getSwapStatus(){ 428 | const result = await window.ethereum.request({ 429 | method: 'wallet_invokeSnap', 430 | params: { 431 | snapId: 'npm:@algorandfoundation/algorand-metamask-snap', 432 | request: { 433 | method: 'getSwapStatus', 434 | params: { 435 | id: 'changenowSwapID' 436 | } 437 | }, 438 | }, 439 | }); 440 | 441 | return result; 442 | } 443 | ``` 444 | 445 | More RPC methods to come 446 | -------------------------------------------------------------------------------- /src/Accounts.js: -------------------------------------------------------------------------------- 1 | import nacl from 'tweetnacl'; 2 | const algo = require('algosdk/dist/cjs'); 3 | import { getBIP44AddressKeyDeriver, JsonBIP44CoinTypeNode} from '@metamask/key-tree'; 4 | import {SHA256, enc} from "crypto-js"; 5 | import Utils from './Utils'; 6 | /* 7 | This class defines handles storing keys, and all account related code 8 | 9 | 10 | 11 | accounts are stored on the metamask state object. 12 | Which is essentially a javascript {} object 13 | This object is encrypted by metamask. 14 | { 15 | currentAccountId: account_address, 16 | Accounts: { 17 | "0xaddresskjhiuhu": { 18 | type: string("generated"|"imported"), 19 | seed: The encrypted Seed for the account if the account type is imported, 20 | path: A path Integer if the account type is generated, 21 | name: the Display name of the Account 22 | addr: //the address of the account the same as the Account Key 23 | swaps: [ //an array that records swap history for an account 24 | {} 25 | ] 26 | 27 | }, 28 | ... 29 | } 30 | } 31 | */ 32 | 33 | // Function for Encrypting Data using TweetNaCl: 34 | function encryptNACL(secretKey, message) { 35 | const nonce = nacl.randomBytes(24); 36 | const secretKeyUint8Array = new Uint8Array(secretKey); 37 | const messageUint8Array = new TextEncoder().encode(message); 38 | 39 | const encryptedMessage = nacl.secretbox(messageUint8Array, nonce, secretKeyUint8Array); 40 | const fullMessage = new Uint8Array(nonce.length + encryptedMessage.length); 41 | 42 | fullMessage.set(nonce); 43 | fullMessage.set(encryptedMessage, nonce.length); 44 | 45 | const base64Encoded = buffer.from(fullMessage).toString('base64'); 46 | return base64Encoded; 47 | } 48 | 49 | // Function for Decrypting Data using TweetNaCl: 50 | function decryptNACL(secretKey, encryptedData) { 51 | const secretKeyUint8Array = new Uint8Array(secretKey); 52 | const messageWithNonceAsBuffer = buffer.from(encryptedData, 'base64'); 53 | const messageWithNonceAsUint8Array = new Uint8Array(messageWithNonceAsBuffer); 54 | 55 | const nonce = messageWithNonceAsUint8Array.slice(0, 24); 56 | const message = messageWithNonceAsUint8Array.slice(24); 57 | 58 | const decryptedMessage = nacl.secretbox.open(message, nonce, secretKeyUint8Array); 59 | const decryptedMessageString = new TextDecoder().decode(decryptedMessage); 60 | 61 | return decryptedMessageString; 62 | } 63 | 64 | 65 | 66 | 67 | 68 | export default class Accounts{ 69 | constructor(wallet){ 70 | 71 | this.wallet = wallet; 72 | this.accounts = {}; 73 | this.currentAccountId = null; 74 | this.currentAccount = null; 75 | this.loaded = false; 76 | 77 | } 78 | //must be called before using the Accounts class 79 | //and esentially loads all the neccerary data 80 | async init(){ 81 | 82 | //load acount Data 83 | const storedAccounts = await this.wallet.request({ 84 | method: 'snap_manageState', 85 | params: {operation: 'get'}, 86 | }); 87 | 88 | //checks to see if accounts already exists and if this is not the case 89 | //creates an account 90 | if(storedAccounts === null || Object.keys(storedAccounts).length === 0){ 91 | 92 | const Account = await this.#generateAccount(2); 93 | let extendedAccount = {}; 94 | extendedAccount.type = 'generated'; 95 | extendedAccount.addr = Account.addr; 96 | extendedAccount.path = 2; 97 | extendedAccount.name = 'Account 1'; 98 | extendedAccount.swaps = []; 99 | const address = Account.addr; 100 | const accounts = {} 101 | accounts[address] = extendedAccount; 102 | await this.wallet.request({ 103 | method: 'snap_manageState', 104 | params: {operation:'update', newState:{"currentAccountId": address, "Accounts": accounts}}, 105 | }) 106 | this.currentAccountId = address; 107 | this.accounts = accounts; 108 | this.loaded = true; 109 | 110 | return {"currentAccountId": address, "Accounts": accounts}; 111 | } 112 | 113 | this.accounts = storedAccounts.Accounts; 114 | this.currentAccountId = storedAccounts.currentAccountId; 115 | this.loaded = true; 116 | return this.accounts; 117 | } 118 | /* 119 | this function takes in an address gets an account from 120 | */ 121 | async unlockAccount(addr){ 122 | 123 | if(this.accounts.hasOwnProperty(addr)){ 124 | const tempAccount = this.accounts[addr]; 125 | if(tempAccount.type === 'generated'){ 126 | const Account = await this.#generateAccount(tempAccount.path); 127 | Account.name = tempAccount.name 128 | return Account; 129 | } 130 | else if(tempAccount.type === 'imported'){ 131 | const key = await this.#getencryptionKey(); 132 | let b64Seed = tempAccount.seed; 133 | b64Seed = decryptNACL(b64Seed, key); 134 | const seed = new Uint8Array(Buffer.from(b64Seed, 'base64')); 135 | const keys = nacl.sign.keyPair.fromSeed(seed); 136 | const Account = {} 137 | Account.addr = algo.encodeAddress(keys.publicKey); 138 | Account.sk = keys.secretKey; 139 | Account.name = tempAccount.name; 140 | return Account 141 | } 142 | } 143 | } 144 | 145 | async getCurrentAccount(){ 146 | if(this.currentAccount !== null){ 147 | return this.currentAccount 148 | } 149 | this.currentAccount = await this.unlockAccount(this.currentAccountId); 150 | return this.currentAccount; 151 | } 152 | 153 | async getCurrentNeuteredAccount(){ 154 | let output = {} 155 | const currentAccount = this.accounts[this.currentAccountId]; 156 | if(currentAccount.type === "imported"){ 157 | output.type = String(currentAccount.type) 158 | output.name = String(currentAccount.name) 159 | output.swaps = JSON.parse(JSON.stringify(currentAccount.swaps)) 160 | output.addr = String(currentAccount.addr) 161 | return output 162 | } 163 | return JSON.parse(JSON.stringify(currentAccount)) 164 | } 165 | 166 | getNeuteredAccounts(){ 167 | let output = {} 168 | for(let addr in this.accounts){ 169 | if(this.accounts[addr].type === "imported"){ 170 | output[addr] = {} 171 | output[addr].type = String(this.accounts[addr].type) 172 | output[addr].name = String(this.accounts[addr].name) 173 | output[addr].addr = String(addr) 174 | output[addr].swaps = JSON.parse(JSON.stringify(this.accounts[addr].swaps)) 175 | } 176 | else{ 177 | output[addr] = JSON.parse(JSON.stringify(this.accounts[addr])); 178 | } 179 | } 180 | 181 | return output; 182 | } 183 | 184 | async setCurrentAccount(addr){ 185 | if(this.accounts.hasOwnProperty(addr)){ 186 | this.currentAccountId = addr; 187 | this.currentAccount = await this.unlockAccount(addr); 188 | await this.wallet.request({ 189 | method: 'snap_manageState', 190 | params: {operation:'update', newState:{"currentAccountId": addr, "Accounts": this.accounts}}, 191 | }) 192 | return true; 193 | } 194 | else{ 195 | return Utils.throwError(4300, "account not found") 196 | } 197 | } 198 | 199 | //gets all accounts 200 | async getAccounts(){ 201 | return this.accounts; 202 | } 203 | 204 | //clears all account data 205 | async clearAccounts(){ 206 | await this.wallet.request({ 207 | method: 'snap_manageState', 208 | params: {operation:'clear'}, 209 | }); 210 | return true 211 | } 212 | 213 | 214 | async createNewAccount(name){ 215 | if(!name){ 216 | const accountIndex = (Object.keys(this.accounts).length+1) //generates an account number from the number of accounts 217 | name = 'Account ' + accountIndex; 218 | } 219 | const path = Object.keys(this.accounts).length+2; 220 | const Account = await this.#generateAccount(path); 221 | const address = Account.addr; 222 | 223 | 224 | this.accounts[address] = {type: 'generated', path: path, name: name, addr: address, swaps: []}; 225 | await this.wallet.request({ 226 | method: 'snap_manageState', 227 | params: {operation:'update', newState:{"currentAccountId": this.currentAccountId, "Accounts": this.accounts}}, 228 | }) 229 | return {"currentAccountId": address, "Accounts": this.accounts, "Account": Account}; 230 | } 231 | 232 | async #getencryptionKey(){ 233 | const entropy = await this.wallet.request({ 234 | method: 'snap_getBip44Entropy', 235 | params: { 236 | coinType: 283, 237 | }, 238 | }); 239 | 240 | //dirive private key using metamask key tree 241 | const coinTypeNode = entropy; 242 | // Get an address key deriver for the coin_type node. 243 | // In this case, its path will be: m / 44' / 60' / 0' / 0 / address_index 244 | // Alternatively you can use an extended key (`xprv`) as well. 245 | const addressKeyDeriver = await getBIP44AddressKeyDeriver(coinTypeNode); 246 | 247 | 248 | //generate an extended private key then grab the first 32 bytes 249 | //this coresponds to the private key portion of the extended private key 250 | 251 | const privateKey = (await addressKeyDeriver(0)).privateKeyBuffer; 252 | return SHA256(privateKey).toString(); 253 | } 254 | 255 | async importAccount(name, mnemonic){ 256 | //if name is not specified generate name based on number of accounts 257 | if(!name){ 258 | name = 'Account ' + (Object.keys(this.accounts).length+1); 259 | } 260 | 261 | const seed = algo.seedFromMnemonic(mnemonic) 262 | const keys = nacl.sign.keyPair.fromSeed(seed); 263 | 264 | const address = algo.encodeAddress(keys.publicKey); 265 | let b64Seed = Buffer.from(seed).toString('base64'); 266 | const key = await this.#getencryptionKey(); 267 | const encryptedSeed = encryptNACL(b64Seed, key).toString(); 268 | 269 | 270 | this.accounts[address] = {type: 'imported', seed:encryptedSeed, name:name, addr: address, swaps: []}; 271 | await this.wallet.request({ 272 | method: 'snap_manageState', 273 | params: {operation:'update', newState:{"currentAccountId": this.currentAccountId, "Accounts": this.accounts}} 274 | }) 275 | return {"currentAccountId": address, "Accounts": this.accounts}; 276 | } 277 | 278 | 279 | async #generateAccount(path){ 280 | 281 | // Get the node sent from the privileged context. 282 | // It will have the following shape: 283 | // { 284 | // privateKey, // A hexadecimal string of the private key 285 | // publicKey, // A hexadecimal string of the public key 286 | // chainCode, // A hexadecimal string of the chain code 287 | // depth, // The number 2, which is the depth of coin_type nodes 288 | // parentFingerprint, // The fingerprint of the parent node as number 289 | // index, // The index of the node as number 290 | // coin_type, // In this case, the number 60 291 | // path, // For visualization only. In this case: m / 44' / 60' 292 | // } 293 | const coinTypeNode = await this.wallet.request({ 294 | method: 'snap_getBip44Entropy', 295 | params: { 296 | coinType: 283, 297 | }, 298 | }); 299 | 300 | 301 | // Get an address key deriver for the coin_type node. 302 | // In this case, its path will be: m / 44' / 60' / 0' / 0 / address_index 303 | // Alternatively you can use an extended key (`xprv`) as well. 304 | const addressKeyDeriver = await getBIP44AddressKeyDeriver(coinTypeNode); 305 | 306 | let seed = (await addressKeyDeriver(path)).privateKeyBytes; 307 | //Harden the seed 308 | seed = nacl.hash(seed).slice(32); 309 | //algosdk requires keysPairs to be dirived by nacl so we can use the private key as 32 bytes of entropy 310 | const keys = nacl.sign.keyPair.fromSeed(seed); 311 | 312 | const Account = {} 313 | Account.addr = algo.encodeAddress(keys.publicKey); 314 | Account.sk = keys.secretKey; 315 | 316 | return Account; 317 | 318 | } 319 | //return a Mnemonic for a given KeyPair 320 | async getMnemonic(keypair){ 321 | return algo.secretKeyToMnemonic(keypair.sk) 322 | } 323 | 324 | } -------------------------------------------------------------------------------- /useWalletIntegration_test/iframe.html: -------------------------------------------------------------------------------- 1 | Webpack App

No Preview

Sorry, but you either have no stories or none are selected somehow.

  • Please check the Storybook config.
  • Try reloading the page.

If the problem persists, check the browser console, or the terminal you've run Storybook from.

-------------------------------------------------------------------------------- /useWalletIntegration_test/522.4a558ff9.iframe.bundle.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunk_txnlab_use_wallet=self.webpackChunk_txnlab_use_wallet||[]).push([[522],{"./node_modules/@walletconnect/browser-utils/dist/esm/index.js":function(__unused_webpack_module,__webpack_exports__,__webpack_require__){__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{detectEnv:function(){return detectEnv},detectOS:function(){return browser_detectOS},formatIOSMobile:function(){return formatIOSMobile},formatMobileRegistry:function(){return formatMobileRegistry},formatMobileRegistryEntry:function(){return formatMobileRegistryEntry},getClientMeta:function(){return getClientMeta},getCrypto:function(){return getCrypto},getCryptoOrThrow:function(){return getCryptoOrThrow},getDappRegistryUrl:function(){return getDappRegistryUrl},getDocument:function(){return getDocument},getDocumentOrThrow:function(){return getDocumentOrThrow},getFromWindow:function(){return getFromWindow},getFromWindowOrThrow:function(){return getFromWindowOrThrow},getLocal:function(){return getLocal},getLocalStorage:function(){return getLocalStorage},getLocalStorageOrThrow:function(){return getLocalStorageOrThrow},getLocation:function(){return getLocation},getLocationOrThrow:function(){return getLocationOrThrow},getMobileLinkRegistry:function(){return getMobileLinkRegistry},getMobileRegistryEntry:function(){return getMobileRegistryEntry},getNavigator:function(){return getNavigator},getNavigatorOrThrow:function(){return getNavigatorOrThrow},getWalletRegistryUrl:function(){return getWalletRegistryUrl},isAndroid:function(){return isAndroid},isBrowser:function(){return isBrowser},isIOS:function(){return isIOS},isMobile:function(){return isMobile},isNode:function(){return isNode},mobileLinkChoiceKey:function(){return mobileLinkChoiceKey},removeLocal:function(){return removeLocal},safeJsonParse:function(){return json_safeJsonParse},safeJsonStringify:function(){return json_safeJsonStringify},saveMobileLinkInfo:function(){return saveMobileLinkInfo},setLocal:function(){return setLocal}});var cjs=__webpack_require__("./node_modules/@walletconnect/window-metadata/dist/cjs/index.js"),dist_cjs=__webpack_require__("./node_modules/@walletconnect/window-getters/dist/cjs/index.js"),process=__webpack_require__("./node_modules/process/browser.js"),__spreadArrays=function(){for(var s=0,i=0,il=arguments.length;i1)}function isMobile(){return!!browser_detectOS()&&(isAndroid()||isIOS())}function isNode(){const env=detectEnv();return!(!env||!env.name)&&"node"===env.name.toLowerCase()}function isBrowser(){return!isNode()&&!!getNavigator()}const getFromWindow=dist_cjs.sD,getFromWindowOrThrow=dist_cjs.$2,getDocumentOrThrow=dist_cjs.uT,getDocument=dist_cjs.Me,getNavigatorOrThrow=dist_cjs.Gw,getNavigator=dist_cjs.jW,getLocationOrThrow=dist_cjs.UO,getLocation=dist_cjs.k$,getCryptoOrThrow=dist_cjs.VQ,getCrypto=dist_cjs.MX,getLocalStorageOrThrow=dist_cjs.xP,getLocalStorage=dist_cjs.$o;function getClientMeta(){return cjs.D()}const json_safeJsonParse=function safeJsonParse(value){if("string"!=typeof value)throw new Error("Cannot safe json parse value of type "+typeof value);try{return JSON.parse(value)}catch(_a){return value}},json_safeJsonStringify=function safeJsonStringify(value){return"string"==typeof value?value:JSON.stringify(value)};function setLocal(key,data){const raw=json_safeJsonStringify(data),local=getLocalStorage();local&&local.setItem(key,raw)}function getLocal(key){let data=null,raw=null;const local=getLocalStorage();return local&&(raw=local.getItem(key)),data=raw?json_safeJsonParse(raw):raw,data}function removeLocal(key){const local=getLocalStorage();local&&local.removeItem(key)}const mobileLinkChoiceKey="WALLETCONNECT_DEEPLINK_CHOICE";function formatIOSMobile(uri,entry){const encodedUri=encodeURIComponent(uri);return entry.universalLink?`${entry.universalLink}/wc?uri=${encodedUri}`:entry.deepLink?`${entry.deepLink}${entry.deepLink.endsWith(":")?"//":"/"}wc?uri=${encodedUri}`:""}function saveMobileLinkInfo(data){const focusUri=data.href.split("?")[0];setLocal(mobileLinkChoiceKey,Object.assign(Object.assign({},data),{href:focusUri}))}function getMobileRegistryEntry(registry,name){return registry.filter((entry=>entry.name.toLowerCase().includes(name.toLowerCase())))[0]}function getMobileLinkRegistry(registry,whitelist){let links=registry;return whitelist&&(links=whitelist.map((name=>getMobileRegistryEntry(registry,name))).filter(Boolean)),links}const API_URL="https://registry.walletconnect.com";function getWalletRegistryUrl(){return API_URL+"/api/v2/wallets"}function getDappRegistryUrl(){return API_URL+"/api/v2/dapps"}function formatMobileRegistryEntry(entry,platform="mobile"){var _a;return{name:entry.name||"",shortName:entry.metadata.shortName||"",color:entry.metadata.colors.primary||"",logo:null!==(_a=entry.image_url.sm)&&void 0!==_a?_a:"",universalLink:entry[platform].universal||"",deepLink:entry[platform].native||""}}function formatMobileRegistry(registry,platform="mobile"){return Object.values(registry).filter((entry=>!!entry[platform].universal||!!entry[platform].native)).map((entry=>formatMobileRegistryEntry(entry,platform)))}},"./node_modules/@walletconnect/window-getters/dist/cjs/index.js":function(__unused_webpack_module,exports){function getFromWindow(name){let res;return"undefined"!=typeof window&&void 0!==window[name]&&(res=window[name]),res}function getFromWindowOrThrow(name){const res=getFromWindow(name);if(!res)throw new Error(`${name} is not defined in Window`);return res}exports.$o=exports.xP=exports.MX=exports.VQ=exports.k$=exports.UO=exports.jW=exports.Gw=exports.Me=exports.uT=exports.$2=exports.sD=void 0,exports.sD=getFromWindow,exports.$2=getFromWindowOrThrow,exports.uT=function getDocumentOrThrow(){return getFromWindowOrThrow("document")},exports.Me=function getDocument(){return getFromWindow("document")},exports.Gw=function getNavigatorOrThrow(){return getFromWindowOrThrow("navigator")},exports.jW=function getNavigator(){return getFromWindow("navigator")},exports.UO=function getLocationOrThrow(){return getFromWindowOrThrow("location")},exports.k$=function getLocation(){return getFromWindow("location")},exports.VQ=function getCryptoOrThrow(){return getFromWindowOrThrow("crypto")},exports.MX=function getCrypto(){return getFromWindow("crypto")},exports.xP=function getLocalStorageOrThrow(){return getFromWindowOrThrow("localStorage")},exports.$o=function getLocalStorage(){return getFromWindow("localStorage")}},"./node_modules/@walletconnect/window-metadata/dist/cjs/index.js":function(__unused_webpack_module,exports,__webpack_require__){exports.D=void 0;const window_getters_1=__webpack_require__("./node_modules/@walletconnect/window-metadata/node_modules/@walletconnect/window-getters/dist/cjs/index.js");exports.D=function getWindowMetadata(){let doc,loc;try{doc=window_getters_1.getDocumentOrThrow(),loc=window_getters_1.getLocationOrThrow()}catch(e){return null}function getWindowMetadataOfAny(...args){const metaTags=doc.getElementsByTagName("meta");for(let i=0;itag.getAttribute(target))).filter((attr=>!!attr&&args.includes(attr)));if(attributes.length&&attributes){const content=tag.getAttribute("content");if(content)return content}}return""}const name=function getName(){let name=getWindowMetadataOfAny("name","og:site_name","og:title","twitter:title");return name||(name=doc.title),name}();return{description:function getDescription(){return getWindowMetadataOfAny("description","og:description","twitter:description","keywords")}(),url:loc.origin,icons:function getIcons(){const links=doc.getElementsByTagName("link"),icons=[];for(let i=0;i-1){const href=link.getAttribute("href");if(href)if(-1===href.toLowerCase().indexOf("https:")&&-1===href.toLowerCase().indexOf("http:")&&0!==href.indexOf("//")){let absoluteHref=loc.protocol+"//"+loc.host;if(0===href.indexOf("/"))absoluteHref+=href;else{const path=loc.pathname.split("/");path.pop();absoluteHref+=path.join("/")+"/"+href}icons.push(absoluteHref)}else if(0===href.indexOf("//")){const absoluteUrl=loc.protocol+href;icons.push(absoluteUrl)}else icons.push(href)}}return icons}(),name:name}}},"./node_modules/@walletconnect/window-metadata/node_modules/@walletconnect/window-getters/dist/cjs/index.js":function(__unused_webpack_module,exports){function getFromWindow(name){let res;return"undefined"!=typeof window&&void 0!==window[name]&&(res=window[name]),res}function getFromWindowOrThrow(name){const res=getFromWindow(name);if(!res)throw new Error(`${name} is not defined in Window`);return res}Object.defineProperty(exports,"__esModule",{value:!0}),exports.getLocalStorage=exports.getLocalStorageOrThrow=exports.getCrypto=exports.getCryptoOrThrow=exports.getLocation=exports.getLocationOrThrow=exports.getNavigator=exports.getNavigatorOrThrow=exports.getDocument=exports.getDocumentOrThrow=exports.getFromWindowOrThrow=exports.getFromWindow=void 0,exports.getFromWindow=getFromWindow,exports.getFromWindowOrThrow=getFromWindowOrThrow,exports.getDocumentOrThrow=function getDocumentOrThrow(){return getFromWindowOrThrow("document")},exports.getDocument=function getDocument(){return getFromWindow("document")},exports.getNavigatorOrThrow=function getNavigatorOrThrow(){return getFromWindowOrThrow("navigator")},exports.getNavigator=function getNavigator(){return getFromWindow("navigator")},exports.getLocationOrThrow=function getLocationOrThrow(){return getFromWindowOrThrow("location")},exports.getLocation=function getLocation(){return getFromWindow("location")},exports.getCryptoOrThrow=function getCryptoOrThrow(){return getFromWindowOrThrow("crypto")},exports.getCrypto=function getCrypto(){return getFromWindow("crypto")},exports.getLocalStorageOrThrow=function getLocalStorageOrThrow(){return getFromWindowOrThrow("localStorage")},exports.getLocalStorage=function getLocalStorage(){return getFromWindow("localStorage")}}}]); -------------------------------------------------------------------------------- /replit_zip_error_log.txt: -------------------------------------------------------------------------------- 1 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/bin/npm","time":"2022-12-14T04:13:08Z"} 2 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/bin/npx","time":"2022-12-14T04:13:08Z"} 3 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/arborist","time":"2022-12-14T04:13:08Z"} 4 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/color-support","time":"2022-12-14T04:13:08Z"} 5 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/cssesc","time":"2022-12-14T04:13:08Z"} 6 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/installed-package-contents","time":"2022-12-14T04:13:08Z"} 7 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/mkdirp","time":"2022-12-14T04:13:08Z"} 8 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/node-gyp","time":"2022-12-14T04:13:08Z"} 9 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/node-which","time":"2022-12-14T04:13:08Z"} 10 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/nopt","time":"2022-12-14T04:13:08Z"} 11 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/pacote","time":"2022-12-14T04:13:08Z"} 12 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/qrcode-terminal","time":"2022-12-14T04:13:08Z"} 13 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/rimraf","time":"2022-12-14T04:13:08Z"} 14 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/.bin/semver","time":"2022-12-14T04:13:08Z"} 15 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/node-gyp/node_modules/.bin/node-which","time":"2022-12-14T04:13:13Z"} 16 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file .config/npm/node_global/lib/node_modules/npm/node_modules/node-gyp/node_modules/.bin/nopt","time":"2022-12-14T04:13:13Z"} 17 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/JSONStream","time":"2022-12-14T04:13:16Z"} 18 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/acorn","time":"2022-12-14T04:13:16Z"} 19 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/browser-pack","time":"2022-12-14T04:13:16Z"} 20 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/browserify","time":"2022-12-14T04:13:16Z"} 21 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/browserslist","time":"2022-12-14T04:13:16Z"} 22 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/browserslist-lint","time":"2022-12-14T04:13:16Z"} 23 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/deps-sort","time":"2022-12-14T04:13:16Z"} 24 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/detective","time":"2022-12-14T04:13:16Z"} 25 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/insert-module-globals","time":"2022-12-14T04:13:16Z"} 26 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/is-ci","time":"2022-12-14T04:13:16Z"} 27 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/is-docker","time":"2022-12-14T04:13:16Z"} 28 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/jsesc","time":"2022-12-14T04:13:16Z"} 29 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/json5","time":"2022-12-14T04:13:16Z"} 30 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/miller-rabin","time":"2022-12-14T04:13:16Z"} 31 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/mime","time":"2022-12-14T04:13:16Z"} 32 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/mm-snap","time":"2022-12-14T04:13:16Z"} 33 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/module-deps","time":"2022-12-14T04:13:16Z"} 34 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/nvm","time":"2022-12-14T04:13:16Z"} 35 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/parser","time":"2022-12-14T04:13:16Z"} 36 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/patch-package","time":"2022-12-14T04:13:16Z"} 37 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/regjsparser","time":"2022-12-14T04:13:16Z"} 38 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/resolve","time":"2022-12-14T04:13:16Z"} 39 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/rimraf","time":"2022-12-14T04:13:16Z"} 40 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/semver","time":"2022-12-14T04:13:16Z"} 41 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/sha.js","time":"2022-12-14T04:13:16Z"} 42 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/umd","time":"2022-12-14T04:13:16Z"} 43 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/undeclared-identifiers","time":"2022-12-14T04:13:16Z"} 44 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/.bin/which","time":"2022-12-14T04:13:16Z"} 45 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/core/node_modules/.bin/json5","time":"2022-12-14T04:13:16Z"} 46 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/core/node_modules/.bin/parser","time":"2022-12-14T04:13:16Z"} 47 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/core/node_modules/.bin/semver","time":"2022-12-14T04:13:16Z"} 48 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/generator/node_modules/.bin/jsesc","time":"2022-12-14T04:13:16Z"} 49 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/helper-compilation-targets/node_modules/.bin/browserslist","time":"2022-12-14T04:13:16Z"} 50 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/helper-compilation-targets/node_modules/.bin/semver","time":"2022-12-14T04:13:16Z"} 51 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/helper-define-polyfill-provider/node_modules/.bin/resolve","time":"2022-12-14T04:13:16Z"} 52 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/helper-define-polyfill-provider/node_modules/.bin/semver","time":"2022-12-14T04:13:16Z"} 53 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/plugin-transform-runtime/node_modules/.bin/semver","time":"2022-12-14T04:13:17Z"} 54 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/preset-env/node_modules/.bin/semver","time":"2022-12-14T04:13:17Z"} 55 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/template/node_modules/.bin/parser","time":"2022-12-14T04:13:17Z"} 56 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@babel/traverse/node_modules/.bin/parser","time":"2022-12-14T04:13:17Z"} 57 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@metamask/snaps-cli/node_modules/.bin/browserify","time":"2022-12-14T04:13:18Z"} 58 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/@metamask/snaps-utils/node_modules/.bin/semver","time":"2022-12-14T04:13:18Z"} 59 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/acorn-node/node_modules/.bin/acorn","time":"2022-12-14T04:13:19Z"} 60 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/babel-plugin-polyfill-corejs2/node_modules/.bin/semver","time":"2022-12-14T04:13:20Z"} 61 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browser-pack/node_modules/.bin/JSONStream","time":"2022-12-14T04:13:20Z"} 62 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browser-pack/node_modules/.bin/umd","time":"2022-12-14T04:13:20Z"} 63 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browser-resolve/node_modules/.bin/resolve","time":"2022-12-14T04:13:20Z"} 64 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browserify/node_modules/.bin/JSONStream","time":"2022-12-14T04:13:20Z"} 65 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browserify/node_modules/.bin/browser-pack","time":"2022-12-14T04:13:20Z"} 66 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browserify/node_modules/.bin/deps-sort","time":"2022-12-14T04:13:20Z"} 67 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browserify/node_modules/.bin/insert-module-globals","time":"2022-12-14T04:13:20Z"} 68 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browserify/node_modules/.bin/module-deps","time":"2022-12-14T04:13:20Z"} 69 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browserify/node_modules/.bin/resolve","time":"2022-12-14T04:13:20Z"} 70 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/browserslist/node_modules/.bin/browserslist-lint","time":"2022-12-14T04:13:20Z"} 71 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/core-js-compat/node_modules/.bin/browserslist","time":"2022-12-14T04:13:21Z"} 72 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/create-hash/node_modules/.bin/sha.js","time":"2022-12-14T04:13:21Z"} 73 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/create-hmac/node_modules/.bin/sha.js","time":"2022-12-14T04:13:21Z"} 74 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/cross-spawn/node_modules/.bin/semver","time":"2022-12-14T04:13:21Z"} 75 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/cross-spawn/node_modules/.bin/which","time":"2022-12-14T04:13:21Z"} 76 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/deps-sort/node_modules/.bin/JSONStream","time":"2022-12-14T04:13:21Z"} 77 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/diffie-hellman/node_modules/.bin/miller-rabin","time":"2022-12-14T04:13:21Z"} 78 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/insert-module-globals/node_modules/.bin/JSONStream","time":"2022-12-14T04:13:22Z"} 79 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/insert-module-globals/node_modules/.bin/undeclared-identifiers","time":"2022-12-14T04:13:22Z"} 80 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/is-wsl/node_modules/.bin/is-docker","time":"2022-12-14T04:13:22Z"} 81 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/module-deps/node_modules/.bin/JSONStream","time":"2022-12-14T04:13:23Z"} 82 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/module-deps/node_modules/.bin/detective","time":"2022-12-14T04:13:23Z"} 83 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/module-deps/node_modules/.bin/resolve","time":"2022-12-14T04:13:23Z"} 84 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/open/node_modules/.bin/is-docker","time":"2022-12-14T04:13:23Z"} 85 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/patch-package/node_modules/.bin/is-ci","time":"2022-12-14T04:13:23Z"} 86 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/patch-package/node_modules/.bin/rimraf","time":"2022-12-14T04:13:23Z"} 87 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/patch-package/node_modules/.bin/semver","time":"2022-12-14T04:13:23Z"} 88 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/pbkdf2/node_modules/.bin/sha.js","time":"2022-12-14T04:13:23Z"} 89 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/regexpu-core/node_modules/.bin/regjsparser","time":"2022-12-14T04:13:24Z"} 90 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/regjsparser/node_modules/.bin/jsesc","time":"2022-12-14T04:13:24Z"} 91 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/superagent/node_modules/.bin/mime","time":"2022-12-14T04:13:31Z"} 92 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/superagent/node_modules/.bin/semver","time":"2022-12-14T04:13:31Z"} 93 | {"error":".zip archives do not support non-regular files","level":"error","msg":"unable to write file node_modules/update-browserslist-db/node_modules/.bin/browserslist","time":"2022-12-14T04:13:32Z"} 94 | -------------------------------------------------------------------------------- /src/TxnVerifier.js: -------------------------------------------------------------------------------- 1 | const algosdk = require('algosdk/dist/cjs'); 2 | 3 | export default class TxnVerifer{ 4 | constructor(){ 5 | this.errorCheck = {}; 6 | this.max64 = (2**64)-1; 7 | this.idTable= {"mainnet-v1.0": "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", 8 | "testnet-v1.0": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", 9 | "betanet-v1.0": "mFgazF+2uRS1tMiL9dsj01hJGySEmPN28B/TjjvpVW0="}; 10 | } 11 | verifyTxn(txn, balance){ 12 | this.errorCheck = 13 | { 14 | valid:true, 15 | error:[], 16 | warnings:[], 17 | info:[], 18 | }; 19 | 20 | const Required = ["type", "from", "fee", "firstRound", "lastRound", "genesisHash"]; 21 | const Optional = ["genesisId", "group", "lease", "note", "reKeyTo", 'amount']; 22 | 23 | for(var requirement of Required){ 24 | if(!txn[requirement]){ 25 | this.thrower(4300, 'Required field missing: '+requirement); 26 | } else { 27 | if(requirement === "fee"){ 28 | let fee = requirement 29 | if(!this.checkInt({value:txn[fee],min:1000})){ 30 | this.thrower(4300,'fee must be a uint64 between 1000 and 18446744073709551615'); 31 | } 32 | if(BigInt(txn[fee]) > BigInt(balance)){ 33 | this.thrower(4100, 'transaction Fee is greater than spendable funds') 34 | } 35 | else{ 36 | if(txn[fee] > 1000000){ 37 | this.errorCheck.warnings.push('fee is very high: '+txn[fee]+' microalgos'); 38 | } 39 | } 40 | } 41 | if(requirement === "firstRound"){ 42 | if(!this.checkInt({value:txn[requirement],min:1})){ 43 | this.thrower(4300, 'firstRound must be a uint64 between 1 and 18446744073709551615') 44 | } 45 | } 46 | if(requirement === "genesisHash"){ 47 | if(txn[requirement] instanceof Uint32Array){ 48 | this.thrower(4300, 'genesisHash must be Uint32Array'); 49 | } 50 | let hashString = this.buf264(txn[requirement]); 51 | if(!Object.values(this.idTable).includes(hashString)){ 52 | this.thrower(4300, 'genesisHash must be valid network hash'); 53 | } 54 | } 55 | if(requirement === "lastRound"){ 56 | if(!this.checkInt({value:txn[requirement],min:1})){ 57 | this.thrower(4300, 'lastRound must be uint64 between 1 and 18446744073709551615'); 58 | } 59 | if(txn[requirement] BigInt(balance)){ 119 | this.thrower(4100, "not a large enough spendable balance") 120 | } 121 | } 122 | } 123 | } 124 | } 125 | if(this.errorCheck.valid===true){ 126 | if(txn.type === "pay"){ 127 | if(txn.hasOwnProperty('to') && txn.hasOwnProperty('amount')){ 128 | if(!this.checkAddress(txn.to)){ 129 | this.thrower(4300, 'to must be a valid address'); 130 | } 131 | if(!this.checkInt({value:txn.amount})){ 132 | this.thrower(4300, 'amount must be a uint64 between 0 and 18446744073709551615'); 133 | } 134 | } else { 135 | this.thrower(4300, 'to and amount fields are required in Payment Transaction'); 136 | } 137 | if(txn.hasOwnProperty('closeRemainderTo')){ 138 | if( !this.checkAddress(txn.closeRemainderTo)){ 139 | this.thrower(4300, 'closeRemainderTo must be a valid CloseRemainderTo address'); 140 | } 141 | else{ 142 | this.errorCheck.warnings.push("this transaction will send all algo to "+txn.closeRemainderTo); 143 | } 144 | } 145 | 146 | this.errorCheck.info.push(`type:Payment\namount:${txn.amount}\nreceiver:${algosdk.encodeAddress(txn.to.publicKey)}\nfee:${txn.fee}`) 147 | 148 | } 149 | else if(txn.type === "keyreg"){ 150 | this.thrower(4200, 'this wallet does not support a Key Registration Txn'); 151 | } 152 | else if(txn.type === "acfg"){ 153 | if(txn.hasOwnProperty('assetIndex')){ 154 | if(!this.checkInt({value:txn.assetIndex})){ 155 | this.thrower(4300, 'assetIndex must be a uint64 between 0 and 18446744073709551615'); 156 | } 157 | this.errorCheck.info.push(`type:Asset Config\nasset id:${txn.assetIndex}\nfee:${txn.fee}`) 158 | } 159 | else if(txn.hasOwnProperty('assetDecimals') && txn.hasOwnProperty('assetDefaultFrozen') && txn.hasOwnProperty('assetTotal')){ 160 | if(!this.checkInt({value:txn.assetDecimals,max:19})){ 161 | this.thrower(4300, 'assetDecimals must be a uint32 between 0 and 19'); 162 | } 163 | if(!this.checkBoolean(txn.assetDefaultFrozen)){ 164 | this.thrower(4300, 'assetDefaultFrozen must be a boolean or undefined'); 165 | } 166 | if(!this.checkInt({value:txn.assetTotal,min:1})){ 167 | this.thrower(4300, 'assetTotal must be a uint64 between 1 and 18446744073709551615'); 168 | } 169 | this.errorCheck.info.push(`type:Asset Create\nasset total:${txn.assetTotal}\nasset decimals:${txn.assetDecimals}\nasset frozen:${txn.assetDefaultFrozen}\nfee:${txn.fee}`) 170 | } else { 171 | this.thrower(4300, 'required fields need to be filled for Asset Config, Create, or Destroy txn'); 172 | } 173 | if(txn.hasOwnProperty('assetClawback') && !this.checkAddress(txn.assetClawback)){ 174 | this.thrower(4300, 'assetClawback must be a valid address'); 175 | } 176 | if(txn.hasOwnProperty('assetFreeze') && !this.checkAddress(txn.assetFreeze)){ 177 | this.thrower(4300, 'assetFreeze must be a valid address'); 178 | } 179 | if(txn.hasOwnProperty('assetManager') && !this.checkAddress(txn.assetManager)){ 180 | this.thrower(4300, 'assetManager must be a valid address'); 181 | } 182 | if(txn.hasOwnProperty('assetReserve') && !this.checkAddress(txn.assetReserve)){ 183 | this.thrower(4300, 'assetReserve must be a valid address'); 184 | } 185 | if(txn.hasOwnProperty('assetMetadataHash') && !(this.checkString({value:txn.assetMetadataHash,min:32,max:32}) || this.checkUint8({value:txn.assetMetadataHash,min:32,max:32}))){ 186 | this.thrower(4300, 'assetMetadataHash must be a valid string or Uint8Array that is 32 bytes in length'); 187 | } 188 | if(txn.hasOwnProperty('assetName') && !this.checkString({value:txn.assetName, max:32})){ 189 | this.thrower(4300, 'assetName must be a string with a max length of 32 bytes'); 190 | } 191 | if(txn.hasOwnProperty('assetURL') && !this.checkString({value:txn.assetURL, max:96})){ 192 | this.thrower(4300, 'assetURL must be a string with a max length of 96 bytes'); 193 | } 194 | if(txn.hasOwnProperty('assetUnitName') && !this.checkString({value:txn.assetUnitName, max:8})){ 195 | this.thrower(4300, 'assetUnitName must be a string with a max length of 8 bytes'); 196 | } 197 | } 198 | else if(txn.type === "axfer"){ 199 | if(txn.hasOwnProperty('amount') && txn.hasOwnProperty('assetIndex') && txn.hasOwnProperty('to')){ 200 | if(!this.checkInt({value:txn.amount})){ 201 | this.thrower(4300, 'amount must be a uint64 between 0 and 18446744073709551615'); 202 | } 203 | if(!this.checkInt({value:txn.assetIndex})){ 204 | this.thrower(4300, 'assetIndex must be a uint64 between 0 and 18446744073709551615'); 205 | } 206 | if(!this.checkAddress(txn.to)){ 207 | this.thrower(4300, 'to must be a valid address'); 208 | } 209 | } else { 210 | this.thrower(4300, 'amount, assetIndex, and to fields are required in Asset Transfer Txn'); 211 | } 212 | if(txn.hasOwnProperty('closeRemainderTo') && !this.checkAddress(txn.closeRemainderTo)){ 213 | this.thrower(4300, 'closeRemainderTo must be a valid address'); 214 | } 215 | if(txn.hasOwnProperty('assetRevocationTarget') && !this.checkAddress(txn.assetRevocationTarget)){ 216 | this.thrower(4300, 'assetRevocationTarget must be a valid address'); 217 | } 218 | 219 | this.errorCheck.info.push(`type:Asset Transfer\nasset id:${txn.assetIndex}\namount:${txn.amount}\nreceiver:${algosdk.encodeAddress(txn.to.publicKey)}\nfee:${txn.fee}`) 220 | } 221 | else if(txn.type === "afrz"){ 222 | if(txn.hasOwnProperty('assetIndex') && txn.hasOwnProperty('freezeAccount')){ 223 | if(!this.checkInt({value:txn.assetIndex})){ 224 | this.thrower(4300, 'assetIndex must be a uint64 between 0 and 18446744073709551615'); 225 | } 226 | if(!this.checkAddress(txn.freezeAccount)){ 227 | this.thrower(4300, 'freezeAccount must be a valid address') 228 | } 229 | if(txn.hasOwnProperty('freezeState') && !this.checkBoolean(txn.freezeState)){ 230 | this.thrower(4300, 'freezeState must be a boolean'); 231 | } 232 | } else { 233 | this.thrower(4300, 'assetIndex and freezeAccount are required in Asset Freeze Txn'); 234 | } 235 | 236 | this.errorCheck.info.push(`type:Asset Freeze\nasset id:${txn.assetIndex}\nfee:${txn.fee}`) 237 | } 238 | else if(txn.type === "appl"){ 239 | //appl create 240 | if(txn.hasOwnProperty('appApprovalProgram') && txn.hasOwnProperty('appClearProgram') && txn.hasOwnProperty('appGlobalByteSlices') && txn.hasOwnProperty('appGlobalInts') && txn.hasOwnProperty('appLocalByteSlices') && txn.hasOwnProperty('appLocalInts')){ 241 | this.errorCheck.info.push(`type:Application Create\nfee:${txn.fee}`) 242 | } 243 | //appl call 244 | else if(txn.hasOwnProperty('appIndex') && txn.hasOwnProperty('appOnComplete')){ 245 | this.errorCheck.info.push(`type:Application Call\napp id:${txn.appIndex}\nfee:${txn.fee}`) 246 | } 247 | //appl update 248 | else if(txn.hasOwnProperty('appIndex') && txn.hasOwnProperty('appApprovalProgram') && txn.hasOwnProperty('appClearProgram')){ 249 | this.errorCheck.info.push(`type:Application Update\napp id:${txn.appIndex}\nfee:${txn.fee}`) 250 | } 251 | //appl clearState, closeOut, delete, noOp, optIn 252 | else if(txn.hasOwnProperty('appIndex')){ 253 | this.errorCheck.info.push(`type:Application Transaction\napp id:${txn.appIndex}\nfee:${txn.fee}`) 254 | } else{ 255 | this.thrower(4300, 'all required fields need to be filled depending on the target ApplicationTxn'); 256 | } 257 | //optional appl params 258 | if(txn.hasOwnProperty('accounts') && !this.arrayAddressCheck(txn.appAccounts)){ 259 | this.thrower(4300, 'account must be an array of valid addresses'); 260 | } 261 | if(txn.hasOwnProperty('appArgs') && !this.arrayUint8Check(txn.appArgs)){ 262 | this.thrower(4300, 'appArgs must be an array of Uint8Arrays'); 263 | } 264 | if(txn.hasOwnProperty('appApprovalProgram') && !this.checkUint8({value:txn.appApprovalProgram,max:2048})){ 265 | this.thrower(4300,'appApprovalProgram must be a Uint8Array that is less than 2048 bytes'); 266 | } 267 | if(txn.hasOwnProperty('appClearProgram') && !this.checkUint8({value:txn.appClearProgram,max:2048})){ 268 | this.thrower(4300,'appClearProgram must be a Uint8Array that is less than 2048 bytes'); 269 | } 270 | if(txn.hasOwnProperty('appGlobalByteSlices') && !this.checkInt({value:txn.appGlobalByteSlices})){ 271 | this.thrower(4300, 'appGlobalByteSlices must be a uint64 between 0 and 18446744073709551615'); 272 | } 273 | if(txn.hasOwnProperty('appGlobalInts') && !this.checkInt({value:txn.appGlobalInts})){ 274 | this.thrower(4300, 'appGlobalInts must be a uint64 between 0 and 18446744073709551615'); 275 | } 276 | if(txn.hasOwnProperty('appIndex') && !this.checkInt({value:txn.appIndex})){ 277 | this.thrower(4300, 'appIndex must be a uint64 between 0 and 18446744073709551615'); 278 | } 279 | if(txn.hasOwnProperty('appLocalByteSlices') && !this.checkInt({value:txn.appLocalByteSlices})){ 280 | this.thrower(4300, 'appLocalByteSlices must be a uint64 between 0 and 18446744073709551615'); 281 | } 282 | if(txn.hasOwnProperty('appLocalInts') && !this.checkInt({value:txn.appLocalInts})){ 283 | this.thrower(4300, 'appLocalInts must be a uint64 between 0 and 18446744073709551615'); 284 | } 285 | if(txn.hasOwnProperty('appOnComplete') && !this.checkInt({value:txn.appOnComplete,max:5})){ 286 | this.thrower(4300, 'appOnComplete must be a uint64 between 0 and 5'); 287 | } 288 | if(txn.hasOwnProperty('extraPages') && !this.checkInt({value:txn.extraPages,max:3})){ 289 | this.thrower(4300, 'extraPages must be a uint64 between 0 and 3'); 290 | } 291 | if(txn.hasOwnProperty('appForeignApps') && !this.checkIntArray(txn.appForeignApps)){ 292 | this.thrower(4300, 'appForeignApps must be an array of uint64s between 0 and 18446744073709551615'); 293 | } 294 | if(txn.hasOwnProperty('appForeignAssets') && !this.checkIntArray(txn.appForeignAssets)){ 295 | this.thrower(4300, 'appForeignAssets must be an array of uint64s between 0 and 18446744073709551615'); 296 | } 297 | } 298 | else{ 299 | this.thrower(4300, 'must specify the type of transaction'); 300 | } 301 | } 302 | 303 | return this.errorCheck; 304 | } 305 | 306 | buf264(buf){ 307 | var binstr = Array.prototype.map.call(buf, function (ch) { 308 | return String.fromCharCode(ch); 309 | }).join(''); 310 | return btoa(binstr); 311 | } 312 | checkInt(intObj){ 313 | if(!intObj.hasOwnProperty('min')){ 314 | intObj.min = 0; 315 | } 316 | if(!intObj.hasOwnProperty('max')){ 317 | intObj.max = this.max64; 318 | } 319 | if(Number.isInteger(intObj.value) && intObj.value>=intObj.min && intObj.value<=intObj.max){ 320 | return true; 321 | } return false; 322 | } 323 | checkBoolean(value){ 324 | if(typeof value === 'boolean' || typeof value === 'undefined'){ 325 | return true; 326 | } return false; 327 | } 328 | checkString(strObj){ 329 | if(!strObj.hasOwnProperty('min')){ 330 | strObj.min = 0; 331 | } 332 | if(!strObj.hasOwnProperty('max')){ 333 | strObj.max = this.max64; 334 | } 335 | if(typeof strObj.value === 'string' && strObj.value.length>=strObj.min && strObj.value.length<=strObj.max){ 336 | return true; 337 | } return false; 338 | } 339 | checkUint8(uintObj){ 340 | if(!uintObj.hasOwnProperty('min')){ 341 | uintObj.min = 0; 342 | } 343 | if(!uintObj.hasOwnProperty('max')){ 344 | uintObj.max = this.max64; 345 | } 346 | if(uintObj.value.byteLength !== 'undefined' && uintObj.value.byteLength>=uintObj.min && uintObj.value.byteLength<=uintObj.max){ 347 | return true; 348 | } return false; 349 | } 350 | checkAddress(addr){ 351 | try{ 352 | addr = algosdk.encodeAddress(addr.publicKey); 353 | } catch {} 354 | return algosdk.isValidAddress(addr); 355 | } 356 | arrayAddressCheck(array){ 357 | if(Object.prototype.toString.call(array) === '[object Array]') { 358 | for(var address of array){ 359 | if(!this.checkAddress(address)){ 360 | return false; 361 | } 362 | } 363 | return true; 364 | } 365 | return false; 366 | } 367 | arrayUint8Check(array){ 368 | if(Object.prototype.toString.call(array) === '[object Array]') { 369 | for(var arg of array){ 370 | if(arg.byteLength === 'undefined'){ 371 | return false; 372 | } 373 | } 374 | return true; 375 | } 376 | return false; 377 | } 378 | checkIntArray(array){ 379 | if(Object.prototype.toString.call(array) === '[object Array]') { 380 | for(var value of array){ 381 | if(!Number.isInteger(value) || value<0 || value>this.max64){ 382 | return false; 383 | } 384 | } 385 | return true; 386 | } 387 | return false; 388 | } 389 | thrower(code, message){ 390 | this.errorCheck.valid=false; 391 | this.errorCheck.error.push({code:code,message:message}); 392 | } 393 | } 394 | --------------------------------------------------------------------------------