├── example
└── app
│ ├── .browserslistrc
│ ├── babel.config.js
│ ├── public
│ ├── favicon.ico
│ └── index.html
│ ├── src
│ ├── assets
│ │ └── logo.png
│ ├── main.js
│ └── create.js
│ ├── .gitignore
│ └── README.md
├── src
├── connectProvider
│ ├── web3Provider
│ │ ├── helpers
│ │ │ ├── providerHelpers.js
│ │ │ ├── solidityTypes.js
│ │ │ ├── commonGenerator.js
│ │ │ ├── addressUtils.js
│ │ │ ├── parseTokensData.js
│ │ │ ├── webWorkerTimer
│ │ │ │ └── index.js
│ │ │ └── misc.js
│ │ ├── index.js
│ │ ├── web3-provider
│ │ │ ├── methods
│ │ │ │ ├── net_version.js
│ │ │ │ ├── eth_coinbase.js
│ │ │ │ ├── eth_requestAccounts.js
│ │ │ │ ├── eth_accounts.js
│ │ │ │ ├── personal_sign.js
│ │ │ │ ├── eth_sign.js
│ │ │ │ ├── index.js
│ │ │ │ ├── utils.js
│ │ │ │ ├── eth_signTypedData_v3.js
│ │ │ │ ├── personal_ecRecover.js
│ │ │ │ ├── eth_getEncryptionPublicKey.js
│ │ │ │ ├── eth_signTypedData_v4.js
│ │ │ │ ├── eth_decrypt.js
│ │ │ │ ├── eth_signTransaction.js
│ │ │ │ └── eth_sendTransaction.js
│ │ │ ├── jsonrpc.js
│ │ │ ├── middleware.js
│ │ │ ├── events.js
│ │ │ ├── index.js
│ │ │ └── providers
│ │ │ │ ├── http-request-manager.js
│ │ │ │ ├── ws-provider.js
│ │ │ │ └── http-provider.js
│ │ ├── MEWconnect
│ │ │ ├── errorHandler.js
│ │ │ └── index.js
│ │ ├── networks
│ │ │ ├── tokens
│ │ │ │ ├── tokens-etc.json
│ │ │ │ ├── tokens-boba.json
│ │ │ │ └── tokens-rop.json
│ │ │ └── types
│ │ │ │ ├── RIN.js
│ │ │ │ ├── index.js
│ │ │ │ ├── ETH.js
│ │ │ │ ├── BOBA.js
│ │ │ │ ├── BSC.js
│ │ │ │ ├── MATIC.js
│ │ │ │ ├── ROP.js
│ │ │ │ ├── GOERLI.js
│ │ │ │ ├── ETC.js
│ │ │ │ └── KOV.js
│ │ ├── HDWalletInterface.js
│ │ ├── utils.js
│ │ └── WalletInterface.js
│ ├── fetchLists
│ │ ├── configs.js
│ │ ├── fetchMainLists.js
│ │ └── index.js
│ ├── utils.js
│ └── platformDeepLinking.js
├── connectClient
│ ├── MewConnectInitiator.js
│ ├── config.js
│ ├── index.js
│ ├── constants
│ │ ├── signals.js
│ │ ├── index.js
│ │ └── constants.js
│ ├── MewConnectCrypto.js
│ ├── MewConnectCommon.js
│ └── websocketWrapper.js
├── connectWindow
│ ├── images
│ │ ├── closeIconBlack.js
│ │ ├── close.svg
│ │ ├── index.js
│ │ ├── camera.js
│ │ ├── refreshIcon.js
│ │ ├── closeIconWhite.js
│ │ └── mobile-icon.js
│ ├── designTemplates
│ │ ├── rawImages
│ │ │ ├── appstore.png
│ │ │ ├── camera.png
│ │ │ ├── spaceman.png
│ │ │ ├── logo-small.png
│ │ │ ├── times-solid (1).png
│ │ │ ├── times-solid (2).png
│ │ │ ├── button-app-store.png
│ │ │ └── button-google-play-color.png
│ │ └── popupWindow.html
│ ├── messageCreator.js
│ ├── popupHtml.js
│ └── popUpHandler.js
├── icon
│ ├── PNG
│ │ ├── c_large_mewconnect.png
│ │ ├── c_medium_mewconnect.png
│ │ ├── c_large_mewconnect@2x.png
│ │ ├── c_large_mewconnect@3x.png
│ │ ├── bw_dark_large_mewconnect.png
│ │ ├── c_medium_mewconnect@2x.png
│ │ ├── c_medium_mewconnect@3x.png
│ │ ├── bw_dark_medium_mewconnect.png
│ │ ├── bw_light_large_mewconnect.png
│ │ ├── bw_light_medium_mewconnect.png
│ │ ├── bw_dark_large_mewconnect@2x.png
│ │ ├── bw_dark_large_mewconnect@3x.png
│ │ ├── bw_dark_medium_mewconnect@2x.png
│ │ ├── bw_dark_medium_mewconnect@3x.png
│ │ ├── bw_light_large_mewconnect@2x.png
│ │ ├── bw_light_large_mewconnect@3x.png
│ │ ├── bw_light_medium_mewconnect@2x.png
│ │ └── bw_light_medium_mewconnect@3x.png
│ ├── App Icon
│ │ ├── mew_wallet_appicon@1x.png
│ │ ├── mew_wallet_appicon@2x.png
│ │ └── mew_wallet_appicon@3x.png
│ └── index.js
├── messageConstants.js
├── config.js
├── index.js
└── messages.js
├── babel.config.js
├── .prettierrc
├── assets
├── Icon
│ ├── PNG
│ │ ├── c_large_mewconnect.png
│ │ ├── c_large_mewconnect@2x.png
│ │ ├── c_large_mewconnect@3x.png
│ │ ├── c_medium_mewconnect.png
│ │ ├── c_medium_mewconnect@2x.png
│ │ ├── c_medium_mewconnect@3x.png
│ │ ├── bw_dark_large_mewconnect.png
│ │ ├── bw_dark_medium_mewconnect.png
│ │ ├── bw_light_large_mewconnect.png
│ │ ├── bw_light_medium_mewconnect.png
│ │ ├── bw_dark_large_mewconnect@2x.png
│ │ ├── bw_dark_large_mewconnect@3x.png
│ │ ├── bw_dark_medium_mewconnect@2x.png
│ │ ├── bw_dark_medium_mewconnect@3x.png
│ │ ├── bw_light_large_mewconnect@2x.png
│ │ ├── bw_light_large_mewconnect@3x.png
│ │ ├── bw_light_medium_mewconnect@2x.png
│ │ └── bw_light_medium_mewconnect@3x.png
│ └── App Icon
│ │ ├── mew_wallet_appicon@1x.png
│ │ ├── mew_wallet_appicon@2x.png
│ │ └── mew_wallet_appicon@3x.png
├── MEWconnect Protocol - Guide.pdf
├── forReadMe
│ ├── MEWconnect Protocol - Guide.png
│ ├── MEWconnect Protocol - Guide2.png
│ ├── MEWconnect Protocol - Guide3.png
│ └── MEWconnect Protocol - Guide4.png
└── README.md
├── tests
├── browser
│ ├── run.js
│ ├── browser_test.html
│ └── webpack.config.js
└── helpers
│ ├── simple-peerMock.js
│ ├── signalServerMock.js
│ └── MewConnectCryptoMock.js
├── README.md
├── test
├── jest.setup.js
├── config
│ └── index.js
├── signals
│ └── index.js
├── Unit.spec.js
├── utils
│ ├── webrtc-connection.js
│ ├── websocket-connection.js
│ └── crypto-utils.js
└── clients
│ ├── initiator.js
│ ├── turnReceiver.js
│ └── receiver.js
├── rollup.config.js
├── .nycrc
├── jest.config.js
├── LICENSE
├── .eslintrc.js
├── .npmignore
├── .github
└── workflows
│ └── npm-publish.yml
├── .gitignore
└── package.json
/example/app/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/helpers/providerHelpers.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@babel/preset-env']
3 | };
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "singleQuote": true,
4 | "trailingComma": "none"
5 | }
6 |
--------------------------------------------------------------------------------
/example/app/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/example/app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/example/app/public/favicon.ico
--------------------------------------------------------------------------------
/example/app/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/example/app/src/assets/logo.png
--------------------------------------------------------------------------------
/src/connectClient/MewConnectInitiator.js:
--------------------------------------------------------------------------------
1 | import combined from './initiator/MewConnectInitiator.js';
2 | export default combined;
3 |
--------------------------------------------------------------------------------
/src/connectWindow/images/closeIconBlack.js:
--------------------------------------------------------------------------------
1 | import closeIcon from './close.svg';
2 | const icon = closeIcon;
3 |
4 | export default icon;
5 |
--------------------------------------------------------------------------------
/src/icon/PNG/c_large_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/c_large_mewconnect.png
--------------------------------------------------------------------------------
/src/icon/PNG/c_medium_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/c_medium_mewconnect.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/c_large_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/c_large_mewconnect.png
--------------------------------------------------------------------------------
/assets/MEWconnect Protocol - Guide.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/MEWconnect Protocol - Guide.pdf
--------------------------------------------------------------------------------
/src/icon/PNG/c_large_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/c_large_mewconnect@2x.png
--------------------------------------------------------------------------------
/src/icon/PNG/c_large_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/c_large_mewconnect@3x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/c_large_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/c_large_mewconnect@2x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/c_large_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/c_large_mewconnect@3x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/c_medium_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/c_medium_mewconnect.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_dark_large_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_dark_large_mewconnect.png
--------------------------------------------------------------------------------
/src/icon/PNG/c_medium_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/c_medium_mewconnect@2x.png
--------------------------------------------------------------------------------
/src/icon/PNG/c_medium_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/c_medium_mewconnect@3x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/c_medium_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/c_medium_mewconnect@2x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/c_medium_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/c_medium_mewconnect@3x.png
--------------------------------------------------------------------------------
/src/icon/App Icon/mew_wallet_appicon@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/App Icon/mew_wallet_appicon@1x.png
--------------------------------------------------------------------------------
/src/icon/App Icon/mew_wallet_appicon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/App Icon/mew_wallet_appicon@2x.png
--------------------------------------------------------------------------------
/src/icon/App Icon/mew_wallet_appicon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/App Icon/mew_wallet_appicon@3x.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_dark_medium_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_dark_medium_mewconnect.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_light_large_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_light_large_mewconnect.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_light_medium_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_light_medium_mewconnect.png
--------------------------------------------------------------------------------
/assets/Icon/App Icon/mew_wallet_appicon@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/App Icon/mew_wallet_appicon@1x.png
--------------------------------------------------------------------------------
/assets/Icon/App Icon/mew_wallet_appicon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/App Icon/mew_wallet_appicon@2x.png
--------------------------------------------------------------------------------
/assets/Icon/App Icon/mew_wallet_appicon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/App Icon/mew_wallet_appicon@3x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_dark_large_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_dark_large_mewconnect.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_dark_medium_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_dark_medium_mewconnect.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_light_large_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_light_large_mewconnect.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_light_medium_mewconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_light_medium_mewconnect.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_dark_large_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_dark_large_mewconnect@2x.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_dark_large_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_dark_large_mewconnect@3x.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_dark_medium_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_dark_medium_mewconnect@2x.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_dark_medium_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_dark_medium_mewconnect@3x.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_light_large_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_light_large_mewconnect@2x.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_light_large_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_light_large_mewconnect@3x.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_light_medium_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_light_medium_mewconnect@2x.png
--------------------------------------------------------------------------------
/src/icon/PNG/bw_light_medium_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/icon/PNG/bw_light_medium_mewconnect@3x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_dark_large_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_dark_large_mewconnect@2x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_dark_large_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_dark_large_mewconnect@3x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_dark_medium_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_dark_medium_mewconnect@2x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_dark_medium_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_dark_medium_mewconnect@3x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_light_large_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_light_large_mewconnect@2x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_light_large_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_light_large_mewconnect@3x.png
--------------------------------------------------------------------------------
/assets/forReadMe/MEWconnect Protocol - Guide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/forReadMe/MEWconnect Protocol - Guide.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_light_medium_mewconnect@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_light_medium_mewconnect@2x.png
--------------------------------------------------------------------------------
/assets/Icon/PNG/bw_light_medium_mewconnect@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/Icon/PNG/bw_light_medium_mewconnect@3x.png
--------------------------------------------------------------------------------
/assets/forReadMe/MEWconnect Protocol - Guide2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/forReadMe/MEWconnect Protocol - Guide2.png
--------------------------------------------------------------------------------
/assets/forReadMe/MEWconnect Protocol - Guide3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/forReadMe/MEWconnect Protocol - Guide3.png
--------------------------------------------------------------------------------
/assets/forReadMe/MEWconnect Protocol - Guide4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/assets/forReadMe/MEWconnect Protocol - Guide4.png
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/rawImages/appstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/connectWindow/designTemplates/rawImages/appstore.png
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/rawImages/camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/connectWindow/designTemplates/rawImages/camera.png
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/rawImages/spaceman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/connectWindow/designTemplates/rawImages/spaceman.png
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/rawImages/logo-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/connectWindow/designTemplates/rawImages/logo-small.png
--------------------------------------------------------------------------------
/example/app/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import App from './App.vue';
3 |
4 | Vue.config.productionTip = false;
5 |
6 | new Vue({
7 | render: h => h(App)
8 | }).$mount('#app');
9 |
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/rawImages/times-solid (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/connectWindow/designTemplates/rawImages/times-solid (1).png
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/rawImages/times-solid (2).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/connectWindow/designTemplates/rawImages/times-solid (2).png
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/index.js:
--------------------------------------------------------------------------------
1 | import WalletInterface from './WalletInterface';
2 | import { MewConnectWallet } from './MEWconnect';
3 |
4 | export { MewConnectWallet, WalletInterface };
5 |
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/rawImages/button-app-store.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/connectWindow/designTemplates/rawImages/button-app-store.png
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/rawImages/button-google-play-color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyEtherWallet/MEWconnect-web-client/HEAD/src/connectWindow/designTemplates/rawImages/button-google-play-color.png
--------------------------------------------------------------------------------
/src/connectWindow/images/close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/browser/run.js:
--------------------------------------------------------------------------------
1 | const open = require('opn');
2 |
3 | // /usr/bin/env node
4 |
5 | var separator = process.platform=="win32" ? "\\" : "/";
6 | open(require('path').dirname(require.main.filename)+separator+".."+separator+"index.html");
7 |
--------------------------------------------------------------------------------
/src/connectProvider/fetchLists/configs.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | MAIN_LISTS_PATH: './src/connectProvider/fetchLists/lists',
3 | TOKENS_PATH: './src/connectProvider/web3Provider/networks/tokens',
4 | SUPPORTED_CHAINS: ['eth', 'rop', 'matic', 'bsc', 'etc']
5 | };
6 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/helpers/solidityTypes.js:
--------------------------------------------------------------------------------
1 | const uint = 'uint';
2 | const address = 'address';
3 | const string = 'string';
4 | const bytes32 = 'bytes32[]';
5 | const bytes = 'bytes';
6 | const bool = 'bool';
7 |
8 | export { uint, address, string, bytes32, bytes, bool };
9 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/net_version.js:
--------------------------------------------------------------------------------
1 | import { toPayload } from '../jsonrpc';
2 |
3 | export default async ({ payload, store }, res, next) => {
4 | if (payload.method !== 'net_version') return next();
5 | res(null, toPayload(payload.id, store.state.network.chainID));
6 | };
7 |
--------------------------------------------------------------------------------
/example/app/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/MEWconnect/errorHandler.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default popUpHandler => {
3 | return err => {
4 | if (err.reject) {
5 | popUpHandler.showNotice('decline');
6 | } else {
7 | popUpHandler.showNotice('error');
8 | console.error(err);
9 | }
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [MEWconnect Demo](https://myetherwallet.github.io/MEWconnect-web-client/#/home)
2 |
3 |
4 | **Documentation for MEWconnect-web-client can be found [here](https://myetherwallet.github.io/MEWconnect-Protocol-Documentation/)**
5 |
6 | [Previous README documentation](https://github.com/MyEtherWallet/MEWconnect-web-client/blob/master/OLD_README.md)
7 |
--------------------------------------------------------------------------------
/test/jest.setup.js:
--------------------------------------------------------------------------------
1 | import 'regenerator-runtime/runtime';
2 | const path = require('path');
3 | function noOp() {}
4 | if (typeof window.URL.createObjectURL === 'undefined') {
5 | Object.defineProperty(window.URL, 'createObjectURL', { value: noOp });
6 | }
7 | window.Worker = noOp;
8 | require('dotenv').config({ path: path.resolve(process.cwd(), '.env.test') });
9 |
--------------------------------------------------------------------------------
/example/app/README.md:
--------------------------------------------------------------------------------
1 | # popup
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Customize configuration
19 | See [Configuration Reference](https://cli.vuejs.org/config/).
20 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/tokens/tokens-etc.json:
--------------------------------------------------------------------------------
1 | [{"symbol":"BEC","address":"0x085fb4f24031EAedbC2B611AA528f22343eB52Db","decimals":8},{"symbol":"PLAY","address":"0x5acE17f87c7391E5792a7683069A8025B83bbd85","decimals":0},{"symbol":"UVC","address":"0x76d0184CF511788032A74a1FB91146e63F43dd53","decimals":5},{"symbol":"UVCX","address":"0xd6dF0C579f2A65049a893fDaEC9fCE098CC19F87","decimals":18}]
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/RIN.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'RIN',
3 | name_long: 'Rinkeby',
4 | homePage: 'https://www.rinkeby.io/',
5 | blockExplorerTX: 'https://rinkeby.etherscan.io/tx/[[txHash]]',
6 | blockExplorerAddr: 'https://rinkeby.etherscan.io/address/[[address]]',
7 | chainID: 4,
8 | tokens: [],
9 | contracts: [],
10 | currencyName: 'RIN'
11 | };
12 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/index.js:
--------------------------------------------------------------------------------
1 | import ETH from './ETH.js';
2 | import GOERLI from './GOERLI.js';
3 | import KOV from './KOV.js';
4 | import ROP from './ROP';
5 | import MATIC from './MATIC';
6 | import BSC from './BSC';
7 | import ETC from './ETC';
8 | import RIN from './RIN';
9 | import BOBA from './BOBA';
10 | export { ETH, GOERLI, KOV, ROP, MATIC, BSC, ETC, RIN, BOBA };
11 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/helpers/commonGenerator.js:
--------------------------------------------------------------------------------
1 | import Common from 'ethereumjs-common';
2 |
3 | const commonGenerator = network => {
4 | const customCommon = Common.forCustomChain('mainnet', {
5 | name: network.name_long,
6 | chainId: network.chainID
7 | });
8 | return new Common(customCommon._chainParams, 'petersburg', ['petersburg']);
9 | };
10 |
11 | export default commonGenerator;
12 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/jsonrpc.js:
--------------------------------------------------------------------------------
1 | const toPayload = (id, result) => {
2 | return {
3 | jsonrpc: '2.0',
4 | id,
5 | result
6 | };
7 | };
8 | const toError = (id, msg, code) => {
9 | return {
10 | jsonrpc: '2.0',
11 | id,
12 | error: {
13 | code: code ? code : -32603,
14 | message: msg
15 | }
16 | };
17 | };
18 | export { toPayload, toError };
19 |
--------------------------------------------------------------------------------
/src/messageConstants.js:
--------------------------------------------------------------------------------
1 | const messages = {
2 | decline: 'decline',
3 | approveTx: 'approveTx',
4 | disconnect: 'disconnect',
5 | complete: 'complete',
6 | sent: 'sent',
7 | failed: 'failed',
8 | signMessage: 'signMessage',
9 | error: 'error',
10 | notConnected: 'notConnected',
11 | declineMessage: 'declineSignMessage',
12 | communicationError: 'communicationError'
13 | };
14 |
15 | export default messages;
16 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | const IOS_LINK =
2 | 'https://apps.apple.com/app/apple-store/id1464614025?pt=118781877&ct=mc&mt=8';
3 | const ANDROID_LINK =
4 | 'https://play.google.com/store/apps/details?id=com.myetherwallet.mewwallet&referrer=utm_source%3Dmc';
5 | const DISCONNECTED = 'disconnected';
6 | const CONNECTING = 'connecting';
7 | const CONNECTED = 'connected';
8 |
9 | export { IOS_LINK, ANDROID_LINK, DISCONNECTED, CONNECTED, CONNECTING };
10 |
--------------------------------------------------------------------------------
/src/connectClient/config.js:
--------------------------------------------------------------------------------
1 | const packageJSON = require('../../package.json');
2 |
3 | const env = 'production';
4 | const version = packageJSON.version;
5 | const V1endpoint = 'https://connect.mewapi.io';
6 | const V2endpoint = 'wss://connect2.mewapi.io/staging';
7 |
8 | const stunServers = [
9 | { urls: 'stun:global.stun.twilio.com:3478?transport=udp' }
10 | ];
11 |
12 | export { env, version, stunServers, V1endpoint, V2endpoint };
13 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/ETH.js:
--------------------------------------------------------------------------------
1 | import tokens from '../tokens/tokens-eth.json';
2 |
3 | export default {
4 | name: 'ETH',
5 | name_long: 'Ethereum',
6 | homePage: 'https://ethereum.org',
7 | blockExplorerTX: 'https://etherscan.io/tx/[[txHash]]',
8 | blockExplorerAddr: 'https://etherscan.io/address/[[address]]',
9 | chainID: 1,
10 | tokens: tokens,
11 | contracts: [],
12 | currencyName: 'ETH'
13 | };
14 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_coinbase.js:
--------------------------------------------------------------------------------
1 | import { toError, toPayload } from '../jsonrpc';
2 |
3 | export default async ({ payload, store }, res, next) => {
4 | if (payload.method !== 'eth_coinbase') return next();
5 | if (store.state.wallet) {
6 | res(null, toPayload(payload.id, store.state.wallet.getAddressString()));
7 | } else {
8 | res(toError(payload.id, 'No active wallet', 4002));
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/BOBA.js:
--------------------------------------------------------------------------------
1 | import tokens from '../tokens/tokens-boba.json';
2 | export default {
3 | name: 'Boba',
4 | name_long: 'Boba',
5 | homePage: 'https://boba.network',
6 | blockExplorerTX: 'https://blockexplorer.boba.network/tx/[[txHash]]',
7 | blockExplorerAddr: 'https://blockexplorer.boba.network/address/[[address]]',
8 | chainID: 288,
9 | tokens: tokens,
10 | contracts: [],
11 | currencyName: 'oETH'
12 | };
13 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/BSC.js:
--------------------------------------------------------------------------------
1 | import tokens from '../tokens/tokens-bsc.json';
2 | export default {
3 | name: 'BSC',
4 | name_long: 'Binance Smart Chain',
5 | homePage: 'https://www.binance.org/en/smartChain',
6 | blockExplorerTX: 'https://bscscan.com/tx/[[txHash]]',
7 | blockExplorerAddr: 'https://bscscan.com/address/[[address]]',
8 | chainID: 56,
9 | tokens: tokens,
10 | contracts: [],
11 | currencyName: 'BNB'
12 | };
13 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/MATIC.js:
--------------------------------------------------------------------------------
1 | import tokens from '../tokens/tokens-matic.json';
2 | export default {
3 | name: 'MATIC',
4 | name_long: 'Polygon (Matic)',
5 | homePage: 'https://polygonscan.com/',
6 | blockExplorerTX: 'https://polygonscan.com/tx/[[txHash]]',
7 | blockExplorerAddr: 'https://polygonscan.com/address/[[address]]',
8 | chainID: 137,
9 | tokens: tokens,
10 | contracts: [],
11 | currencyName: 'MATIC'
12 | };
13 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/ROP.js:
--------------------------------------------------------------------------------
1 | import tokens from '../tokens/tokens-rop.json';
2 |
3 | export default {
4 | name: 'ROP',
5 | name_long: 'Ropsten',
6 | homePage: 'https://github.com/ethereum/ropsten',
7 | blockExplorerTX: 'https://ropsten.etherscan.io/tx/[[txHash]]',
8 | blockExplorerAddr: 'https://ropsten.etherscan.io/address/[[address]]',
9 | chainID: 3,
10 | tokens: tokens,
11 | contracts: [],
12 | currencyName: 'ROP'
13 | };
14 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/GOERLI.js:
--------------------------------------------------------------------------------
1 | // import tokens from '@/tokens/tokens-goerli.json';
2 |
3 | export default {
4 | name: 'GOERLI',
5 | name_long: 'Goerli',
6 | homePage: 'https://github.com/goerli/testnet',
7 | blockExplorerTX: 'https://goerli.etherscan.io/tx/[[txHash]]',
8 | blockExplorerAddr: 'https://goerli.etherscan.io/address/[[address]]',
9 | chainID: 5,
10 | tokens: [],
11 | contracts: [],
12 | currencyName: 'GöETH'
13 | };
14 |
--------------------------------------------------------------------------------
/src/connectProvider/utils.js:
--------------------------------------------------------------------------------
1 | export function isLocalStorageBlocked() {
2 | try {
3 | localStorage.getItem('test');
4 | } catch (err) {
5 | return true;
6 | }
7 | return false;
8 | }
9 |
10 | export function postMessageToParent(message, origin = '*') {
11 | if (window.opener) {
12 | window.opener.postMessage(message, origin);
13 | return;
14 | }
15 | if (window.parent !== window) {
16 | window.parent.postMessage(message, origin);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/ETC.js:
--------------------------------------------------------------------------------
1 | import tokens from '../tokens/tokens-etc.json';
2 | export default {
3 | name: 'ETC',
4 | name_long: 'Ethereum Classic',
5 | homePage: 'https://ethereumclassic.org/',
6 | blockExplorerTX: 'https://blockscout.com/etc/mainnet/tx/[[txHash]]',
7 | blockExplorerAddr: 'https://blockscout.com/etc/mainnet/address/[[address]]',
8 | chainID: 61,
9 | tokens: tokens,
10 | contracts: [],
11 | currencyName: 'ETC'
12 | };
13 |
--------------------------------------------------------------------------------
/test/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import wrtc from 'wrtc';
4 |
5 | const stunServers = [{ urls: 'stun:global.stun.twilio.com:3478?transport=udp' }];
6 | const websocketURL = process.env.WEBSOCKET_URL || 'wss://connect2.mewapi.io/staging'
7 | const webRTCOptions = {
8 | trickle: false,
9 | iceTransportPolicy: 'relay',
10 | config: {
11 | iceServers: stunServers
12 | },
13 | wrtc: wrtc
14 | };
15 |
16 | export { stunServers, websocketURL, webRTCOptions };
17 |
--------------------------------------------------------------------------------
/src/icon/index.js:
--------------------------------------------------------------------------------
1 | import bwDarkLarge from './SVG/bw_dark_large_mewconnect.svg';
2 | import bwDarkMedium from './SVG/bw_dark_medium_mewconnect.svg';
3 | import bwLightLarge from './SVG/bw_light_large_mewconnect.svg';
4 | import bwLightMedium from './SVG/bw_light_medium_mewconnect.svg';
5 | import large from './SVG/c_large_mewconnect.svg';
6 | import medium from './SVG/c_medium_mewconnect.svg';
7 |
8 | export default {
9 | bwDarkLarge,
10 | bwDarkMedium,
11 | bwLightLarge,
12 | bwLightMedium,
13 | large,
14 | medium
15 | };
16 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import json from '@rollup/plugin-json';
2 | import image from '@rollup/plugin-image';
3 | import { babel } from '@rollup/plugin-babel';
4 | import commonjs from '@rollup/plugin-commonjs';
5 | export default {
6 | input: 'src/index.js',
7 | output: [
8 | {
9 | format: 'esm',
10 | dir: 'dist/esm/'
11 | },
12 | { format: 'cjs', dir: 'dist/cjs/' }
13 | ],
14 | plugins: [
15 | json(),
16 | image(),
17 | commonjs({
18 | include: /node_modules/
19 | }),
20 | babel()
21 | ]
22 | };
23 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/helpers/addressUtils.js:
--------------------------------------------------------------------------------
1 | import web3 from 'web3';
2 |
3 | const isAddress = address => {
4 | if (!/^(0x)?[0-9a-f]{40}$/i.test(address)) {
5 | return false;
6 | } else if (
7 | /^(0x|0X)?[0-9a-f]{40}$/.test(address) ||
8 | /^(0x|0X)?[0-9A-F]{40}$/.test(address)
9 | ) {
10 | return true;
11 | }
12 | return web3.utils.checkAddressChecksum(address);
13 | };
14 | const toChecksumAddress = address => {
15 | return web3.utils.toChecksumAddress(address);
16 | };
17 | export { isAddress, toChecksumAddress };
18 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/middleware.js:
--------------------------------------------------------------------------------
1 | class Middleware {
2 | constructor() {
3 | this.middlewares = [];
4 | }
5 |
6 | use(fn) {
7 | this.middlewares.push(fn);
8 | }
9 |
10 | executeMiddleware(req, res, done) {
11 | this.middlewares.reduceRight(
12 | (done, next) => () => next(req, res, done),
13 | done
14 | )(req, res);
15 | }
16 |
17 | run(req, res) {
18 | return new Promise(resolve => {
19 | this.executeMiddleware(req, res, resolve);
20 | });
21 | }
22 | }
23 |
24 | export default Middleware;
25 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/events.js:
--------------------------------------------------------------------------------
1 | export default {
2 | SHOW_WEB3_CONFIRM_MODAL: 'showWeb3Wallet',
3 | SHOW_TX_CONFIRM_MODAL: 'showTxConfirmModal',
4 | SHOW_MSG_CONFIRM_MODAL: 'showMessageConfirmModal',
5 | SHOW_TX_SIGN_MODAL: 'showTxSignModal',
6 | GET_ENCRYPTED_PUBLIC_KEY: 'eth_getEncryptionPublicKey',
7 | DECRYPT: 'eth_decrypt',
8 | SIGN_TYPE_DATA_V3: 'eth_signTypedData_v3',
9 | SIGN_TYPE_DATA_V4: 'eth_signTypedData_v4',
10 | SIGN_TYPE_DATA: 'eth_signTypedData',
11 | WALLET_NOT_CONNECTED: 'walletNotConnected',
12 | ERROR_NOTIFY: 'errorNotify'
13 | };
14 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_requestAccounts.js:
--------------------------------------------------------------------------------
1 | import { toPayload } from '../jsonrpc';
2 |
3 | export default async ({ payload, store }, res, next) => {
4 | if (payload.method !== 'eth_requestAccounts') return next();
5 | if (store.state.wallet) {
6 | res(null, toPayload(payload.id, [store.state.wallet.getAddressString()]));
7 | } else {
8 | try {
9 | store.state.enable().then(accounts => {
10 | res(null, toPayload(payload.id, accounts));
11 | });
12 | } catch (e) {
13 | res(null, toPayload(payload.id, []));
14 | }
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/types/KOV.js:
--------------------------------------------------------------------------------
1 | // import tokens from '@/tokens/tokens-kov.json';
2 | // import contracts from '@/contracts/contract-abi-kov.json';
3 | // import kov from '@/assets/images/icons/network.svg';
4 |
5 | export default {
6 | name: 'KOV',
7 | name_long: 'Kovan',
8 | homePage: 'https://kovan-testnet.github.io/website/',
9 | blockExplorerTX: 'https://kovan.etherscan.io/tx/[[txHash]]',
10 | blockExplorerAddr: 'https://kovan.etherscan.io/address/[[address]]',
11 | chainID: 42,
12 | tokens: [],
13 | contracts: [],
14 | // icon: kov,
15 | currencyName: 'KOV'
16 | };
17 |
--------------------------------------------------------------------------------
/assets/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 
4 |
5 | 
6 |
7 | 
8 |
9 | 
--------------------------------------------------------------------------------
/src/connectClient/index.js:
--------------------------------------------------------------------------------
1 | // INITIATOR CLIENT
2 | // The initiator client is the integration end of the connection,
3 | // and sends the connection details to
4 | // the signal server which then waits for a corresponding receiver connection.
5 |
6 | // CRYPTO
7 | // the crypto constructor is a collection of methods used by both the initiator and receiver
8 | // in creating the direct connection
9 |
10 | import MewConnectInitiator from './MewConnectInitiator';
11 | import MewConnectCrypto from './MewConnectCrypto';
12 |
13 | export default {
14 | Crypto: MewConnectCrypto,
15 | Initiator: MewConnectInitiator
16 | };
17 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_accounts.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | import { toPayload } from '../jsonrpc';
4 |
5 | export default async ({ payload, store }, res, next) => {
6 | if (payload.method !== 'eth_accounts') return next();
7 | if (store.state.wallet) {
8 | res(null, toPayload(payload.id, [store.state.wallet.getAddressString()]));
9 | } else {
10 | try {
11 | store.state.enable().then(accounts => {
12 | res(null, toPayload(payload.id, accounts));
13 | });
14 | } catch (e) {
15 | res(null, toPayload(payload.id, []));
16 | }
17 | }
18 | };
19 |
--------------------------------------------------------------------------------
/src/connectWindow/images/index.js:
--------------------------------------------------------------------------------
1 | import logoMEW from './logoImage';
2 | import logo from './mobile-icon';
3 | import spaceman from './spaceman';
4 | import refresh from './refreshIcon';
5 | import playStoreButton from './button-google-play-color';
6 | import appStoreButton from './button-app-store';
7 | import camera from './camera';
8 | import closeIconWhite from './closeIconWhite';
9 | import closeIconBlack from './closeIconBlack';
10 |
11 | export {
12 | logoMEW,
13 | logo,
14 | refresh,
15 | spaceman,
16 | playStoreButton,
17 | appStoreButton,
18 | camera,
19 | closeIconWhite,
20 | closeIconBlack
21 | };
22 |
--------------------------------------------------------------------------------
/example/app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | popup
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/connectProvider/fetchLists/fetchMainLists.js:
--------------------------------------------------------------------------------
1 | const configs = require('./configs');
2 | const fetch = require('node-fetch');
3 | const fs = require('fs');
4 |
5 | const fetchLists = async () => {
6 | const tokenList = await fetch(
7 | 'https://api.github.com/repos/MyEtherWallet/ethereum-lists/contents/dist/tokens'
8 | )
9 | .then(res => res.json())
10 | .catch(console.error);
11 | fs.writeFileSync(
12 | configs.MAIN_LISTS_PATH + '/tokens.json',
13 | JSON.stringify(tokenList)
14 | );
15 | };
16 |
17 | (async () => {
18 | try {
19 | await fetchLists();
20 | console.log('Done');
21 | } catch (e) {
22 | console.error(e);
23 | }
24 | })();
25 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/index.js:
--------------------------------------------------------------------------------
1 | import WSProvider from './providers/ws-provider';
2 | import HttpProvider from './providers/http-provider';
3 | class MEWProvider {
4 | constructor(host, options, store, eventHub) {
5 | if (host && typeof host === 'string') {
6 | if (/^http(s)?:\/\//i.test(host)) {
7 | store.noSubs = true;
8 | return new HttpProvider(host, options, store, eventHub);
9 | } else if (/^ws(s)?:\/\//i.test(host)) {
10 | return new WSProvider(host, options, store, eventHub);
11 | } else if (host) {
12 | throw new Error('Can\'t autodetect provider for "' + host + '"');
13 | }
14 | }
15 | }
16 | }
17 |
18 | export default MEWProvider;
19 |
--------------------------------------------------------------------------------
/.nycrc:
--------------------------------------------------------------------------------
1 | {
2 | "description": "These are just examples for demonstration, nothing prescriptive",
3 | "nyc": {
4 | "check-coverage": true,
5 | "per-file": true,
6 | "lines": 99,
7 | "statements": 99,
8 | "functions": 99,
9 | "branches": 99,
10 | "include": [
11 | "src/**/*.js"
12 | ],
13 | "exclude": [
14 | "src/**/*.spec.js"
15 | ],
16 | "ignore-class-method": "methodToIgnore",
17 | "reporter": [
18 | "lcov",
19 | "text-summary"
20 | ],
21 | "require": [
22 | "./test/helpers/some-helper.js"
23 | ],
24 | "extension": [
25 | ".jsx"
26 | ],
27 | "cache": true,
28 | "all": true,
29 | "temp-directory": "./alternative-tmp",
30 | "report-dir": "./alternative"
31 | }
32 | }
--------------------------------------------------------------------------------
/tests/browser/browser_test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mocha Tests
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // INITIATOR CLIENT
2 | // The initiator client is the integration end of the connection,
3 | // and sends the connection details to
4 | // the signal server which then waits for a corresponding receiver connection.
5 |
6 | // CRYPTO
7 | // the crypto constructor is a collection of methods used by both the initiator and receiver
8 | // in creating the direct connection
9 | import 'core-js/stable';
10 | import 'regenerator-runtime/runtime';
11 | import MewConnectClient from './connectClient/index';
12 | import MewConnectProvider from './connectProvider/index';
13 | // import icons from './icon';
14 |
15 | export default {
16 | Initiator: MewConnectClient.Initiator,
17 | Crypto: MewConnectClient.Crypto,
18 | Client: MewConnectClient,
19 | Provider: MewConnectProvider
20 | // icons
21 | };
22 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/personal_sign.js:
--------------------------------------------------------------------------------
1 | import EventNames from '../events';
2 | import { toError, toPayload } from '../jsonrpc';
3 | import misc from '../../helpers/misc';
4 | import debugLogger from 'debug';
5 | const debug = debugLogger('MEWconnectWeb3');
6 |
7 | export default async ({ payload, eventHub }, res, next) => {
8 | if (payload.method !== 'personal_sign') return next();
9 | const msg = payload.params[0];
10 | eventHub.emit(EventNames.SHOW_MSG_CONFIRM_MODAL, msg, _response => {
11 | if (_response.reject) {
12 | debug('USER DECLINED PERSONAL SIGN');
13 | res(toError(payload.id, 'User Rejected Request', 4001));
14 | return;
15 | }
16 | _response = misc.sanitizeHex(_response.toString('hex'));
17 | res(null, toPayload(payload.id, _response));
18 | });
19 | };
20 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | verbose: true,
3 | /* clearMocks: true,
4 | collectCoverage: true,
5 | setTimeout: 10000,
6 | coverageDirectory: 'coverage',*/
7 | testEnvironment: 'jsdom',
8 | testMatch: ['**/__tests__/**/*.js?(x)', '**/tests/**/?(*.)+(spec|test).js?(x)', '**/test/**/?(*.)+(spec|test).js?(x)'],
9 | testPathIgnorePatterns: ['/node_modules/'],
10 | // "testEnvironment": "node",
11 | /* transform: {
12 | "^.+\\.(js) ? $": "babel-jest"
13 | },*/
14 | "setupFiles": [
15 | "/test/jest.setup.js"
16 | ],
17 | "moduleNameMapper": {
18 | "@signals(.*)$": "/test/signals$1",
19 | "@clients(.*)$": "/test/clients$1",
20 | "@config(.*)$": "/test/config$1",
21 | "@utils(.*)$": "/test/utils$1",
22 | "@/(.*)$": "dist$1"
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_sign.js:
--------------------------------------------------------------------------------
1 | import EventNames from '../events';
2 | import { toError, toPayload } from '../jsonrpc';
3 | import misc from '../../helpers/misc';
4 | import debugLogger from 'debug';
5 | const debug = debugLogger('MEWconnectWeb3');
6 |
7 | export default async ({ payload, eventHub }, res, next) => {
8 | if (payload.method !== 'eth_sign') return next();
9 | const msg = payload.params[1];
10 | eventHub.emit(EventNames.SHOW_MSG_CONFIRM_MODAL, msg, _response => {
11 | if (_response.reject) {
12 | debug('USER DECLINED SIGN MESSAGE');
13 | res(toError(payload.id, 'User Rejected Request', 4001));
14 | return;
15 | }
16 | _response = misc.sanitizeHex(_response.toString('hex'));
17 | debug('sign result', _response);
18 | res(null, toPayload(payload.id, _response));
19 | });
20 | };
21 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/HDWalletInterface.js:
--------------------------------------------------------------------------------
1 | import WalletInterface from './WalletInterface';
2 |
3 | class HDWalletInterface extends WalletInterface {
4 | constructor(
5 | path,
6 | pubkey,
7 | isHardware,
8 | identifier,
9 | errorHandler,
10 | txSigner,
11 | msgSigner,
12 | displayAddress
13 | ) {
14 | super(pubkey, true, identifier);
15 | this.path = path;
16 | this.txSigner = txSigner;
17 | this.msgSigner = msgSigner;
18 | this.isHardware = isHardware;
19 | this.errorHandler = errorHandler;
20 | this.displayAddress = displayAddress;
21 | }
22 |
23 | signTransaction(txParams) {
24 | return super.signTransaction(txParams, this.txSigner);
25 | }
26 |
27 | signMessage(msg) {
28 | return super.signMessage(msg, this.msgSigner);
29 | }
30 | }
31 |
32 | export default HDWalletInterface;
33 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/providers/http-request-manager.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { Manager as Web3RequestManager } from 'web3-core-requestmanager';
3 | class HttpRequestManager {
4 | constructor(host, options) {
5 | options = options || {};
6 | this.host = host;
7 | const config = {
8 | timeout: options.timeout || 15000,
9 | headers: { 'Content-Type': 'application/json' }
10 | };
11 | if (options.headers) {
12 | options.headers.forEach(header => {
13 | config.headers[header.name] = header.value;
14 | });
15 | }
16 | this.request = axios.create(config);
17 | return new Web3RequestManager(this);
18 | }
19 | send(payload, callback) {
20 | this.request
21 | .post(this.host, payload)
22 | .then(result => {
23 | callback(null, result.data);
24 | })
25 | .catch(err => {
26 | callback(err);
27 | });
28 | }
29 | disconnect() {}
30 | }
31 | export default HttpRequestManager;
32 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/index.js:
--------------------------------------------------------------------------------
1 | import ethSendTransaction from './eth_sendTransaction';
2 | import ethSign from './eth_sign';
3 | import ethAccounts from './eth_accounts';
4 | import ethCoinbase from './eth_coinbase';
5 | import ethSignTransaction from './eth_signTransaction';
6 | import netVersion from './net_version';
7 | import personalSign from './personal_sign';
8 | import ecRecover from './personal_ecRecover';
9 | import getEncryptionPublicKey from './eth_getEncryptionPublicKey';
10 | import decrypt from './eth_decrypt';
11 | import signTypedData_v3 from './eth_signTypedData_v3';
12 | import signTypedData_v4 from './eth_signTypedData_v4';
13 | import ethRequestAccounts from './eth_requestAccounts';
14 |
15 | export {
16 | ethSendTransaction,
17 | ethSign,
18 | personalSign,
19 | ecRecover,
20 | ethAccounts,
21 | ethCoinbase,
22 | ethSignTransaction,
23 | netVersion,
24 | getEncryptionPublicKey,
25 | decrypt,
26 | signTypedData_v3,
27 | signTypedData_v4,
28 | ethRequestAccounts
29 | };
30 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/utils.js:
--------------------------------------------------------------------------------
1 | import { formatters } from 'web3-core-helpers';
2 |
3 | const getSanitizedTx = tx => {
4 | return new Promise((resolve, reject) => {
5 | if (!tx.gas && !tx.gasLimit && !tx.chainId)
6 | return reject(new Error('"gas" or "chainId" is missing'));
7 | if (
8 | tx.nonce < 0 ||
9 | tx.gas < 0 ||
10 | tx.gasPrice < 0 ||
11 | !tx.gasPrice ||
12 | tx.chainId < 0
13 | )
14 | return reject(
15 | new Error(
16 | 'Gas, gasPrice, nonce or chainId is lower than 0 or "gasPrice" is missing '
17 | )
18 | );
19 |
20 | try {
21 | tx = formatters.inputCallFormatter(tx);
22 | const transaction = tx;
23 | if (tx.to) transaction.to = tx.to;
24 | transaction.data = tx.data || '0x';
25 | transaction.value = tx.value || '0x';
26 | transaction.chainId = tx.chainId;
27 | resolve(transaction);
28 | } catch (e) {
29 | reject(e);
30 | }
31 | });
32 | };
33 | ``;
34 | export { getSanitizedTx };
35 |
--------------------------------------------------------------------------------
/src/connectWindow/messageCreator.js:
--------------------------------------------------------------------------------
1 | import { messages } from '../messages';
2 | export function getMessage(text, extra) {
3 | if (extra) {
4 | switch (extra.type) {
5 | case 'sent':
6 | return `${
7 | messages[extra.type]
8 | }
View details`;
12 | case 'failed':
13 | return `${
14 | messages[extra.type]
15 | }
View details`;
19 | case 'nonStandardMessage':
20 | return extra.message;
21 | }
22 | }
23 |
24 | const regEx = new RegExp(/^Returned error:/);
25 | if (regEx.test(text)) {
26 | return text;
27 | }
28 |
29 | if (!text) {
30 | return messages.defaultMessage;
31 | }
32 |
33 | return messages[text];
34 | }
35 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_signTypedData_v3.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import { toError, toPayload } from '../jsonrpc';
3 | import EventNames from '../events';
4 | import debugLogger from 'debug';
5 | const debug = debugLogger('MEWconnectWeb3');
6 | const debugErrors = debugLogger('MEWconnectError');
7 |
8 | export default async ({ payload, eventHub }, res, next) => {
9 | if (payload.method !== 'eth_signTypedData_v3') return next();
10 | try {
11 | eventHub.emit(
12 | EventNames.SIGN_TYPE_DATA_V3,
13 | payload.params[1],
14 | _response => {
15 | if (_response.reject) {
16 | debug('USER DECLINED SIGN TYPED DATA');
17 | res(toError(payload.id, 'User Rejected Request', 4001));
18 | return;
19 | }
20 | debug('eth_signTypedData_v3 response', payload.method, _response);
21 | res(null, toPayload(payload.id, _response));
22 | }
23 | );
24 | } catch (e) {
25 | debugErrors(e);
26 | debugErrors('Error: eth_signTypedData_v3', e);
27 | res(e);
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/personal_ecRecover.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import misc from '../../helpers/misc';
3 | import { toError, toPayload } from '../jsonrpc';
4 | import utils from 'ethereumjs-utils';
5 |
6 | export default async ({ payload }, res, next) => {
7 | if (payload.method !== 'personal_ecRecover') return next();
8 | if (payload.params.length < 2) {
9 | res(
10 | toError(
11 | payload.id,
12 | `personal_ecRecover expects 2 parameters. Received ${payload.params.length} `
13 | )
14 | );
15 | }
16 | const parts = utils.fromRpcSig(payload.params[1]);
17 | if (!parts) {
18 | res(
19 | toError(payload.id, 'Invalid signature supplied to personal_ecRecover')
20 | );
21 | }
22 | const recovered = utils.ecrecover(
23 | utils.hashPersonalMessage(misc.toBuffer(payload.params[0])),
24 | parts.v,
25 | parts.r,
26 | parts.s
27 | );
28 | const addressBuffer = utils.pubToAddress(recovered);
29 |
30 | res(null, toPayload(payload.id, '0x' + addressBuffer.toString('hex')));
31 | };
32 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/tokens/tokens-boba.json:
--------------------------------------------------------------------------------
1 | [{"symbol":"OMG","address":"0xe1E2ec9a85C607092668789581251115bCBD20de","decimals":18},{"symbol":"USDT",
2 | "address":"0x5DE1677344D3Cb0D7D465c10b72A8f60699C062d","decimals":6},{"symbol":"DAI","address":"0xf74195Bb8a5cf652411867c5C2C5b8C2a402be35",
3 | "decimals":18},{"symbol":"USDC","address":"0x66a2A913e447d6b4BF33EFbec43aAeF87890FBbc","decimals":6},{"symbol":"WBTC",
4 | "address":"0xdc0486f8bf31DF57a952bcd3c1d3e166e3d9eC8b","decimals":8},{"symbol":"REPv2","address":"0x8b5B1E971862015bc058234FC11ce6C4a4c536dD",
5 | "decimals":18},{"symbol":"BAT","address":"0xc0C16dF1ee7dcEFb88C55003C49F57AA416A3578","decimals":18},{"symbol":"ZRX",
6 | "address":"0xf135f13Db3B114107dCB0B32B6c9e10fFF5a6987","decimals":18},{"symbol":"SUSHI","address":"0x5fFccc55C0d2fd6D3AC32C26C020B3267e933F1b",
7 | "decimals":18},{"symbol":"LINK","address":"0xD5D5030831eE83e22a2C9a5cF99931A50c676433","decimals":18},{"symbol":"UNI",
8 | "address":"0xDBDE1347fED5dC03C74059010D571a16417d307e","decimals":18},{"symbol":"DODO","address":"0x572c5B5BF34f75FB62c39b9BFE9A75bb0bb47984",
9 | "decimals":18}]
--------------------------------------------------------------------------------
/test/signals/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const signals = {
4 | attemptingTurn: 'attemptingturn',
5 | turnToken: 'turntoken',
6 | tryTurn: 'tryturn',
7 | connect: 'connect',
8 | connection: 'connection',
9 | signature: 'signature',
10 | offerSignal: 'offersignal',
11 | offer: 'offer',
12 | answerSignal: 'answersignal',
13 | answer: 'answer',
14 | initiated: 'initiated',
15 | rtcConnected: 'rtcconnected',
16 | disconnect: 'disconnect',
17 | handshake: 'handshake',
18 | confirmation: 'confirmation',
19 | socketTimeout: 'socketTimeout',
20 | invalidConnection: 'InvalidConnection',
21 | confirmationFailedBusy: 'confirmationFailedBusy',
22 | confirmationFailed: 'confirmationFailed',
23 | receivedSignal: 'receivedSignal',
24 | error: 'error'
25 | }
26 |
27 | const roles = {
28 | initiator: 'initiator',
29 | receiver: 'receiver'
30 | }
31 |
32 | const rtcSignals = {
33 | error: 'error',
34 | connect: 'connect',
35 | disconnected: 'disconnected',
36 | close: 'close',
37 | data: 'data',
38 | signal: 'signal'
39 | }
40 |
41 | export { signals, roles, rtcSignals }
42 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_getEncryptionPublicKey.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import { toError, toPayload } from '../jsonrpc';
3 | import EventNames from '../events';
4 | import debugLogger from 'debug';
5 | const debug = debugLogger('MEWconnectWeb3');
6 | const debugErrors = debugLogger('MEWconnectError');
7 |
8 | export default async ({ payload, eventHub }, res, next) => {
9 | if (payload.method !== 'eth_getEncryptionPublicKey') return next();
10 | try {
11 | eventHub.emit(
12 | EventNames.GET_ENCRYPTED_PUBLIC_KEY,
13 | payload.params,
14 | _response => {
15 | if (_response.reject) {
16 | debug('USER DECLINED SIGN TRANSACTION');
17 | res(toError(payload.id, 'User Rejected Request', 4001));
18 | return;
19 | }
20 | debug('eth_getEncryptionPublicKey response', payload.method, _response);
21 | res(null, toPayload(payload.id, _response));
22 | }
23 | );
24 | } catch (e) {
25 | debugErrors(e);
26 | debugErrors('Error: eth_getEncryptionPublicKey', e);
27 | res(e);
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 MyEtherWallet
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_signTypedData_v4.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import { toError, toPayload } from '../jsonrpc';
3 | import EventNames from '../events';
4 | import debugLogger from 'debug';
5 | const debug = debugLogger('MEWconnectWeb3');
6 | const debugErrors = debugLogger('MEWconnectError');
7 |
8 | export default async ({ payload, eventHub }, res, next) => {
9 | if (
10 | payload.method !== 'eth_signTypedData_v4' &&
11 | payload.method !== 'eth_signTypedData'
12 | )
13 | return next();
14 | try {
15 | eventHub.emit(
16 | EventNames.SIGN_TYPE_DATA_V4,
17 | payload.params[1],
18 | _response => {
19 | if (_response.reject) {
20 | debug('USER DECLINED SIGN TYPED DATA');
21 | res(toError(payload.id, 'User Rejected Request', 4001));
22 | return;
23 | }
24 | debug('eth_signTypedData_v4 response', payload.method, _response);
25 | res(null, toPayload(payload.id, _response));
26 | }
27 | );
28 | } catch (e) {
29 | debugErrors(e);
30 | debugErrors('Error: eth_signTypedData_v3', e);
31 | res(e);
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/src/connectWindow/popupHtml.js:
--------------------------------------------------------------------------------
1 | const noticeHtml = (elementId, imageSrc, iconImage) => {
2 | return `
3 |
4 |
5 |

6 |
7 |

8 |
MEW wallet
9 |
10 |
11 |
12 |
13 |
14 | `;
15 | };
16 |
17 | const connectedNoticeHtml = (elementId, imageSrc, iconImage) => {
18 | return `
19 |
20 |
21 |
22 |

23 |
24 |
25 |
26 | Connected to
27 | MEW wallet
28 | Powered by MyEtherWallet
29 |
30 |
31 | `;
32 | };
33 |
34 | export { noticeHtml, connectedNoticeHtml };
35 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | globals: {
3 | VERSION: 'readonly',
4 | ROUTER_MODE: 'readonly',
5 | NODE_ENV: 'readonly'
6 | },
7 | ignorePatterns: ['dist/**/*.js'],
8 | root: true,
9 | env: {
10 | node: true,
11 | jest: true
12 | },
13 | extends: ['plugin:vue/recommended', '@vue/prettier', 'eslint:recommended'],
14 | rules: {
15 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
17 | 'no-else-return': ['error', { allowElseIf: true }],
18 | 'arrow-parens': 'off',
19 | 'generator-star-spacing': 'off',
20 | semi: 'off',
21 | 'prefer-const': 'error',
22 | 'no-var': 'error',
23 | 'security/detect-new-buffer': 'off',
24 | 'security/detect-object-injection': 'off',
25 | 'require-atomic-updates': 'off',
26 | 'no-prototype-builtins': 'off',
27 | 'no-irregular-whitespace': [
28 | 'error',
29 | {
30 | skipComments: true,
31 | skipTemplates: true,
32 | skipStrings: true,
33 | skipRegExps: true
34 | }
35 | ],
36 | 'vue/custom-event-name-casing': 'off'
37 | },
38 | parserOptions: {
39 | parser: 'babel-eslint'
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/src/messages.js:
--------------------------------------------------------------------------------
1 | const messages = {
2 | decline: 'User declined action in MEW wallet app',
3 | approveTx: 'Check your phone to approve transaction ',
4 | disconnect: 'Disconnected from MEW wallet',
5 | complete: 'Transaction completed',
6 | sent: 'Transaction sent',
7 | failed: 'Transaction failed',
8 | signMessage: 'Check your phone to sign the message',
9 | declineSignMessage: 'User declined message signing',
10 | notConnected: 'Phone not connected. Please connect your phone and try again',
11 | defaultMessage: 'Check your phone to continue',
12 | error: 'An error occurred while preparing the last action',
13 | communicationError:
14 | 'Could not complete last response from MEW wallet. Nothing was sent. Please try to send or sign again.',
15 | disconnectError: ''
16 | };
17 |
18 | const messageConstants = {
19 | decline: 'decline',
20 | approveTx: 'approveTx',
21 | disconnect: 'disconnect',
22 | complete: 'complete',
23 | sent: 'sent',
24 | failed: 'failed',
25 | signMessage: 'signMessage',
26 | error: 'error',
27 | notConnected: 'notConnected',
28 | declineMessage: 'declineSignMessage',
29 | communicationError: 'communicationError',
30 | disconnectError: 'disconnectError'
31 | };
32 |
33 | export { messages, messageConstants };
34 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | .idea/
61 | /example/Initiator_Peer/mewConnect.js
62 | /example/Initiator_Peer/mewConnectUtils.js
63 | /example/Initiator_Peer/mewRTC.js
64 | /browser/package.json
65 | /example/
66 | /site/
67 | /tests/fsdfds/
68 | /assets/
69 | /scraps/
70 |
--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
3 |
4 | name: Node.js Package
5 |
6 | on:
7 | release:
8 | types: [created]
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: actions/setup-node@v1
16 | with:
17 | node-version: 12
18 | - run: npm ci
19 |
20 | publish-npm:
21 | needs: build
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/checkout@v2
25 | - uses: actions/setup-node@v1
26 | with:
27 | node-version: 12
28 | registry-url: https://registry.npmjs.org/
29 | - run: npm ci
30 | - run: npm publish
31 | env:
32 | NODE_AUTH_TOKEN: ${{secrets.npm_token}}
33 |
34 | # publish-gpr:
35 | # needs: build
36 | # runs-on: ubuntu-latest
37 | # steps:
38 | # - uses: actions/checkout@v2
39 | # - uses: actions/setup-node@v1
40 | # with:
41 | # node-version: 12
42 | # registry-url: https://npm.pkg.github.com/
43 | # - run: npm ci
44 | # - run: npm publish
45 | # env:
46 | # NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | .idea/
61 | /example/Initiator_Peer/mewConnect.js
62 | /example/Initiator_Peer/mewConnectUtils.js
63 | /example/Initiator_Peer/mewRTC.js
64 | /browser/package.json
65 | /example/node_modules/
66 | /tests/fsdfds/
67 | /test/ganache.sh
68 | /scraps/
69 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_decrypt.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import { toError, toPayload } from '../jsonrpc';
3 | import EventNames from '../events';
4 | import debugLogger from 'debug';
5 | import { isHexStrict } from 'web3-utils';
6 | import { bufferToHex } from 'ethereumjs-utils';
7 | const debug = debugLogger('MEWconnectWeb3');
8 | const debugErrors = debugLogger('MEWconnectError');
9 |
10 | export default async ({ payload, eventHub }, res, next) => {
11 | if (payload.method !== 'eth_decrypt') return next();
12 | try {
13 | debug(payload.params[0]); // todo remove dev item
14 | let jsonObj = payload.params[0];
15 | if (!isHexStrict(jsonObj)) {
16 | jsonObj = JSON.parse(jsonObj);
17 | jsonObj = bufferToHex(Buffer.from(JSON.stringify(jsonObj), 'utf8'));
18 | }
19 | eventHub.emit(
20 | EventNames.DECRYPT,
21 | [jsonObj, payload.params[1]],
22 | _response => {
23 | if (_response.reject) {
24 | debug('USER DECLINED SIGN TRANSACTION');
25 | res(toError(payload.id, 'User Rejected Request', 4001));
26 | return;
27 | }
28 | debug('decrypt response', payload.method, _response);
29 | res(null, toPayload(payload.id, _response));
30 | }
31 | );
32 | } catch (e) {
33 | debugErrors(e);
34 | debugErrors('Error: eth_decrypt', e);
35 | res(e);
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/example/app/src/create.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | export default class MewWalletConnector {
4 | constructor(url) {
5 | this.mewConnect = '';
6 | this.provider = '';
7 | this.url = url;
8 | }
9 |
10 | async activate() {
11 | let account;
12 | const { default: MewConnect } = await import('../../../src');
13 | if (!MewConnect.Provider.isConnected) {
14 | this.mewConnect = new MewConnect.Provider({ windowClosedError: true });
15 |
16 | this.provider = this.mewConnect.makeWeb3Provider(1, this.url, true);
17 | this.mewConnect.on('disconnected', () => {
18 | // this.emitDeactivate();
19 | });
20 | account = await this.mewConnect
21 | .enable()
22 | .catch(() => {
23 | throw new Error('The user rejected the request.');
24 | })
25 | .then(accounts => accounts[0]);
26 | }
27 |
28 |
29 |
30 | return { provider: this.provider, chainId: 1, account: account };
31 | }
32 |
33 | async getProvider(){
34 | return this.provider;
35 | }
36 |
37 | async getChainId() {
38 | return 1;
39 | }
40 |
41 | async getAccount() {
42 | return this.provider.send('eth_accounts').then(accounts => accounts[0]);
43 | }
44 |
45 | deactivate() {
46 | this.provider.close();
47 | // this.emitDeactivate();
48 | }
49 |
50 | async close() {
51 | this.provider.close();
52 | // this.emitDeactivate();
53 | }
54 | }
--------------------------------------------------------------------------------
/src/connectClient/constants/signals.js:
--------------------------------------------------------------------------------
1 | const signalV1 = {
2 | attemptingTurn: 'attemptingTurn',
3 | turnToken: 'turnToken',
4 | tryTurn: 'tryTurn',
5 | connection: 'connection',
6 | connect: 'connect',
7 | signature: 'signature',
8 | offerSignal: 'offerSignal',
9 | offer: 'offer',
10 | answerSignal: 'answerSignal',
11 | answer: 'answer',
12 | rtcConnected: 'rtcConnected',
13 | disconnect: 'disconnect',
14 | handshake: 'handshake',
15 | confirmation: 'confirmation',
16 | invalidConnection: 'InvalidConnection',
17 | confirmationFailedBusy: 'confirmationFailedBusy',
18 | confirmationFailed: 'confirmationFailed'
19 | };
20 |
21 | const signalV2 = {
22 | //V1 (ish)
23 | attemptingTurn: 'attemptingturn',
24 | turnToken: 'turntoken',
25 | tryTurn: 'tryturn',
26 | connect: 'connect',
27 | connection: 'connection',
28 | signature: 'signature',
29 | offerSignal: 'offersignal',
30 | offer: 'offer',
31 | answerSignal: 'answersignal',
32 | answer: 'answer',
33 | rtcConnected: 'rtcconnected',
34 | disconnect: 'disconnect',
35 | handshake: 'handshake',
36 | confirmation: 'confirmation',
37 | invalidConnection: 'InvalidConnection',
38 | confirmationFailedBusy: 'confirmationFailedBusy',
39 | confirmationFailed: 'confirmationFailed',
40 | // V2
41 | initiated: 'initiated',
42 | socketTimeout: 'socketTimeout',
43 | receivedSignal: 'receivedSignal',
44 | error: 'error',
45 | disconnected: 'disconnected'
46 | };
47 |
48 | export { signalV1, signalV2 };
49 |
--------------------------------------------------------------------------------
/src/connectClient/constants/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | version,
3 | versions,
4 | connectionCodeSchemas,
5 | connectionCodeSeparator,
6 | stages,
7 | rtc,
8 | iceConnectionState,
9 | RTCSignalingState,
10 | RTCIceGatheringState,
11 | lifeCycle,
12 | communicationTypes,
13 | loggerLevels
14 | } from './constants';
15 |
16 | import { signalV1, signalV2 } from './signals';
17 | import { V2endpoint, V1endpoint } from '../config';
18 |
19 | const signalUrl = {
20 | V1: V1endpoint,
21 | V2: V2endpoint
22 | };
23 |
24 | const signals = {
25 | V1: signalV1,
26 | V2: signalV2
27 | };
28 |
29 | const versionIdentify = ver => {
30 | const parts = ver.toString().split('.');
31 | if (parts.length > 0) {
32 | ver = parts[0];
33 | }
34 | switch (ver) {
35 | case 1:
36 | case '1':
37 | case 'V1':
38 | return 'V1';
39 | case 2:
40 | case '2':
41 | case 'V2':
42 | return 'V2';
43 | default:
44 | return 'V2';
45 | }
46 | };
47 |
48 | const signalServer = ver => {
49 | return signalUrl[versionIdentify(ver)];
50 | };
51 |
52 | const signal = ver => {
53 | return signals[versionIdentify(ver)];
54 | };
55 |
56 | export {
57 | version,
58 | versions,
59 | signalServer,
60 | connectionCodeSchemas,
61 | connectionCodeSeparator,
62 | signals,
63 | signal,
64 | stages,
65 | rtc,
66 | iceConnectionState,
67 | RTCSignalingState,
68 | RTCIceGatheringState,
69 | lifeCycle,
70 | communicationTypes,
71 | loggerLevels
72 | };
73 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/helpers/parseTokensData.js:
--------------------------------------------------------------------------------
1 | import BigNumber from 'bignumber.js';
2 |
3 | function parseTokensData(data, to, _web3, networkToken, networkName) {
4 | const web3 = _web3;
5 | let token = networkToken.find(el => {
6 | return el.address.toLowerCase() === to.toLowerCase();
7 | });
8 |
9 | const jsonInterface = {
10 | constant: false,
11 | inputs: [
12 | { name: '_to', type: 'address' },
13 | { name: '_amount', type: 'uint256' }
14 | ],
15 | name: 'transfer',
16 | outputs: [{ name: '', type: 'bool' }],
17 | payable: false,
18 | stateMutability: 'nonpayable',
19 | type: 'function'
20 | };
21 | const transferFuncSig = web3.eth.abi.encodeFunctionSignature(jsonInterface);
22 | const tokenData = {
23 | tokenTransferTo: '',
24 | tokenTransferVal: '',
25 | tokenSymbol: ''
26 | };
27 | if (data.substr(0, 10) === transferFuncSig) {
28 | const params = web3.eth.abi.decodeParameters(
29 | ['address', 'uint256'],
30 | `${data.substr(10)}`
31 | );
32 | const value = new BigNumber(params[1]);
33 | tokenData.tokenTransferTo = params[0];
34 | tokenData.tokenTransferVal = token
35 | ? value
36 | .div(new BigNumber(10).pow(token.decimals))
37 | .toFixed()
38 | .toString()
39 | : value.toString();
40 | tokenData.tokenSymbol = token ? token.symbol : 'Unidentified Token';
41 | }
42 |
43 | return tokenData;
44 | }
45 |
46 | export default parseTokensData;
47 |
--------------------------------------------------------------------------------
/tests/helpers/simple-peerMock.js:
--------------------------------------------------------------------------------
1 | // socket.io-client.js
2 | let EVENTS = {};
3 |
4 | export default class PeerMock {
5 | constructor(toEmit, data, time) {
6 | this._pc = {
7 | addEventListener(event, args) {
8 | console.log(event, args); // todo remove dev item
9 | EVENTS[event].forEach(func => func(args));
10 | }
11 | };
12 | }
13 |
14 | Peer() {
15 | let _this = this;
16 | console.log('called'); // todo remove dev item
17 | return function (){
18 | console.log('called'); // todo remove dev item
19 | return _this;
20 | }
21 | };
22 |
23 | on(event, func) {
24 | console.log(event); // todo remove dev item
25 | if (EVENTS[event]) {
26 | return EVENTS[event].push(func);
27 | }
28 | EVENTS[event] = [func];
29 | // if (event === toEmit) {
30 | setTimeout(() => {
31 | console.log(event, data); // todo remove dev item
32 | EVENTS[event].forEach(func => func(data));
33 | }, 50);
34 | // }
35 | }
36 |
37 | emit(event) {
38 | setTimeout(() => {
39 | console.log(event, data); // todo remove dev item
40 | EVENTS[event].forEach(func => func(data));
41 | }, time);
42 | }
43 |
44 | signal() {
45 | setTimeout(() => {
46 | console.log(event, data); // todo remove dev item
47 | EVENTS[event].forEach(func => func(data));
48 | }, time);
49 | }
50 |
51 | send() {
52 |
53 | }
54 |
55 | destroy() {
56 |
57 | }
58 |
59 | }
60 |
61 | // cleanup helper
62 | export function cleanup() {
63 | EVENTS = {};
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/tests/helpers/signalServerMock.js:
--------------------------------------------------------------------------------
1 | // socket.io-client.js
2 | let EVENTS = {};
3 |
4 |
5 | const socket = {
6 | on(event, func) {
7 | if (EVENTS[event]) {
8 | return EVENTS[event].push(func);
9 | }
10 | EVENTS[event] = [func];
11 | },
12 | emit(event, args) {
13 | console.log(event, args); // todo remove dev item
14 | EVENTS[event].forEach(func => func(args));
15 | }
16 | };
17 |
18 | const connect = {
19 | connect: function(url, options) {
20 | console.log(url, options); // todo remove dev item
21 | return socket;
22 | }
23 | };
24 |
25 | export default function io(url, options) {
26 | return connect;
27 | };
28 |
29 |
30 |
31 |
32 | // function emit(event, ...args) {
33 | // EVENTS[event].forEach(func => func(...args));
34 | // }
35 | //
36 | // const socket = {
37 | // on(event, func) {
38 | // if (EVENTS[event]) {
39 | // return EVENTS[event].push(func);
40 | // }
41 | // EVENTS[event] = [func];
42 | // },
43 | // emit
44 | // };
45 | //
46 | // function connect(url, options){
47 | // return socket;
48 | // }
49 | //
50 | // function io(url, options) {
51 | // console.log(url, option); // todo remove dev item
52 | // return {
53 | // connect
54 | // }
55 | // }
56 |
57 | // io.connect = (url, options) => {
58 | // console.log(url, option); // todo remove dev item
59 | // return socket;
60 | // };
61 |
62 | // Additional helpers, not included in the real socket.io-client,just for out test.
63 | // to emulate server emit.
64 | // export const serverSocket = { emit, connect };
65 |
66 | // cleanup helper
67 | export function cleanup() {
68 | EVENTS = {};
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/tests/browser/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const webpack = require('webpack')
3 |
4 | module.exports = {
5 | mode: 'none', // "production" | "development" | "none"
6 | entry: {
7 | MewConnectBrowserTest: [/*'babel-polyfil', */'../specs/MewConnectInitiator.spec.js']
8 | },
9 | output: {
10 | path: __dirname, // string
11 | filename: '[name].min.js',
12 | // library: 'MewConnect', // string,
13 | // the name of the exported library
14 | // TODO figure out the best option to use here
15 | // libraryTarget: 'umd', // umd', // "var" | "assign" | "this" | "window" | "global" | "commonjs" | "commonjs2" | "amd" | "umd"
16 | // the type of the exported library
17 | // globalObject: 'this'
18 | },
19 | module: {
20 | rules: [
21 | {
22 | test: /\.js$/,
23 | exclude: /(node_modules|bower_components|dist)/,
24 | use: {
25 | loader: 'babel-loader',
26 | options: {
27 | plugins: [require('babel-plugin-transform-object-rest-spread')],
28 | presets: ["env"]
29 | }
30 | }
31 | }
32 | ]
33 | },
34 | resolve: {
35 | modules: [
36 | 'node_modules',
37 | path.resolve(__dirname, 'src')
38 | ],
39 | extensions: ['.js', '.json', '.jsx', '.css']
40 | },
41 | performance: {
42 | hints: 'warning', // enum
43 | maxAssetSize: 200000, // int (in bytes),
44 | maxEntrypointSize: 400000 // int (in bytes)
45 | },
46 | devtool: 'source-map', // enum
47 | context: __dirname, // string (absolute path!)
48 | target: 'web', // enum
49 | // the environment in which the bundle should run
50 | plugins: [
51 | new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify('production')})
52 | ]
53 | }
54 |
--------------------------------------------------------------------------------
/test/Unit.spec.js:
--------------------------------------------------------------------------------
1 | // import 'regenerator-runtime/runtime';
2 | // import { expect as chaiExpect } from 'chai';
3 | // import debug from 'debug';
4 | // import * as MewConnectSrc from '../../src';
5 | // import MewConnectReceiver from '../helpers/MewConnectReceiver';
6 | //
7 | // const connectLogger = debug('test:Connect');
8 | // const fallbackLogger = debug('test:Fallback');
9 | //
10 | // const signalUrl = typeof signalServer !== 'undefined' ? signalServer : 'https://connect.mewapi.io';
11 | import MewConnectInitiator from '../src/connectClient/initiator/MewConnectInitiator';
12 | import MewConnectCrypto from '../src/connectClient/MewConnectCrypto';
13 |
14 | describe('Check Base Connection Operation', () => {
15 | it('tests', async done => {
16 | const init = new MewConnectInitiator();
17 | init.generateKeys();
18 | const mewCrypto = init.mewCrypto
19 | const data = { type: 'address', data: '0x2khkj223lkjh2', id: '123' };
20 | const input = JSON.stringify(data);
21 |
22 | const encrypt = async arg => {
23 | let encryptedSend;
24 | if (typeof arg === 'string') {
25 | encryptedSend = await mewCrypto.encrypt(arg);
26 | } else {
27 | encryptedSend = await mewCrypto.encrypt(JSON.stringify(arg));
28 | }
29 | return JSON.stringify(encryptedSend);
30 | };
31 | encrypt(input).then(vlaue => {
32 | init.webRtcCommunication.on('appData', result => {
33 | console.log(result); // todo remove dev item
34 | expect(result.type).toEqual(expect.stringMatching(data.type));
35 | expect(result.data).toEqual(expect.stringMatching(data.data));
36 | expect(result.id).toEqual(expect.stringMatching(data.id));
37 | done();
38 | })
39 | init.webRtcCommunication.onData('123', vlaue)
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/src/connectProvider/fetchLists/index.js:
--------------------------------------------------------------------------------
1 | const fetch = require('node-fetch');
2 | const fs = require('fs');
3 | const configs = require('./configs');
4 | const tokenList = require('./lists/tokens.json');
5 |
6 | const fetchTokens = async () => {
7 | try {
8 | if (!fs.existsSync(configs.TOKENS_PATH)) {
9 | fs.mkdirSync(configs.TOKENS_PATH);
10 | }
11 | const tokenFileURL =
12 | 'https://cdn.jsdelivr.net/gh/MyEtherWallet/ethereum-lists@master/dist/tokens/';
13 | if (tokenList !== undefined && tokenList.length > 0) {
14 | for (let i = 0; i < tokenList.length; i++) {
15 | const tokenFile = tokenList[i];
16 | if (configs.SUPPORTED_CHAINS.includes(tokenFile.name)) {
17 | let tokensCollection = await fetch(
18 | `${tokenFileURL + tokenFile.name}/tokens-${tokenFile.name}.json`
19 | )
20 | .then(res => res.json())
21 | .catch(err => console.log(err));
22 | if (tokensCollection !== undefined) {
23 | console.log('Writing tokens for the network: ' + tokenFile.name);
24 | tokensCollection = tokensCollection.map(item => {
25 | return {
26 | symbol: item.symbol,
27 | address: item.address,
28 | decimals: item.decimals
29 | };
30 | });
31 | fs.writeFileSync(
32 | `${configs.TOKENS_PATH}/tokens-${tokenFile.name}.json`,
33 | JSON.stringify(tokensCollection)
34 | );
35 | }
36 | }
37 | }
38 | }
39 | } catch (e) {
40 | console.error(e); // Not captured by sentry
41 | }
42 | };
43 |
44 | const run = async () => {
45 | await fetchTokens();
46 | };
47 |
48 | (async () => {
49 | try {
50 | await run();
51 | console.log('Done');
52 | } catch (e) {
53 | console.error(e);
54 | }
55 | })();
56 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/utils.js:
--------------------------------------------------------------------------------
1 | import { bufferToInt } from 'ethereumjs-utils';
2 |
3 | const getBufferFromHex = hex => {
4 | hex = sanitizeHex(hex);
5 | const _hex = hex.toLowerCase().replace('0x', '');
6 | return new Buffer(_hex, 'hex');
7 | };
8 | const padLeftEven = hex => {
9 | hex = hex.length % 2 != 0 ? '0' + hex : hex;
10 | return hex;
11 | };
12 | const sanitizeHex = hex => {
13 | hex = hex.substring(0, 2) == '0x' ? hex.substring(2) : hex;
14 | if (hex == '') return '';
15 | return '0x' + padLeftEven(hex);
16 | };
17 | const bufferToHex = buffer => {
18 | return '0x' + buffer.toString('hex');
19 | };
20 | const getHexTxObject = tx => {
21 | return {
22 | to: sanitizeHex(tx.to.toString('hex')),
23 | value: sanitizeHex(tx.value.toString('hex')),
24 | data: sanitizeHex(tx.data.toString('hex')),
25 | chainId: tx.getChainId(),
26 | nonce: sanitizeHex(tx.nonce.toString('hex')),
27 | gasLimit: sanitizeHex(tx.gasLimit.toString('hex')),
28 | gasPrice: sanitizeHex(tx.gasPrice.toString('hex'))
29 | };
30 | };
31 | const getSignTransactionObject = tx => {
32 | return {
33 | rawTransaction: bufferToHex(tx.serialize()),
34 | tx: {
35 | nonce: bufferToHex(tx.nonce),
36 | gasPrice: bufferToHex(tx.gasPrice),
37 | gas: tx.gasLimit ? bufferToHex(tx.gasLimit) : bufferToHex(tx.gas),
38 | to: bufferToHex(tx.to),
39 | value: bufferToHex(tx.value),
40 | input: bufferToHex(tx.data),
41 | v: bufferToHex(tx.v),
42 | r: bufferToHex(tx.r),
43 | s: bufferToHex(tx.s),
44 | hash: bufferToHex(tx.hash())
45 | }
46 | };
47 | };
48 | const calculateChainIdFromV = v => {
49 | const sigV = bufferToInt(v);
50 | let chainId = Math.floor((sigV - 35) / 2);
51 | if (chainId < 0) chainId = 0;
52 | return chainId;
53 | };
54 | export {
55 | getBufferFromHex,
56 | bufferToHex,
57 | getSignTransactionObject,
58 | sanitizeHex,
59 | padLeftEven,
60 | getHexTxObject,
61 | calculateChainIdFromV
62 | };
63 |
--------------------------------------------------------------------------------
/src/connectWindow/images/camera.js:
--------------------------------------------------------------------------------
1 | const image = `data:image/png;base64, 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`;
2 |
3 | export default image;
4 |
--------------------------------------------------------------------------------
/tests/helpers/MewConnectCryptoMock.js:
--------------------------------------------------------------------------------
1 | import ethUtils from 'ethereumjs-utils';
2 | import crypto from 'crypto';
3 | import secp256k1 from 'secp256k1';
4 |
5 | const privateStr =
6 | '6d96ff74ad12467b3ebd993f6b0927d6996d464900bbd63de866b3090cb36d2b';
7 | const pubStr =
8 | '035892d28938ebe58339649fdaef273953b0b1f5d68bfb7422adf41d5993d9e20d';
9 | export default class MewConnectCrypto {
10 | static create() {
11 | return new MewConnectCrypto();
12 | }
13 |
14 | setPrivate(pvtKey) {
15 | this.prvt = Buffer.from(pvtKey, 'hex');
16 | }
17 |
18 | generateMessage() {
19 | return crypto.randomBytes(32).toString('hex');
20 | }
21 |
22 | // Not for the Address, but generate them for the connection check
23 | prepareKey() {
24 | this.prvt = Buffer.from(privateStr, 'hex');
25 | this.pub = Buffer.from(pubStr, 'hex');
26 | return { pub: this.pub, pvt: this.prvt };
27 | }
28 |
29 | generatePrivate() {
30 | return Buffer.from(privateStr, 'hex');
31 | }
32 |
33 | generatePublic() {
34 | const pvt = Buffer.from(privateStr, 'hex');
35 | this.prvt = pvt;
36 | return secp256k1.publicKeyCreate(pvt);
37 | }
38 |
39 | encrypt(dataToSend) {
40 | return new Promise(resolve => {
41 | resolve(dataToSend);
42 | });
43 | }
44 |
45 | decrypt(dataToSee) {
46 | return new Promise(resolve => {
47 | resolve(dataToSee);
48 | });
49 | }
50 |
51 | signMessage(msgToSign) {
52 | return new Promise((resolve, reject) => {
53 | try {
54 | const msg = ethUtils.hashPersonalMessage(ethUtils.toBuffer(msgToSign));
55 | const signed = ethUtils.ecsign(
56 | Buffer.from(msg),
57 | Buffer.from(this.prvt, 'hex')
58 | );
59 | const combined = Buffer.concat([
60 | Buffer.from([signed.v]),
61 | Buffer.from(signed.r),
62 | Buffer.from(signed.s)
63 | ]);
64 | const combinedHex = combined.toString('hex');
65 | resolve(combinedHex);
66 | } catch (e) {
67 | reject(e);
68 | }
69 | });
70 | }
71 |
72 | bufferToConnId(buf) {
73 | return buf.toString('hex').slice(32);
74 | }
75 |
76 | isJSON(arg) {
77 | try {
78 | JSON.parse(arg);
79 | return true;
80 | } catch (e) {
81 | return false;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/connectWindow/images/refreshIcon.js:
--------------------------------------------------------------------------------
1 | const refreshIcon =
2 | 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMThweCIgaGVpZ2h0PSIxN3B4IiB2aWV3Qm94PSIwIDAgMTggMTciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDQ5LjIgKDUxMTYwKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5leGNoYW5nZSAoMSk8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz48L2RlZnM+CiAgICA8ZyBpZD0iU3ltYm9scyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9ImFkZHJlc3MtYm94IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTkwLjAwMDAwMCwgLTEwNy4wMDAwMDApIiBmaWxsPSIjMDAwMDAwIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI2ZmZmZmZiIgc3Ryb2tlLXdpZHRoPSIwLjIiPgogICAgICAgICAgICA8ZyBpZD0iZXhjaGFuZ2UtKDEpIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxOTEuMDAwMDAwLCAxMDguMDAwMDAwKSI+CiAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUuMDY2OTg5OCw5LjMwNTY0NTY4IEMxNS4wNjY5ODk4LDEwLjY2ODM5NzEgMTQuMjIzMjYxMiwxMC43NjU3MzY1IDE0LjA2MjU1MSwxMC43NjU3MzY1IEwxLjcxMjk3NjE4LDEwLjc2NTczNjUgTDQuMzY5NzE2NzYsOC4xOTExMDk2NyBMMy42NjE1ODc0Miw3LjUgTDAuMTQ2MDUxNjc3LDEwLjkwNjg3ODcgQy0wLjA0ODY4Mzg5MjIsMTEuMDk2NzIwOSAtMC4wNDg2ODM4OTIyLDExLjQwMzI3OTEgMC4xNDYwNTE2NzcsMTEuNTkzMTIxMyBMMy42NjE1ODc0MiwxNSBMNC4zNjk3MTY3NiwxNC4zMTM3NTczIEwxLjcxMjk3NjE4LDExLjczOTEzMDQgTDE0LjA2MjU1MSwxMS43MzkxMzA0IEMxNC43NTU2MTM4LDExLjczOTEzMDQgMTYuMDcxNDI4NiwxMS4yNTI0MzM1IDE2LjA3MTQyODYsOS4zMDU2NDU2OCBMMTYuMDcxNDI4Niw3Ljg0NTU1NDgzIEwxNS4wNjY5ODk4LDcuODQ1NTU0ODMgTDE1LjA2Njk4OTgsOS4zMDU2NDU2OCBaIiBpZD0iU2hhcGUiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xLjAwNDQzODc4LDUuNjk5MjIxMjggQzEuMDA0NDM4NzgsNC4zMzY0Njk4MiAxLjg0ODE2NzM2LDQuMjM5MTMwNDMgMi4wMDg4Nzc1Niw0LjIzOTEzMDQzIEwxNC4zNTg0NTI0LDQuMjM5MTMwNDMgTDExLjcwMTcxMTgsNi44MTM3NTczIEwxMi40MDk4NDEyLDcuNSBMMTUuOTI1Mzc2OSw0LjA5MzEyMTM1IEMxNi4xMjAxMTI1LDMuOTAzMjc5MTIgMTYuMTIwMTEyNSwzLjU5NjcyMDg4IDE1LjkyNTM3NjksMy40MDY4Nzg2NSBMMTIuNDA5ODQxMiwwIEwxMS42OTY2ODk2LDAuNjkxMTA5NjY5IEwxNC4zNTg0NTI0LDMuMjY1NzM2NTMgTDIuMDA4ODc3NTYsMy4yNjU3MzY1MyBDMS4zMTU4MTQ4LDMuMjY1NzM2NTMgMCwzLjc1MjQzMzQ4IDAsNS42OTkyMjEyOCBMMCw3LjE1OTMxMjEzIEwxLjAwNDQzODc4LDcuMTU5MzEyMTMgTDEuMDA0NDM4NzgsNS42OTkyMjEyOCBaIiBpZD0iU2hhcGUiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+';
3 |
4 | export default refreshIcon;
5 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/networks/tokens/tokens-rop.json:
--------------------------------------------------------------------------------
1 | [{"symbol":"*PLASMA","address":"0x95D7321EdCe519419ba1DbC60A89bAfbF55EAC0D","decimals":6},{"symbol":"aBAT","address":"0x0D0Ff1C81F2Fbc8cbafA8Df4bF668f5ba963Dab4","decimals":18},{"symbol":"ABCD","address":"0x21C968b15be143484E0BD1CfaE1f7378f89b414c","decimals":18},{"symbol":"aDAI","address":"0xcB1Fe6F440c49E9290c3eb7f158534c2dC374201","decimals":18},{"symbol":"aETH","address":"0x2433A1b6FcF156956599280C3Eb1863247CFE675","decimals":18},{"symbol":"aKNC","address":"0xCf6efd4528d27Df440fdd585a116D3c1fC5aDdEe","decimals":18},{"symbol":"aLEND","address":"0x383261d0e287f0A641322AEB15E3da50147Dd36b","decimals":18},{"symbol":"aLINK","address":"0x52fd99c15e6FFf8D4CF1B83b2263a501FDd78973","decimals":18},{"symbol":"aMANA","address":"0x8e96a4068da80F66ef1CFc7987f0F834c26106fa","decimals":18},{"symbol":"aMKR","address":"0xEd6A5d671f7c55aa029cbAEa2e5E9A18E9d6a1CE","decimals":18},{"symbol":"aREP","address":"0xE4B92BcDB2f972e1ccc069D4dB33d5f6363738dE","decimals":18},{"symbol":"aSUSD","address":"0x5D17e0ea2d886F865E40176D71dbc0b59a54d8c1","decimals":6},{"symbol":"aTUSD","address":"0x6308180b412c481982628D093f342A259b4e681C","decimals":18},{"symbol":"aUSDC","address":"0x2dB6a31f973Ec26F5e17895f0741BB5965d5Ae15","decimals":6},{"symbol":"aUSDT","address":"0x790744bC4257B4a0519a3C5649Ac1d16DDaFAE0D","decimals":6},{"symbol":"aWBTC","address":"0xA1c4dB01F8344eCb11219714706C82f0c0c64841","decimals":18},{"symbol":"aZRX","address":"0x5BDC773c9D3515a5e3Dd415428F92a90E8e63Ae4","decimals":18},{"symbol":"cBAT","address":"0x189CA88bE39C9c1B8c8dd437F5ff1DB1f584b14b","decimals":8},{"symbol":"cDAI","address":"0x2B536482a01E620eE111747F8334B395a42A555E","decimals":8},{"symbol":"cETH","address":"0x42a628e0c5F3767930097B34b08dCF77e78e4F2B","decimals":8},{"symbol":"cREP","address":"0xA3C2c1618214549281E1b15dee9D682C8aa0DC1C","decimals":8},{"symbol":"cUSDC","address":"0x43a1363AFB28235720FCbDF0C2dAb7759091F7e0","decimals":8},{"symbol":"cWBTC","address":"0x06E728D7907C164649427D2ACFD4c81669D453Bf","decimals":8},{"symbol":"cZRX","address":"0xDff375162cfE7D77473C1BEC4560dEDE974E138c","decimals":8},{"symbol":"dqr30","address":"0xa1bAccA0e12D4091Ec1f92e7CaE3394CC9854D3D","decimals":18},{"symbol":"FQXT","address":"0x5D47033e140f7b589CC2545416eC9D7a712A7de9","decimals":8},{"symbol":"MEWV5","address":"0x4C572Fbc03D4A2B683cF4f10ffdcaFD00885E108","decimals":9},{"symbol":"RLC","address":"0x7314Dc4d7794b5E7894212CA1556ae8e3De58621","decimals":9}]
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_signTransaction.js:
--------------------------------------------------------------------------------
1 | // import unit from 'ethjs-unit';
2 | import { toError, toPayload } from '../jsonrpc';
3 | import EventNames from '../events';
4 | import { getSanitizedTx } from './utils';
5 |
6 | import debugLogger from 'debug';
7 | import BigNumber from 'bignumber.js';
8 | const debug = debugLogger('MEWconnectWeb3');
9 | const debugErrors = debugLogger('MEWconnectError');
10 |
11 | export default async ({ payload, store, eventHub }, res, next) => {
12 | if (payload.method !== 'eth_signTransaction') return next();
13 | const tx = payload.params[0];
14 | const localTx = Object.assign({}, tx);
15 | delete localTx['gas'];
16 | delete localTx['nonce'];
17 | try {
18 | if (!store.state.wallet) {
19 | eventHub.emit(EventNames.WALLET_NOT_CONNECTED);
20 | debug('NOT ACTIVE WALLET IDENTIFIED');
21 | res(toError(payload.id, 'No active wallet: eth_signTransaction', 4002));
22 | return;
23 | }
24 | tx.nonce = !tx.nonce
25 | ? await store.state.web3.eth.getTransactionCount(
26 | store.state.wallet.getAddressString()
27 | )
28 | : tx.nonce;
29 |
30 | if (tx.gasLimit && !tx.gas) {
31 | tx.gas = tx.gasLimit;
32 | } else if (!tx.gasLimit && tx.gas) {
33 | tx.gasLimit = tx.gas;
34 | }
35 | tx.gas =
36 | !tx.gas || new BigNumber(tx.gas).lte(0)
37 | ? await store.state.web3.eth.estimateGas(localTx)
38 | : tx.gas;
39 | tx.chainId = !tx.chainId ? store.state.network.chainID : tx.chainId;
40 | tx.gasPrice =
41 | !tx.gasPrice || new BigNumber(tx.gasPrice).lte(0)
42 | ? await store.state.web3.eth.getGasPrice()
43 | : tx.gasPrice;
44 |
45 | getSanitizedTx(tx)
46 | .then(_tx => {
47 | eventHub.emit(EventNames.SHOW_TX_SIGN_MODAL, _tx, _response => {
48 | if (_response.reject) {
49 | debug('USER DECLINED SIGN TRANSACTION');
50 | res(toError(payload.id, 'User Rejected Request', 4001));
51 | return;
52 | }
53 | debug('return signed transaction', payload.method, _response);
54 | res(null, toPayload(payload.id, _response.rawTransaction));
55 | });
56 | })
57 | .catch(e => {
58 | eventHub.emit(EventNames.ERROR_NOTIFY, e);
59 | debugErrors('Error: eth_signTransaction', e);
60 | res(e);
61 | });
62 | } catch (e) {
63 | debugErrors(e);
64 | debugErrors('Error: eth_signTransaction', e);
65 | res(e);
66 | }
67 | };
68 |
--------------------------------------------------------------------------------
/src/connectClient/constants/constants.js:
--------------------------------------------------------------------------------
1 | import { version } from '../config';
2 |
3 | const versions = ['0.0.1'];
4 |
5 | const connectionCodeSchemas = {
6 | '0.0.1': ['version', 'key', 'connId']
7 | };
8 |
9 | const connectionCodeSeparator = '_';
10 |
11 | const rtc = {
12 | error: 'error',
13 | connect: 'connect',
14 | close: 'close',
15 | data: 'data',
16 | signal: 'signal'
17 | };
18 |
19 | const iceConnectionState = {
20 | new: 'new',
21 | connecting: 'connecting',
22 | connected: 'connected',
23 | disconnected: 'disconnected',
24 | failed: 'failed',
25 | closed: 'closed'
26 | };
27 |
28 | const RTCSignalingState = {
29 | stable: 'stable',
30 | 'have-local-offer': 'have-local-offer',
31 | 'have-remote-offer': 'have-remote-offer',
32 | 'have-local-pranswer': 'have-local-pranswer',
33 | 'have-remote-pranswer': 'have-remote-pranswer'
34 | };
35 |
36 | const RTCIceGatheringState = {
37 | new: 'new',
38 | gathering: 'gathering',
39 | complete: 'complete'
40 | };
41 |
42 | const stages = {
43 | initiator: 'initiator',
44 | receiver: 'receiver'
45 | };
46 |
47 | const lifeCycle = {
48 | AuthRejected: 'AuthRejected',
49 | RtcInitiatedEvent: 'RtcInitiatedEvent',
50 | signatureCheck: 'signatureCheck',
51 | SocketConnectedEvent: 'SocketConnectedEvent',
52 | confirmationFailedEvent: 'confirmationFailedEvent',
53 | confirmationFailedBusyEvent: 'confirmationFailedBusyEvent',
54 | invalidConnectionEvent: 'invalidConnectionEvent',
55 | codeDisplay: 'codeDisplay',
56 | checkNumber: 'checkNumber',
57 | ConnectionId: 'ConnectionId',
58 | receiverVersion: 'receiverVersion',
59 | offerCreated: 'offerCreated',
60 | sendOffer: 'sendOffer',
61 | answerReceived: 'answerReceived',
62 | RtcConnectedEvent: 'RtcConnectedEvent',
63 | RtcConnectedEmitted: 'RtcConnectedEmitted',
64 | RtcClosedEvent: 'RtcClosedEvent',
65 | RtcDisconnectEvent: 'RtcDisconnectEvent',
66 | RtcDestroyedEvent: 'RtcDestroyedEvent',
67 | RtcFailedEvent: 'RtcFailedEvent',
68 | RtcErrorEvent: 'RtcErrorEvent',
69 | UsingFallback: 'UsingFallback',
70 | Failed: 'failed',
71 | attemptedDisconnectedSend: 'attemptedDisconnectedSend',
72 | connected: 'connected',
73 | disconnected: 'disconnected',
74 | ShowReload: 'ShowReload',
75 | decryptError: 'decryptError',
76 | connectingStart: 'connectingStart'
77 | };
78 |
79 | const communicationTypes = {
80 | address: 'address',
81 | signMessage: 'signMessage',
82 | signTx: 'signTx'
83 | };
84 |
85 | const loggerLevels = {
86 | errorLvl: 'error',
87 | warnLvl: 'warn',
88 | infoLvl: 'info',
89 | verboseLvl: 'verbose',
90 | debugLvl: 'debug',
91 | sillyLvl: 'silly'
92 | };
93 |
94 | export {
95 | version,
96 | versions,
97 | connectionCodeSchemas,
98 | connectionCodeSeparator,
99 | stages,
100 | rtc,
101 | iceConnectionState,
102 | RTCSignalingState,
103 | RTCIceGatheringState,
104 | lifeCycle,
105 | communicationTypes,
106 | loggerLevels
107 | };
108 |
--------------------------------------------------------------------------------
/test/utils/webrtc-connection.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import Peer from 'simple-peer'
4 | import wrtc from 'wrtc'
5 | import { stunServers, turnServers } from '@config'
6 | import { rtcSignals } from '@signals'
7 |
8 | export default class WebRTCConnection {
9 | constructor(options = {}) {
10 | this.options = options
11 | this.peer = {}
12 | this.listeners = {}
13 | }
14 |
15 | /**
16 | * Attempt to initiate an "offer" WebRTC connection between two peers.
17 | * This will return an offer object that can be used by the receiver to create a
18 | * p2p connection.
19 | *
20 | * If ICE servers are given, then use those instead. The object format returned
21 | * by twilio is incorrect. The 'url' properties must be renamed 'urls'
22 | *
23 | * @return {Object} - WebRTC connection offer
24 | */
25 | async offer(iceServers = null) {
26 | return new Promise((resolve, reject) => {
27 | const options = {
28 | initiator: true,
29 | trickle: false,
30 | iceTransportPolicy: 'relay',
31 | config: {
32 | iceServers: iceServers
33 | ? iceServers.map(obj => {
34 | const newObject = {}
35 | delete Object.assign(newObject, obj, { ['urls']: obj['url'] })[
36 | 'url'
37 | ]
38 | return newObject
39 | })
40 | : stunServers
41 | },
42 | wrtc: wrtc
43 | }
44 |
45 | this.peer = new Peer(options)
46 | this.peer.on(rtcSignals.signal, data => {
47 | resolve(data)
48 | })
49 |
50 | })
51 | }
52 |
53 | /**
54 | * Given a WebRTC offer object (created with the offer() function),
55 | * a receiver can create a WebRTC response in order to create a p2p
56 | * connection between the initiator and receiver.
57 | *
58 | * @param {Object} offer - WebRTC offer object create with offer()
59 | * @return {Object} - WebRTC answer object, to be used by the initiator
60 | */
61 | async answer(offer, iceServers = null) {
62 | return new Promise((resolve, reject) => {
63 | const options = {
64 | trickle: false,
65 | iceTransportPolicy: 'relay',
66 | config: {
67 | iceServers: iceServers ? iceServers : stunServers
68 | },
69 | wrtc: wrtc
70 | }
71 | this.peer = new Peer(options)
72 | this.peer.on(rtcSignals.error, console.log)
73 | this.peer.signal(offer)
74 | this.peer.on(rtcSignals.signal, data => {
75 | resolve(data)
76 | })
77 | })
78 | }
79 |
80 | /**
81 | * Given a WebRTC answer object, complete WebRTC connection.
82 | * @param {Object} answer - WebRTC answer object created by answer()
83 | */
84 | connect(answer) {
85 | this.peer.signal(answer)
86 | }
87 |
88 | /**
89 | * Disconnect from current WebRTC connection
90 | */
91 | disconnect() {
92 | this.peer.destroy()
93 | }
94 |
95 | /**
96 | * On @sigal event sent via WebRTC, perform given fn
97 | * @param {String} signal - WebRTC signal/event. E.g. 'data'
98 | * @param {Function} fn - Callback function to perform on signal event
99 | */
100 | on(signal, fn) {
101 | this.peer.on(signal, fn)
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/connectProvider/platformDeepLinking.js:
--------------------------------------------------------------------------------
1 | import { IOS_LINK, ANDROID_LINK } from '../config';
2 |
3 | const APP_STORE_LINK = IOS_LINK;
4 | const PLAY_STORE_LINK = ANDROID_LINK;
5 | const SCHEMA_BASE = 'mewwallet://dapps';
6 |
7 | export function mobileCheck() {
8 | let check = false;
9 | (function(a) {
10 | // eslint-disable-next-line
11 | if (
12 | /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
13 | a
14 | ) ||
15 | // eslint-disable-next-line
16 | /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
17 | a.substr(0, 4)
18 | )
19 | )
20 | check = true;
21 | })(navigator.userAgent || navigator.vendor || window.opera);
22 | return check;
23 | }
24 | function iOS() {
25 | return ['iPhone Simulator', 'iPhone', 'iPod'].includes(navigator.platform);
26 | }
27 |
28 | export function nativeCheck() {
29 | return new Promise(resolve => {
30 | try {
31 | if (mobileCheck()) {
32 | const fallbackToStore = () => {
33 | if (iOS()) {
34 | window.location.replace(APP_STORE_LINK);
35 | } else {
36 | window.location.replace(PLAY_STORE_LINK);
37 | }
38 | resolve(false);
39 | };
40 | const openApp = () => {
41 | const loc = window.location.origin;
42 | const url = encodeURIComponent(loc);
43 | const scheme = `${SCHEMA_BASE}?url=${url}`;
44 | window.location.replace(scheme);
45 | };
46 | if (iOS()) {
47 | return resolve(true);
48 | }
49 | const triggerAppOpen = () => {
50 | openApp();
51 | setTimeout(fallbackToStore, 1000);
52 | };
53 | triggerAppOpen();
54 | } else {
55 | resolve(true);
56 | }
57 | } catch (e) {
58 | resolve(true);
59 | }
60 | });
61 | }
62 |
--------------------------------------------------------------------------------
/test/utils/websocket-connection.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import queryString from 'query-string'
4 | import webSocketClient from 'promise-ws'
5 |
6 | export default class WebsocketConnection {
7 | constructor(options = {}) {
8 | this.options = options
9 | this.socket = {}
10 | this.listeners = {}
11 | }
12 |
13 | /**
14 | * Connect to a given @websocketURL with given @options query params.
15 | * The client will connect and bind every on "message" event to the
16 | * onMessage() function.
17 | *
18 | * In order to handle a message, the on() member function must be used to add
19 | * an listener. This gives functionality similar to socket.io, in which
20 | * it is possible to so something like:
21 | *
22 | * socket.on('error', err => {})
23 | * as opposed to:
24 | * socket.on('message', message => { if (message.signal === 'error')... })
25 | *
26 | * @param {String} websocketURL - WSS address of websocket API
27 | * @param {Object} options - JSON-formatted connection query params
28 | * @param {String} options.role - Either "initiator" or "receiver" accordingly
29 | * @param {String} options.connId - Last 32 characters of the public key portion of the key-pair
30 | * created for the particular paired connection
31 | * @param {String} options.signed - Private key signed with the private key created for the connection
32 | */
33 | async connect(websocketUrl, options = {}) {
34 | let url = `${websocketUrl}?${queryString.stringify(options)}`
35 | this.socket = await webSocketClient.create(url)
36 | this.socket.on('message', this.onMessage.bind(this))
37 | }
38 |
39 | /**
40 | * On 'message' event, parse the message and if possible,
41 | * call the event listener with the message's particular signal.
42 | *
43 | * Messages are received as stringified JSON objects, that when parsed,
44 | * take the following format:
45 | *
46 | * {
47 | * signal, // This is the signal that the member function on() can bind to
48 | * data, // The actual data payload
49 | * message // Accompanying server message
50 | * }
51 | *
52 | * @param {String} message - Stringified JSON payload sent by the server
53 | * @return {[type]} [description]
54 | */
55 | onMessage(message) {
56 | const parsedMessage = JSON.parse(message)
57 | const signal = parsedMessage.signal
58 | const data = parsedMessage.data
59 |
60 | try {
61 | this.listeners[signal].call(this, data)
62 | } catch (e) {
63 | // Unhandled message signal
64 | }
65 | }
66 |
67 | /**
68 | * Bind an function to a particular message signal event.
69 | * E.G.
70 | * socket.on('error', err => {})
71 | *
72 | * @param {String} signal - The signal to listen for
73 | * @param {Function} fn - Function to perform on message signal
74 | */
75 | on(signal, fn) {
76 | this.listeners[signal] = fn
77 | }
78 |
79 | /**
80 | * Unbind a particular message signal event listener.
81 | *
82 | * @param {String} signal - The signal to unbind
83 | */
84 | off(signal) {
85 | delete this.listeners[signal]
86 | }
87 |
88 | /**
89 | * Send a data payload to a particular signal.
90 | *
91 | * @param {String} signal - Particular action/signal such as "offersignal"
92 | * @param {[type]} data - Data payload
93 | */
94 | send(signal, data = {}) {
95 | const message = JSON.stringify({
96 | action: signal,
97 | data: data
98 | })
99 | this.socket.send(message)
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/providers/ws-provider.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | import Web3WSProvider from './ws-web3-provider';
4 | import { Manager as Web3RequestManager } from 'web3-core-requestmanager';
5 | import MiddleWare from '../middleware';
6 | import workerTimer from '../../helpers/webWorkerTimer/index';
7 | import { v4 as uuidv4 } from 'uuid';
8 | import {
9 | ethSendTransaction,
10 | ethSignTransaction,
11 | ethSign,
12 | personalSign,
13 | ecRecover,
14 | ethAccounts,
15 | ethCoinbase,
16 | netVersion,
17 | decrypt,
18 | signTypedData_v3,
19 | signTypedData_v4,
20 | getEncryptionPublicKey,
21 | ethRequestAccounts
22 | } from '../methods/index';
23 |
24 | class WSProvider {
25 | constructor(host, options, store, eventHub) {
26 | this.wsProvider = new Web3WSProvider(host, options);
27 | this.lastMessage = new Date().getTime();
28 | const keepAlive = () => {
29 | if (
30 | this.wsProvider.connection.readyState ===
31 | this.wsProvider.connection.OPEN
32 | )
33 | this.wsProvider.connection.send('');
34 | if (
35 | !Object.is(this.wsProvider, store.state.web3.currentProvider) &&
36 | this.lastMessage + 10 * 60 * 1000 < new Date().getTime() //wait extra 10 minutes
37 | ) {
38 | this.wsProvider.disconnect();
39 | workerTimer.clearInterval(this.keepAliveTimer);
40 | }
41 | };
42 | this.keepAliveTimer = workerTimer.setInterval(keepAlive, 5000);
43 | const _this = this.wsProvider;
44 | delete this.wsProvider['send'];
45 | this.wsProvider.send = (payload, callback) => {
46 | this.lastMessage = new Date().getTime();
47 | if (_this.connection.readyState === _this.connection.CONNECTING) {
48 | setTimeout(() => {
49 | this.wsProvider.send(payload, callback);
50 | }, 100);
51 | return;
52 | }
53 | if (_this.connection.readyState !== _this.connection.OPEN) {
54 | if (typeof _this.connection.onerror === 'function') {
55 | _this.connection.onerror(new Error('connection not open'));
56 | }
57 | callback(new Error('connection not open'));
58 | return;
59 | }
60 | const req = {
61 | payload,
62 | store,
63 | eventHub
64 | };
65 | const middleware = new MiddleWare();
66 | middleware.use(ethSendTransaction);
67 | middleware.use(ethSignTransaction);
68 | middleware.use(ethSign);
69 | middleware.use(personalSign);
70 | middleware.use(ecRecover);
71 | middleware.use(ethAccounts);
72 | middleware.use(ethCoinbase);
73 | middleware.use(ethRequestAccounts);
74 | middleware.use(netVersion);
75 | middleware.use(decrypt);
76 | middleware.use(signTypedData_v3);
77 | middleware.use(signTypedData_v4);
78 | middleware.use(getEncryptionPublicKey);
79 | middleware.run(req, callback).then(() => {
80 | _this.connection.send(JSON.stringify(payload));
81 | _this._addResponseCallback(payload, callback);
82 | });
83 | };
84 | this.wsProvider.request = payload => {
85 | return new Promise((resolve, reject) => {
86 | this.wsProvider.send(
87 | {
88 | jsonrpc: '2.0',
89 | id: uuidv4(),
90 | method: payload.method,
91 | params: payload.params
92 | },
93 | (err, res) => {
94 | if (err) return reject(err);
95 | else if (res.error) return reject(res.error);
96 | resolve(res.result);
97 | }
98 | );
99 | });
100 | };
101 | return this.wsProvider;
102 | }
103 | }
104 |
105 | export default WSProvider;
106 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/WalletInterface.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | import {
4 | getBufferFromHex,
5 | getSignTransactionObject,
6 | sanitizeHex,
7 | calculateChainIdFromV
8 | } from './utils';
9 | import {
10 | hashPersonalMessage,
11 | publicToAddress,
12 | bufferToHex,
13 | ecsign,
14 | isValidPrivate,
15 | isValidPublic,
16 | privateToPublic,
17 | isHexString,
18 | toBuffer as utilsToBuffer
19 | } from 'ethereumjs-utils';
20 | import { toChecksumAddress } from './helpers/addressUtils';
21 |
22 | const toBuffer = v => {
23 | if (isHexString(v)) {
24 | return utilsToBuffer(v);
25 | }
26 | return Buffer.from(v);
27 | };
28 |
29 | class WalletInterface {
30 | constructor(key, isPub = false, identifier, nick, keystore) {
31 | this.nickname = nick !== null && nick !== '' ? nick : '';
32 | this.keystore = keystore !== null && keystore !== '' ? keystore : '';
33 | this.identifier = identifier;
34 | if (!isPub) {
35 | const _privKey = Buffer.isBuffer(key)
36 | ? key
37 | : getBufferFromHex(sanitizeHex(key));
38 | if (!isValidPrivate(_privKey))
39 | throw new Error(
40 | 'Private key does not satisfy the curve requirements (ie. it is invalid)'
41 | );
42 | this.privateKey = _privKey;
43 | this.publicKey = privateToPublic(_privKey);
44 | this.isPubOnly = false;
45 | } else {
46 | const _pubKey = Buffer.isBuffer(key) ? key : getBufferFromHex(key);
47 | if (_pubKey.length !== 20 && !isValidPublic(_pubKey, true))
48 | throw new Error('Invalid public key');
49 | if (_pubKey.length === 20) this.isAddress = true;
50 | this.publicKey = _pubKey;
51 | this.isPubOnly = true;
52 | }
53 | }
54 |
55 | getPrivateKey() {
56 | if (this.isPubOnly) throw new Error('public key only wallet');
57 | return this.privateKey;
58 | }
59 |
60 | getPrivateKeyString() {
61 | if (this.isPubOnly) throw new Error('public key only wallet');
62 | return bufferToHex(this.getPrivateKey());
63 | }
64 |
65 | getNickname() {
66 | if (this.nickname === '') return '';
67 | return this.nickname;
68 | }
69 |
70 | getKeystore() {
71 | if (this.keystore === '') return '';
72 | return this.keystore;
73 | }
74 |
75 | getPublicKey() {
76 | if (this.isAddress) throw new Error('Address only wallet');
77 | return this.publicKey;
78 | }
79 |
80 | getPublicKeyString() {
81 | return bufferToHex(this.getPublicKey());
82 | }
83 |
84 | getAddress() {
85 | if (this.isAddress) return this.publicKey;
86 | return publicToAddress(this.publicKey, true);
87 | }
88 |
89 | getAddressString() {
90 | return bufferToHex(this.getAddress());
91 | }
92 |
93 | getChecksumAddressString() {
94 | return toChecksumAddress(this.getAddressString());
95 | }
96 |
97 | signTransaction(txParams, signer) {
98 | if (this.isPubOnly && typeof signer !== 'function')
99 | throw new Error('public key only wallets needs a signer');
100 | return new Promise((resolve, reject) => {
101 | signer(txParams)
102 | .then(resolve)
103 | .catch(reject);
104 | // }
105 | });
106 | }
107 |
108 | signMessage(msg, signer) {
109 | if (this.isPubOnly && typeof signer !== 'function')
110 | throw new Error('public key only wallets needs a signer');
111 | return new Promise((resolve, reject) => {
112 | if (!this.isPubOnly) {
113 | const msgHash = hashPersonalMessage(toBuffer(msg));
114 | const signed = ecsign(msgHash, this.privateKey);
115 | resolve(
116 | Buffer.concat([
117 | Buffer.from(signed.r),
118 | Buffer.from(signed.s),
119 | Buffer.from([signed.v])
120 | ])
121 | );
122 | } else {
123 | signer(msg)
124 | .then(resolve)
125 | .catch(reject);
126 | }
127 | });
128 | }
129 | }
130 |
131 | export default WalletInterface;
132 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/methods/eth_sendTransaction.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import EventNames from '../events';
3 | import { toPayload, toError } from '../jsonrpc';
4 | import { getSanitizedTx } from './utils';
5 | import BigNumber from 'bignumber.js';
6 | import debugLogger from 'debug';
7 | const debug = debugLogger('MEWconnectWeb3');
8 | const debugErrors = debugLogger('MEWconnectError');
9 |
10 | const setEvents = (promiObj, tx, eventHub) => {
11 | promiObj
12 | .once('transactionHash', hash => {
13 | eventHub.emit('Hash', hash);
14 | })
15 | .once('receipt', res => {
16 | eventHub.emit('Receipt', res);
17 | })
18 | .on('error', err => {
19 | eventHub.emit('Error', err);
20 | });
21 | };
22 | export default async ({ payload, store, eventHub }, res, next) => {
23 | if (payload.method !== 'eth_sendTransaction') return next();
24 | const tx = Object.assign({}, payload.params[0]);
25 | const localTx = Object.assign({}, tx);
26 | delete localTx['gas'];
27 | delete localTx['nonce'];
28 | try {
29 | if (!store.state.wallet) {
30 | eventHub.emit(EventNames.WALLET_NOT_CONNECTED);
31 | debug('NOT ACTIVE WALLET IDENTIFIED');
32 | res(toError(payload.id, 'No active wallet: eth_sendTransaction', 4002));
33 | return;
34 | }
35 | tx.nonce = !tx.nonce
36 | ? await store.state.web3.eth.getTransactionCount(
37 | store.state.wallet.getAddressString()
38 | )
39 | : tx.nonce;
40 | if (tx.gasLimit && !tx.gas) {
41 | tx.gas = tx.gasLimit;
42 | } else if (!tx.gasLimit && tx.gas) {
43 | tx.gasLimit = tx.gas;
44 | }
45 | tx.gas = !tx.gas ? await store.state.web3.eth.estimateGas(localTx) : tx.gas;
46 | tx.gasPrice = !tx.gasPrice
47 | ? await store.state.web3.eth.getGasPrice()
48 | : tx.gasPrice;
49 | tx.chainId = !tx.chainId ? store.state.network.chainID : tx.chainId;
50 | } catch (e) {
51 | eventHub.emit(EventNames.ERROR_NOTIFY, e);
52 | debugErrors(e);
53 | res(e);
54 | return;
55 | }
56 | debug('RAW TX', tx);
57 | getSanitizedTx(tx)
58 | .then(_tx => {
59 | debug('TX', _tx);
60 | eventHub.emit(EventNames.SHOW_TX_CONFIRM_MODAL, _tx, _response => {
61 | if (_response.reject) {
62 | debug('USER DECLINED SIGN TRANSACTION & SEND');
63 | res(toError(payload.id, 'User Rejected Request', 4001));
64 | return;
65 | }
66 | debug('broadcasting', payload.method, _response.rawTransaction);
67 | const _promiObj = store.state.web3.eth.sendSignedTransaction(
68 | _response.rawTransaction
69 | );
70 | _promiObj
71 | .once('transactionHash', hash => {
72 | if (store.state.wallet !== null) {
73 | if (store.noSubs) {
74 | const txHash = hash;
75 | const start = Date.now();
76 | const interval = setInterval(() => {
77 | store.state.web3.eth
78 | .getTransactionReceipt(txHash)
79 | .then(result => {
80 | if (result !== null) {
81 | clearInterval(interval);
82 | _promiObj.emit('receipt', result);
83 | return;
84 | }
85 | const cancelInterval =
86 | (Date.now() - start) / 1000 > 60 * 60;
87 | if (cancelInterval) {
88 | clearInterval(interval);
89 | }
90 | })
91 | .catch(err => {
92 | eventHub.emit(EventNames.ERROR_NOTIFY, err);
93 | _promiObj.emit('error', err);
94 | });
95 | }, 5000);
96 | }
97 | }
98 | res(null, toPayload(payload.id, hash));
99 | })
100 | .on('error', err => {
101 | eventHub.emit(EventNames.ERROR_NOTIFY, err);
102 | debugErrors('Error: eth_sendTransaction', err);
103 | res(err);
104 | });
105 | setEvents(_promiObj, _tx, eventHub);
106 | });
107 | })
108 | .catch(e => {
109 | res(e);
110 | });
111 | };
112 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/helpers/webWorkerTimer/index.js:
--------------------------------------------------------------------------------
1 | const createTimerObject = () => {
2 | const Timer = class {
3 | static setTimeout(cb, ms) {
4 | return setTimeout(cb, ms);
5 | }
6 |
7 | static clearTimeout(id) {
8 | return clearTimeout(id);
9 | }
10 |
11 | static setInterval(cb, ms) {
12 | return setInterval(cb, ms);
13 | }
14 |
15 | static clearInterval(id) {
16 | return clearInterval(id);
17 | }
18 |
19 | static setImmediate(cb) {
20 | if (typeof setImmediate == 'function') {
21 | return setImmediate(cb);
22 | }
23 |
24 | return setTimeout(cb);
25 | }
26 | };
27 | return Timer;
28 | };
29 |
30 | const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
31 |
32 | const _timers = new Map();
33 |
34 | const _SetTimeoutType = 0;
35 | const _SetIntervalType = 1;
36 | const _SetImmediateType = 2;
37 | const _ClearTimeoutType = 3;
38 | const _ClearIntervalType = 4;
39 |
40 | let worker;
41 |
42 | let _nextId = 0;
43 | const nextId = function() {
44 | if (_nextId == MAX_SAFE_INTEGER) {
45 | _nextId = 0;
46 | }
47 | return _nextId++;
48 | };
49 |
50 | class Timer {
51 | static setTimeout(cb, ms) {
52 | const id = nextId();
53 | _timers.set(id, cb);
54 | worker.postMessage({ type: _SetTimeoutType, id: id, ms: ms });
55 | return id;
56 | }
57 |
58 | static clearTimeout(id) {
59 | _timers.delete(id);
60 | worker.postMessage({ type: _ClearTimeoutType, id: id });
61 | }
62 |
63 | static setInterval(cb, ms) {
64 | const id = nextId();
65 | _timers.set(id, cb);
66 | worker.postMessage({ type: _SetIntervalType, id: id, ms: ms });
67 | return id;
68 | }
69 |
70 | static clearInterval(id) {
71 | _timers.delete(id);
72 | worker.postMessage({ type: _ClearIntervalType, id: id });
73 | }
74 |
75 | static setImmediate(cb) {
76 | const id = nextId();
77 | _timers.set(id, cb);
78 | worker.postMessage({ type: _SetImmediateType, id: id });
79 | return id;
80 | }
81 |
82 | static onmessage(e) {
83 | const cb = _timers.get(e.data.id);
84 | if (cb !== undefined) {
85 | cb.call();
86 | if (e.data.type !== _SetIntervalType) {
87 | _timers.delete(e.data.id);
88 | }
89 | }
90 | }
91 | }
92 |
93 | const workerCode = function() {
94 | return (
95 | '(' +
96 | function() {
97 | const _wSetTimeoutType = 0;
98 | const _wSetIntervalType = 1;
99 | const _wSetImmediateType = 2;
100 | const _wClearTimeoutType = 3;
101 | const _wClearIntervalType = 4;
102 | const timers = {};
103 | self.onmessage = e => {
104 | if (e.data.type == _wSetTimeoutType) {
105 | timers[e.data.id] = setTimeout(
106 | () => self.postMessage(e.data),
107 | e.data.ms
108 | );
109 | } else if (e.data.type == _wSetIntervalType) {
110 | timers[e.data.id] = setInterval(
111 | () => self.postMessage(e.data),
112 | e.data.ms
113 | );
114 | } else if (e.data.type == _wSetImmediateType) {
115 | self.postMessage(e.data);
116 | } else if (e.data.type == _wClearTimeoutType) {
117 | clearTimeout(timers[e.data.id]);
118 | delete timers[e.data.id];
119 | } else if (e.data.type == _wClearIntervalType) {
120 | clearInterval(timers[e.data.id]);
121 | delete timers[e.data.id];
122 | }
123 | };
124 | }.toString() +
125 | '());'
126 | );
127 | };
128 | const getTimer = () => {
129 | if (
130 | typeof navigator !== 'undefined' &&
131 | (navigator.userAgent.indexOf('MSIE') !== -1 ||
132 | navigator.userAgent.match(/Trident.*rv:11\./))
133 | ) {
134 | return createTimerObject();
135 | } else if (
136 | typeof WorkerGlobalScope !== 'undefined' &&
137 | self instanceof WorkerGlobalScope // eslint-disable-line
138 | ) {
139 | return createTimerObject();
140 | } else if (worker === undefined) {
141 | const url = URL.createObjectURL(
142 | new Blob([workerCode()], { type: 'text/javascript' })
143 | );
144 | worker = new Worker(url);
145 | worker.onmessage = Timer.onmessage;
146 | return Timer;
147 | }
148 | };
149 | export default getTimer();
150 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@myetherwallet/mewconnect-web-client",
3 | "homepage": "https://github.com/myetherwallet/MEWconnect-web-client",
4 | "version": "2.2.0-beta.18",
5 | "main": "dist/cjs/index.js",
6 | "module": "dist/esm/index.js",
7 | "scripts": {
8 | "start": "./node_modules/.bin/vue-cli-service serve --https example/app/src/main.js",
9 | "test:jest": "npx jest --detectOpenHandles --forceExit --runInBand",
10 | "test:browser": "npx opn ./tests/browser/browser_test.html",
11 | "test:old": "npm run buildBrowserTest && npm run test:jest && npm run test:browser",
12 | "test": "npm run test:jest",
13 | "buildBrowserTest": "webpack --config tests/browser/webpack.config.js",
14 | "buildBrowserTest:watch": "webpack --config tests/browser/webpack.config.js -w",
15 | "build": "npx npm-force-resolutions && npm install && npm run lint && rimraf dist/ && npx rollup -c",
16 | "build:dev": "rimraf dist/ && npx rollup -c",
17 | "lint": "npx eslint --fix 'src/**.js'",
18 | "update:mainlist": "node src/connectProvider/fetchLists/fetchMainLists.js",
19 | "update:lists": "npm run update:mainlist && node src/connectProvider/fetchLists/index.js",
20 | "prepublishOnly": "npm install && npm run update:lists && npm run build",
21 | "prepack": "npm run build",
22 | "ci": "npm install && npm run update:lists && npm run build"
23 | },
24 | "gitHooks": {
25 | "pre-commit": "npm run lint"
26 | },
27 | "dependencies": {
28 | "@rollup/plugin-babel": "^5.3.0",
29 | "@rollup/plugin-commonjs": "^20.0.0",
30 | "@rollup/plugin-json": "^4.1.0",
31 | "bignumber.js": "^9.0.0",
32 | "browser-or-node": "^1.2.1",
33 | "core-js": "^3.4.4",
34 | "debug": "^4.0.1",
35 | "detect-browser": "^3.0.1",
36 | "eccrypto": "^1.1.6",
37 | "eth-sig-util": "^3.0.1",
38 | "ethereumjs-common": "^1.5.0",
39 | "ethereumjs-tx": "^2.1.2",
40 | "ethereumjs-utils": "^5.2.5",
41 | "ethjs-unit": "^0.1.6",
42 | "events": "^3.1.0",
43 | "isomorphic-ws": "^4.0.1",
44 | "logging": "^3.2.0",
45 | "mocha": "^5.2.0",
46 | "node-fetch": "^2.6.0",
47 | "platform": "^1.3.5",
48 | "promise-ws": "^1.0.0-1",
49 | "qrcode": "^1.5.0",
50 | "query-string": "^6.10.1",
51 | "secp256k1": "^3.8.0",
52 | "simple-peer": "^9.6.2",
53 | "socket.io-client": "^2.3.0",
54 | "store": "^2.0.12",
55 | "underscore": "^1.13.2",
56 | "uuid": "^3.4.0",
57 | "vue": "^2.6.10",
58 | "web3": "1.5.0",
59 | "web3-core-helpers": "1.5.0",
60 | "web3-core-method": "1.5.0",
61 | "web3-core-requestmanager": "1.5.0",
62 | "web3-utils": "1.5.0",
63 | "webrtc-adapter": "^6.4.3",
64 | "wrtc": "^0.4.6",
65 | "ws": "^7.5.3"
66 | },
67 | "devDependencies": {
68 | "@babel/core": "^7.8.4",
69 | "@babel/plugin-external-helpers": "^7.8.3",
70 | "@babel/plugin-transform-async-to-generator": "^7.8.3",
71 | "@babel/plugin-transform-regenerator": "^7.8.3",
72 | "@babel/plugin-transform-runtime": "^7.8.3",
73 | "@babel/plugin-transform-spread": "^7.8.3",
74 | "@babel/preset-env": "^7.8.4",
75 | "@rollup/plugin-image": "^2.1.0",
76 | "@vue/cli-plugin-babel": "^4.1.0",
77 | "@vue/cli-plugin-eslint": "^4.2.3",
78 | "@vue/cli-service": "^4.1.0",
79 | "@vue/eslint-config-prettier": "^4.0.1",
80 | "axios": "^0.21.4",
81 | "babel-core": "^7.0.0-bridge.0",
82 | "babel-eslint": "^10.0.3",
83 | "babel-jest": "^25.1.0",
84 | "babel-preset-es2015-rollup": "^3.0.0",
85 | "chai": "^4.2.0",
86 | "clean-webpack-plugin": "^3.0.0",
87 | "eslint": "^6.8.0",
88 | "eslint-config-airbnb-base": "^13.2.0",
89 | "eslint-config-prettier": "^3.0.1",
90 | "eslint-plugin-import": "^2.20.1",
91 | "eslint-plugin-security": "^1.4.0",
92 | "eslint-plugin-vue": "^6.2.1",
93 | "jest": "^25.2.3",
94 | "node-sass": "^4.12.0",
95 | "nyc": "^15.0.0",
96 | "opn": "^5.5.0",
97 | "opn-cli": "^3.1.0",
98 | "regenerator-runtime": "^0.13.3",
99 | "rimraf": "^2.7.1",
100 | "rollup": "^2.56.2",
101 | "rollup-plugin-json": "^3.1.0",
102 | "sass-loader": "^8.0.0",
103 | "style-loader": "^1.1.3",
104 | "svg-inline-loader": "^0.8.0",
105 | "url-loader": "^3.0.0",
106 | "vue-template-compiler": "^2.6.10",
107 | "yorkie": "^2.0.0"
108 | },
109 | "resolutions": {
110 | "xmlhttprequest-ssl": "1.6.1"
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/web3-provider/providers/http-provider.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | import HttpRequestManger from './http-request-manager';
4 | import MiddleWare from '../middleware';
5 | import {
6 | ethSendTransaction,
7 | ethSignTransaction,
8 | ethSign,
9 | ethAccounts,
10 | ethCoinbase,
11 | netVersion,
12 | personalSign,
13 | ecRecover,
14 | decrypt,
15 | signTypedData_v3,
16 | signTypedData_v4,
17 | getEncryptionPublicKey,
18 | ethRequestAccounts
19 | } from '../methods/index';
20 | import { v4 as uuidv4 } from 'uuid';
21 | class HttpProvider {
22 | constructor(host, options, store, eventHub) {
23 | const requestManager = new HttpRequestManger(host, options);
24 | this.httpProvider = {
25 | send: (payload, callback) => {
26 | const req = {
27 | payload,
28 | store,
29 | eventHub
30 | };
31 | const middleware = new MiddleWare();
32 | middleware.use(ethSendTransaction);
33 | middleware.use(ethSignTransaction);
34 | middleware.use(ethSign);
35 | middleware.use(personalSign);
36 | middleware.use(ecRecover);
37 | middleware.use(ethAccounts);
38 | middleware.use(ethCoinbase);
39 | middleware.use(ethRequestAccounts);
40 | middleware.use(netVersion);
41 | middleware.use(decrypt);
42 | middleware.use(signTypedData_v3);
43 | middleware.use(signTypedData_v4);
44 | middleware.use(getEncryptionPublicKey);
45 | middleware.run(req, callback).then(() => {
46 | requestManager.provider.send(payload, callback);
47 | });
48 | },
49 | notificationCallbacks: [],
50 | disconnectCallbacks: [],
51 | closeCallbacks: [],
52 | accountsChangedCallbacks: [],
53 | createSubscriptions: subscription => {
54 | requestManager.addSubscription();
55 | },
56 | on: (type, callback) => {
57 | if (typeof callback !== 'function')
58 | throw new Error('The second parameter callback must be a function.');
59 |
60 | switch (type) {
61 | case 'data':
62 | this.httpProvider.notificationCallbacks.push(callback);
63 | this.httpProvider.dataCallback = callback;
64 | break;
65 | case 'accountsChanged':
66 | this.httpProvider.accountsChangedCallbacks.push(callback);
67 | this.accountsChanged = callback;
68 | break;
69 | case 'disconnected':
70 | this.httpProvider.disconnectedCallback = callback;
71 | break;
72 | case 'disconnect':
73 | this.httpProvider.disconnectCallbacks.push(callback);
74 | this.httpProvider.disconnectCallback = callback;
75 | break;
76 | case 'close':
77 | this.httpProvider.closeCallbacks.push(callback);
78 | this.httpProvider.closeCallback = callback;
79 | break;
80 | }
81 | },
82 | emit: (type, data) => {
83 | if (typeof type !== 'string')
84 | throw new Error('The first parameter type must be a string.');
85 |
86 | switch (type) {
87 | case 'accountsChanged':
88 | this.httpProvider.accountsChangedCallbacks.forEach(function(
89 | callback
90 | ) {
91 | if (typeof callback === 'function') callback(data);
92 | });
93 | break;
94 | case 'disconnect':
95 | this.httpProvider.disconnectCallbacks.forEach(function(callback) {
96 | if (typeof callback === 'function') callback(data);
97 | });
98 | break;
99 | case 'close':
100 | this.httpProvider.closeCallbacks.forEach(function(callback) {
101 | if (typeof callback === 'function') callback(data);
102 | });
103 | break;
104 | }
105 | }
106 | };
107 | this.httpProvider.request = payload => {
108 | return new Promise((resolve, reject) => {
109 | this.httpProvider.send(
110 | {
111 | jsonrpc: '2.0',
112 | id: uuidv4(),
113 | method: payload.method,
114 | params: payload.params
115 | },
116 | (err, res) => {
117 | if (err) return reject(err);
118 | else if (res.error) return reject(res.error);
119 | resolve(res.result);
120 | }
121 | );
122 | });
123 | };
124 | return this.httpProvider;
125 | }
126 | }
127 | export default HttpProvider;
128 |
--------------------------------------------------------------------------------
/src/connectWindow/images/closeIconWhite.js:
--------------------------------------------------------------------------------
1 | const icon =
2 | 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWAAAAIACAMAAACLo0a5AAACAVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9n7yP8AAAAqnRSTlMAAQIDBAUGBwgLDA0ODxESExQVFxgZGhscHR4fICEiIyQlJicoKS0wMTIzNTc4OTs8PT5AQUJDREVGR0hJS15fYGRlZmhpam1ub3BxcnN0d3l6fICGh4iJiouMlpeYmZqbnJ6foKGipKqtrq+wsbKztLW2t7i5uru8vb6/xcbHyMnM0dLT1NfY2drb3N3f4OHi4+Tl5ufo6err7O3u8PHy8/T19vf4+fr7/H3oGy4AAAABYktHRKq+Ble+AAALB0lEQVR42u3de2NUxRnH8WcbNggWJRVvLW2kSlsvaZR201I0xaqtIWAvFKiVBmktVglgaTXB2lWLqFDl0hSCija7ZIk+r7J/hEsSk+zZc2bOPJff9w3MzIeHyWU3Z4kQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQggh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';
3 |
4 | export default icon;
5 |
--------------------------------------------------------------------------------
/test/utils/crypto-utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import crypto from 'crypto';
4 | import eccrypto from 'eccrypto';
5 | import ethUtils from 'ethereumjs-utils';
6 | import secp256k1 from 'secp256k1';
7 |
8 | export default (() => {
9 | /**
10 | * Generate a public/private keypair using secp256k1
11 | *
12 | * @return {Object} - publicKey/privateKey object
13 | */
14 | const generateKeys = () => {
15 | const privateKey = Buffer.from(crypto.randomBytes(32), 'hex');
16 | const publicKey = secp256k1.publicKeyCreate(privateKey);
17 | return {
18 | publicKey,
19 | privateKey
20 | };
21 | };
22 |
23 | /**
24 | * Generate a connId using given a public key
25 | *
26 | * @param {String} publicKey - publicKey string (usually generated with generateKeys())
27 | * @return {String} - connId string
28 | */
29 | const generateConnId = publicKey => {
30 | return publicKey.toString('hex').slice(-32);
31 | };
32 |
33 | /**
34 | * Generate a random message of 32 bytes
35 | *
36 | * @return {String} - The randomly generated string
37 | */
38 | const generateRandomMessage = () => {
39 | return crypto.randomBytes(32).toString('hex');
40 | };
41 |
42 | const bufferToString = buf => {
43 | if (buf instanceof Buffer) {
44 | return buf.toString('hex');
45 | }
46 | return buf;
47 | };
48 |
49 | /**
50 | * Sign a message using a privateKey
51 | *
52 | * @param {String} msg - Message to sign/hash
53 | * @param {[type]} privateKey - Private key (usually generated with generateKeys())
54 | * @return {String} - Signed message
55 | */
56 | const signMessage = (msg, privateKey) => {
57 | const hashedMsg = ethUtils.hashPersonalMessage(
58 | ethUtils.toBuffer(bufferToString(msg))
59 | );
60 | const signed = ethUtils.ecsign(
61 | Buffer.from(hashedMsg),
62 | Buffer.from(privateKey, 'hex')
63 | );
64 | const combined = Buffer.concat([
65 | Buffer.from([signed.v]),
66 | Buffer.from(signed.r),
67 | Buffer.from(signed.s)
68 | ]);
69 | const combinedHex = combined.toString('hex');
70 | return combinedHex;
71 | };
72 |
73 | /**
74 | * Encrypt a set of data given a private key using eccrypto
75 | *
76 | * @param {Object/String} data - Data to encrypt
77 | * @param {String} privateKey - Private key (usually generated with generateKeys())
78 | * @return {Object} - Encrypted data object with the following properties:
79 | * 'ciphertext', 'ephemPublicKey', 'iv', 'mac'
80 | */
81 | const encrypt = async (data, privateKey) => {
82 | return new Promise((resolve, reject) => {
83 | const publicKey = eccrypto.getPublic(privateKey);
84 | eccrypto
85 | .encrypt(publicKey, Buffer.from(data))
86 | .then(encryptedData => {
87 | resolve(encryptedData);
88 | })
89 | .catch(error => {
90 | reject(error);
91 | });
92 | });
93 | };
94 |
95 | /**
96 | * Decrypt an encrypted data object given a private key using eccrypto
97 | *
98 | * @param {Object} data - An encrypted data object (usually using the encrypt() function)
99 | * @param {String} privateKey - Private key (usually generated with generateKeys())
100 | * @return {Object} - Decrypted data
101 | */
102 | const decrypt = async (data, privateKey) => {
103 | return new Promise((resolve, reject) => {
104 | eccrypto
105 | .decrypt(privateKey, {
106 | ciphertext: Buffer.from(data.ciphertext),
107 | ephemPublicKey: Buffer.from(data.ephemPublicKey),
108 | iv: Buffer.from(data.iv),
109 | mac: Buffer.from(data.mac)
110 | })
111 | .then(decrypted => {
112 | let result;
113 | try {
114 | if (isJSON(decrypted)) {
115 | const humanRadable = JSON.parse(decrypted);
116 | if (Array.isArray(humanRadable)) {
117 | result = humanRadable[0];
118 | } else {
119 | result = humanRadable;
120 | }
121 | } else {
122 | result = decrypted.toString();
123 | }
124 | } catch (e) {
125 | reject(e);
126 | }
127 | resolve(JSON.stringify(result));
128 | })
129 | .catch(error => {
130 | reject(error);
131 | });
132 | });
133 | };
134 |
135 | const isJSON = arg => {
136 | try {
137 | JSON.parse(arg);
138 | return true;
139 | } catch (e) {
140 | return false;
141 | }
142 | };
143 |
144 | return {
145 | generateKeys,
146 | generateConnId,
147 | generateRandomMessage,
148 | signMessage,
149 | encrypt,
150 | decrypt
151 | };
152 | })();
153 |
--------------------------------------------------------------------------------
/src/connectClient/MewConnectCrypto.js:
--------------------------------------------------------------------------------
1 | import eccrypto from 'eccrypto';
2 | import ethUtils from 'ethereumjs-utils';
3 | import crypto from 'crypto';
4 | import secp256k1 from 'secp256k1';
5 |
6 | export default class MewConnectCrypto {
7 | static create() {
8 | return new MewConnectCrypto();
9 | }
10 |
11 | setPrivate(pvtKey) {
12 | this.prvt = Buffer.from(pvtKey, 'hex');
13 | this.pub = this.generatePublic(this.prvt);
14 | return { publicKey: this.pub, privateKey: this.prvt };
15 | }
16 |
17 | generateMessage() {
18 | return crypto.randomBytes(32).toString('hex');
19 | }
20 |
21 | // Not for the Address, but generate them for the connection check
22 | prepareKey() {
23 | this.prvt = this.generatePrivate();
24 | this.pub = this.generatePublic(this.prvt);
25 | return { pub: this.pub, pvt: this.prvt };
26 | }
27 |
28 | generateKeys() {
29 | this.prvt = this.generatePrivate();
30 | this.pub = this.generatePublic(this.prvt);
31 | return { publicKey: this.pub, privateKey: this.prvt };
32 | }
33 |
34 | generatePrivate() {
35 | let privKey;
36 | do {
37 | privKey = crypto.randomBytes(32);
38 | } while (!secp256k1.privateKeyVerify(privKey));
39 | return privKey;
40 | }
41 |
42 | generatePublic(privKey) {
43 | const pvt = Buffer.from(privKey, 'hex');
44 | this.prvt = pvt;
45 | return secp256k1.publicKeyCreate(pvt);
46 | }
47 |
48 | encrypt(dataToSend) {
49 | const publicKeyA = eccrypto.getPublic(this.prvt);
50 | return new Promise((resolve, reject) => {
51 | eccrypto
52 | .encrypt(publicKeyA, Buffer.from(dataToSend))
53 | .then(_initial => {
54 | resolve(_initial);
55 | })
56 | .catch(error => {
57 | reject(error);
58 | });
59 | });
60 | }
61 |
62 | decrypt(dataToSee) {
63 | return new Promise((resolve, reject) => {
64 | eccrypto
65 | .decrypt(this.prvt, {
66 | ciphertext: Buffer.from(dataToSee.ciphertext),
67 | ephemPublicKey: Buffer.from(dataToSee.ephemPublicKey),
68 | iv: Buffer.from(dataToSee.iv),
69 | mac: Buffer.from(dataToSee.mac)
70 | })
71 | .then(_initial => {
72 | let result;
73 | try {
74 | if (this.isJSON(_initial)) {
75 | const humanRadable = JSON.parse(_initial);
76 | if (Array.isArray(humanRadable)) {
77 | result = humanRadable[0];
78 | } else {
79 | result = humanRadable;
80 | }
81 | } else {
82 | result = _initial.toString();
83 | }
84 | } catch (e) {
85 | console.error(e);
86 | }
87 | resolve(JSON.stringify(result));
88 | })
89 | .catch(error => {
90 | reject(error);
91 | });
92 | });
93 | }
94 |
95 | signMessage(msgToSign) {
96 | return new Promise((resolve, reject) => {
97 | try {
98 | const msg = ethUtils.hashPersonalMessage(ethUtils.toBuffer(msgToSign));
99 | const signed = ethUtils.ecsign(
100 | Buffer.from(msg),
101 | Buffer.from(this.prvt, 'hex')
102 | );
103 | const combined = Buffer.concat([
104 | Buffer.from([signed.v]),
105 | Buffer.from(signed.r),
106 | Buffer.from(signed.s)
107 | ]);
108 | const combinedHex = combined.toString('hex');
109 | resolve(combinedHex);
110 | } catch (e) {
111 | reject(e);
112 | }
113 | });
114 | }
115 |
116 | signMessageSync(msgToSign) {
117 | msgToSign = this.bufferToString(msgToSign);
118 |
119 | const msg = ethUtils.hashPersonalMessage(ethUtils.toBuffer(msgToSign));
120 | const signed = ethUtils.ecsign(
121 | Buffer.from(msg),
122 | Buffer.from(this.prvt, 'hex')
123 | );
124 | const combined = Buffer.concat([
125 | Buffer.from([signed.v]),
126 | Buffer.from(signed.r),
127 | Buffer.from(signed.s)
128 | ]);
129 | return combined.toString('hex');
130 | }
131 |
132 | bufferToConnId(buf) {
133 | return buf.toString('hex').slice(0, 32);
134 | }
135 |
136 | generateConnId(buf) {
137 | if (buf instanceof Buffer) {
138 | return buf.toString('hex').slice(0, 32);
139 | }
140 | return Buffer.from(buf)
141 | .toString('hex')
142 | .slice(0, 32);
143 | }
144 |
145 | isJSON(arg) {
146 | try {
147 | JSON.parse(arg);
148 | return true;
149 | } catch (e) {
150 | return false;
151 | }
152 | }
153 |
154 | toBuffer(buf) {
155 | if (buf instanceof Buffer) {
156 | return buf;
157 | }
158 | return Buffer.from(buf, 'hex');
159 | }
160 |
161 | bufferToString(buf) {
162 | if (buf instanceof Buffer) {
163 | return buf.toString('hex');
164 | }
165 | return buf;
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/connectClient/MewConnectCommon.js:
--------------------------------------------------------------------------------
1 | import EventEmitter from 'events';
2 | import { isBrowser } from 'browser-or-node';
3 | import { detect } from 'detect-browser';
4 |
5 | import {
6 | versions,
7 | connectionCodeSchemas,
8 | connectionCodeSeparator,
9 | signalServer,
10 | signals,
11 | signal,
12 | rtc,
13 | iceConnectionState,
14 | stages,
15 | lifeCycle,
16 | communicationTypes
17 | } from './constants/index';
18 | import { stunServers } from './config';
19 |
20 | export default class MewConnectCommon extends EventEmitter {
21 | constructor(version = -1) {
22 | super();
23 |
24 | this.isBrowser = isBrowser;
25 |
26 | this.jsonDetails = {
27 | stunSrvers: [...stunServers],
28 | signalServer: signalServer(version),
29 | signals: {
30 | ...signal(version)
31 | },
32 | signalsV1: {
33 | ...signals.V1
34 | },
35 | signalsV2: {
36 | ...signals.V2
37 | },
38 | stages: {
39 | ...stages
40 | },
41 | lifeCycle: {
42 | ...lifeCycle
43 | },
44 | rtc: {
45 | ...rtc
46 | },
47 | communicationTypes: {
48 | ...communicationTypes
49 | },
50 | iceConnectionState: {
51 | ...iceConnectionState
52 | },
53 | connectionCodeSeparator,
54 | version,
55 | versions,
56 | connectionCodeSchemas
57 | };
58 | }
59 |
60 | isJSON(arg) {
61 | try {
62 | JSON.parse(arg);
63 | return true;
64 | } catch (e) {
65 | return false;
66 | }
67 | }
68 |
69 | static getBrowserRTC() {
70 | if (typeof window === 'undefined') return null;
71 | const wrtc = {
72 | RTCPeerConnection:
73 | // eslint-disable-next-line no-undef
74 | window.RTCPeerConnection ||
75 | // eslint-disable-next-line no-undef
76 | window.mozRTCPeerConnection ||
77 | // eslint-disable-next-line no-undef
78 | window.webkitRTCPeerConnection,
79 | RTCSessionDescription:
80 | // eslint-disable-next-line no-undef
81 | window.RTCSessionDescription ||
82 | // eslint-disable-next-line no-undef
83 | window.mozRTCSessionDescription ||
84 | // eslint-disable-next-line no-undef
85 | window.webkitRTCSessionDescription,
86 | RTCIceCandidate:
87 | // eslint-disable-next-line no-undef
88 | window.RTCIceCandidate ||
89 | // eslint-disable-next-line no-undef
90 | window.mozRTCIceCandidate ||
91 | // eslint-disable-next-line no-undef
92 | window.webkitRTCIceCandidate
93 | };
94 | if (!wrtc.RTCPeerConnection) return null;
95 | return wrtc;
96 | }
97 |
98 | static checkWebRTCAvailable() {
99 | const doesNotHaveWebRTC = MewConnectCommon.getBrowserRTC() == null;
100 | return !doesNotHaveWebRTC;
101 | // return false
102 | }
103 |
104 | static checkBrowser() {
105 | let browser = detect();
106 | if (browser === null) {
107 | browser = { version: { split: () => [1] } };
108 | }
109 | const browserVersion = browser.version.split(0, 1)[0];
110 | /*
111 | * Chrome > 23
112 | * Firefox > 22
113 | * Opera > 18
114 | * Safari > 11 (caveats exist)
115 | * Edge - none (RTCDataChannel not supported)
116 | * IE - none
117 | * */
118 | if (typeof window !== 'undefined') {
119 | if (browser.name === 'safari') {
120 | // eslint-disable-next-line global-require
121 | require('webrtc-adapter');
122 | return MewConnectCommon.buildBrowserResult(
123 | true,
124 | 'Safari',
125 | `version: ${browser.version}`
126 | );
127 | }
128 | if (browser.name === 'ie') {
129 | return MewConnectCommon.buildBrowserResult(
130 | true,
131 | 'Internet Explorer',
132 | '',
133 | true
134 | );
135 | }
136 | if (browser.name === 'edge') {
137 | return MewConnectCommon.buildBrowserResult(
138 | true,
139 | 'Edge',
140 | `version: ${browser.version}`,
141 | true
142 | );
143 | }
144 | let name = '';
145 | let minVersion = 0;
146 |
147 | if (browser.name === 'opera') {
148 | name = 'Opera';
149 | minVersion = 18;
150 | } else if (browser.name === 'firefox') {
151 | name = 'Firefox';
152 | minVersion = 22;
153 | } else if (browser.name === 'chrome') {
154 | name = 'Chrome';
155 | minVersion = 23;
156 | } else {
157 | return MewConnectCommon.buildBrowserResult(false, '', '', true);
158 | }
159 |
160 | try {
161 | if (minVersion >= +browserVersion) {
162 | return MewConnectCommon.buildBrowserResult(
163 | true,
164 | name,
165 | `version: ${browserVersion}`
166 | );
167 | }
168 | return MewConnectCommon.buildBrowserResult(false, '', '');
169 | } catch (e) {
170 | console.error(e);
171 | }
172 | }
173 | }
174 |
175 | static buildBrowserResult(status, browser, browserVersion, noSupport) {
176 | return {
177 | status,
178 | browser,
179 | browserVersion,
180 | noSupport: noSupport || false
181 | };
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/test/clients/initiator.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import CryptoUtils from '@utils/crypto-utils'
4 | import WebsocketConnection from '@utils/websocket-connection'
5 | import WebRTCConnection from '@utils/webrtc-connection'
6 | import { stunServers, websocketURL } from '@config'
7 | import { signals, rtcSignals, roles } from '@signals'
8 |
9 | export default class Initiator {
10 | constructor(options = {}) {
11 | this.socket = new WebsocketConnection()
12 | this.peer = new WebRTCConnection()
13 |
14 | this.publicKey
15 | this.privateKey
16 | this.signed
17 | this.connId
18 | }
19 |
20 | /*
21 | ===================================================================================
22 | Keys
23 | ===================================================================================
24 | */
25 |
26 | /* Set the public and private keys, connId, and signed that will be used
27 | * for the duration of the pairing process. The receiver will need to have access
28 | * to this information as well, however, the initiator creates the credentials to be
29 | * shared with the receiver.
30 | */
31 | generateKeys() {
32 | const keys = CryptoUtils.generateKeys()
33 | this.publicKey = keys.publicKey
34 | this.privateKey = keys.privateKey
35 | this.connId = CryptoUtils.generateConnId(this.publicKey)
36 | this.signed = CryptoUtils.signMessage(this.privateKey, this.privateKey)
37 | }
38 |
39 | /*
40 | ===================================================================================
41 | Encryption
42 | ===================================================================================
43 | */
44 |
45 | /**
46 | * Using the generated privateKey, encrypt a message.
47 | * The message must be a String, however, if an object is given,
48 | * it will become stringified for proper encryption.
49 | *
50 | * @param {Object} message - String or Object to be encrypted
51 | * @return {Object} - Encrypted message
52 | */
53 | async encrypt(message) {
54 | message = typeof message === 'String' ? message : JSON.stringify(message)
55 | return await CryptoUtils.encrypt(message, this.privateKey)
56 | }
57 |
58 | /**
59 | * Decrypt an encrypted message using the generated privateKey.
60 | *
61 | * @param {Object} message - Message to be decrypted.
62 | * @return {Object} - Decrypted message object
63 | */
64 | async decrypt(message) {
65 | const decryptedMessageString = await CryptoUtils.decrypt(
66 | message,
67 | this.privateKey
68 | )
69 | return JSON.parse(decryptedMessageString)
70 | }
71 |
72 | /*
73 | ===================================================================================
74 | Websocket
75 | ===================================================================================
76 | */
77 |
78 | /**
79 | * Given a @websocketURL, attempt to connect with given query param @options.
80 | * If no options are given, default to -what should- be the correct parameters.
81 | *
82 | * @param {String} websocketURL - WS/WSS websocket URL
83 | * @param {Object} options - (Optional) Connection query parameters
84 | */
85 | async connect(websocketURL, options = null) {
86 | const queryOptions = options
87 | ? options
88 | : {
89 | role: roles.initiator,
90 | connId: this.connId,
91 | signed: this.signed
92 | }
93 | await this.socket.connect(websocketURL, queryOptions)
94 | }
95 |
96 | /**
97 | * Bind a particular websocket signal/event to a given callback function.
98 | *
99 | * @param {String} signal - Signal to listen to. E.g. 'onoffer'
100 | * @param {Function} fn - Callback function to perform on given signal
101 | */
102 | on(signal, fn) {
103 | this.socket.on(signal, fn)
104 | }
105 |
106 | /**
107 | * Unbind listening to a particular signal that was bound in on()
108 | * @param {String} signal - Signal to stop listening to. E.g. 'onoffer'
109 | */
110 | off(signal) {
111 | this.socket.off(signal)
112 | }
113 |
114 | /**
115 | * Emit a @signal event with a given @data payload.
116 | *
117 | * @param {String} signal - Signal to emit. E.g. 'offersignal'
118 | * @param {Object} data - Data/message payload to send
119 | */
120 | send(signal, data) {
121 | this.socket.send(signal, data)
122 | }
123 |
124 | /*
125 | ===================================================================================
126 | WebRTC
127 | ===================================================================================
128 | */
129 |
130 | /**
131 | * Attempt to create a WebRTC Offer.
132 | * Return the encrypted offer for transmission to the receiver.
133 | *
134 | * @return {Object} - Encrypted WebRTC offer
135 | */
136 | async offer(options = null) {
137 | const offer = await this.peer.offer(options)
138 | return await this.encrypt(offer)
139 | }
140 |
141 | /**
142 | * Given a WebRTC response from the receiver, complete p2p connection.
143 | *
144 | * @param {Object} answer - WebRTC answer created by receiver
145 | */
146 | async signal(answer) {
147 | return await this.peer.connect(answer)
148 | }
149 |
150 | /**
151 | * Disconnect from current WebRTC connection
152 | */
153 | async disconnectRTC() {
154 | this.peer = new WebRTCConnection()
155 | }
156 |
157 | /**
158 | * On a given @signal event from the WebRTC connection, perform callback function.
159 | *
160 | * @param {String} signal - Signal to listen to. E.g. 'data'
161 | * @param {Function} fn - Callback function to perform
162 | */
163 | onRTC(signal, fn) {
164 | this.peer.on(signal, fn)
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/connectWindow/images/mobile-icon.js:
--------------------------------------------------------------------------------
1 | const image = `data:image/png;base64, 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`;
2 |
3 | export default image;
4 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/helpers/misc.js:
--------------------------------------------------------------------------------
1 | import { isAddress } from './addressUtils';
2 | import url from 'url';
3 | import utils from 'web3-utils';
4 | import { isHexString, toBuffer as utilsToBuffer } from 'ethereumjs-utils';
5 | import { uint, address, string, bytes, bool } from './solidityTypes';
6 |
7 | const toBuffer = v => {
8 | if (isHexString(v)) {
9 | return utilsToBuffer(v);
10 | }
11 | return Buffer.from(v);
12 | };
13 | const capitalize = value => {
14 | if (!value) return '';
15 | value = value.toString();
16 | return value.charAt(0).toUpperCase() + value.slice(1);
17 | };
18 | /* Accepts string, returns boolean */
19 | const isJson = str => {
20 | try {
21 | JSON.parse(str);
22 | } catch (e) {
23 | return false;
24 | }
25 |
26 | return true;
27 | };
28 |
29 | const getService = parsableUrl => {
30 | const parsedUrl = url.parse(parsableUrl).hostname;
31 | const splitUrl = parsedUrl.split('.');
32 | if (splitUrl.length > 2)
33 | // eslint-disable-next-line
34 | return capitalize(`${splitUrl[1]}.${splitUrl[2]}`);
35 | return capitalize(splitUrl.join('.'));
36 | };
37 |
38 | const doesExist = val => val !== undefined && val !== null;
39 |
40 | const padLeftEven = hex => {
41 | hex = hex.length % 2 !== 0 ? '0' + hex : hex;
42 | return hex;
43 | };
44 |
45 | const isInt = num => {
46 | return num % 1 === 0;
47 | };
48 |
49 | const formatDate = date => {
50 | const days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
51 | const day = days[new Date(date).getDay()];
52 | const dateString = new Date(date).toLocaleDateString();
53 | const regExp = /\(([^)]+)\)/;
54 | const timeString = new Date(date).toTimeString();
55 | const lengthMinus1 = timeString.length - 1;
56 | const stripTimezone = timeString
57 | .slice(timeString.indexOf('(') + 1, lengthMinus1)
58 | .split(' ')
59 | .map(item => {
60 | return item[0];
61 | })
62 | .join('');
63 | const removedTimezone = timeString.replace(regExp, '');
64 | const removeEndNumber = removedTimezone.slice(0, 12);
65 | const GMTtime = removeEndNumber.replace(removeEndNumber.slice(5, 8), '');
66 | const localTime = new Date(date).toLocaleTimeString(navigator.language, {
67 | hour: '2-digit',
68 | minute: '2-digit'
69 | });
70 | return `${day}. ${dateString} ${GMTtime} - ${localTime} ${stripTimezone}`;
71 | };
72 | const isValidETHAddress = address => {
73 | return isAddress(address);
74 | };
75 | const isValidENSorEtherAddress = address => {
76 | return isValidETHAddress(address);
77 | };
78 |
79 | const sanitizeHex = hex => {
80 | hex = hex.substring(0, 2) == '0x' ? hex.substring(2) : hex;
81 | if (hex == '') return '0x';
82 | return '0x' + padLeftEven(hex);
83 | };
84 |
85 | const scrollToTop = scrollDuration => {
86 | const scrollHeight = window.scrollY,
87 | scrollStep = Math.PI / (scrollDuration / 15),
88 | cosParameter = scrollHeight / 2;
89 |
90 | let scrollCount = 0;
91 | let scrollMargin;
92 | const scrollInterval = setInterval(function() {
93 | if (window.scrollY != 0) {
94 | scrollCount = scrollCount + 1;
95 | scrollMargin =
96 | cosParameter - cosParameter * Math.cos(scrollCount * scrollStep);
97 | window.scrollTo(0, scrollHeight - scrollMargin);
98 | } else clearInterval(scrollInterval);
99 | }, 15);
100 | };
101 |
102 | const validateHexString = str => {
103 | if (str === '') return true;
104 | str =
105 | str.substring(0, 2) === '0x'
106 | ? str.substring(2).toUpperCase()
107 | : str.toUpperCase();
108 | return utils.isHex(str);
109 | };
110 |
111 | const solidityType = inputType => {
112 | if (!inputType) inputType = '';
113 | if (inputType.includes('[') && inputType.includes(']')) {
114 | if (inputType.includes(uint))
115 | return { type: 'string', solidityType: `${uint}[]` };
116 | if (inputType.includes(address))
117 | return { type: 'text', solidityType: `${address}[]` };
118 | if (inputType.includes(string))
119 | return { type: 'text', solidityType: `${string}[]` };
120 | if (inputType.includes(bytes))
121 | return { type: 'text', solidityType: `${bytes}[]` };
122 | if (inputType.includes(bool))
123 | return { type: 'string', solidityType: `${bool}[]` };
124 | return { type: 'text', solidityType: `${string}[]` };
125 | }
126 | if (inputType.includes(uint)) return { type: 'number', solidityType: uint };
127 | if (inputType.includes(address))
128 | return { type: 'text', solidityType: address };
129 | if (inputType.includes(string)) return { type: 'text', solidityType: string };
130 | if (inputType.includes(bytes)) return { type: 'text', solidityType: bytes };
131 | if (inputType.includes(bool)) return { type: 'radio', solidityType: bool };
132 | return { type: 'text', solidityType: string };
133 | };
134 |
135 | const stringToArray = str => {
136 | return str.replace(/[^a-zA-Z0-9_,]+/g, '').split(',');
137 | };
138 |
139 | const isContractArgValid = (value, solidityType) => {
140 | if (!value) value = '';
141 | if (solidityType.includes('[') && solidityType.includes(']')) {
142 | const parsedValue = Array.isArray(value) ? value : stringToArray(value);
143 | const values = [];
144 | parsedValue.forEach(item => {
145 | if (solidityType.includes(uint)) {
146 | values.push(item !== '' && !isNaN(item) && isInt(item));
147 | } else if (solidityType.includes(address)) {
148 | values.push(isAddress(item));
149 | } else if (solidityType.includes(string)) {
150 | values.push(item !== '');
151 | } else if (solidityType.includes(bool)) {
152 | values.push(typeof item === typeof true || item === '');
153 | } else if (solidityType.includes(bytes)) {
154 | values.push(validateHexString(item));
155 | }
156 | });
157 | return !values.includes(false);
158 | }
159 | if (solidityType === 'uint')
160 | return value !== '' && !isNaN(value) && isInt(value);
161 | if (solidityType === 'address') return isAddress(value);
162 | if (solidityType === 'string') return true;
163 | if (solidityType === 'bytes')
164 | return value.substr(0, 2) === '0x' && validateHexString(value);
165 | if (solidityType === 'bool')
166 | return typeof value === typeof true || value === '';
167 | return false;
168 | };
169 |
170 | export default {
171 | isJson,
172 | doesExist,
173 | padLeftEven,
174 | formatDate,
175 | isValidENSorEtherAddress,
176 | isValidETHAddress,
177 | sanitizeHex,
178 | validateHexString,
179 | scrollToTop,
180 | solidityType,
181 | isInt,
182 | capitalize,
183 | getService,
184 | stringToArray,
185 | isContractArgValid,
186 | toBuffer
187 | };
188 |
--------------------------------------------------------------------------------
/src/connectClient/websocketWrapper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | import queryString from 'query-string';
3 | import 'isomorphic-ws';
4 | import debugLogger from 'debug';
5 |
6 | const debugPeer = debugLogger('MEWconnectVerbose:websocketWrapper');
7 | const debug = debugLogger('MEWconnect:websocketWrapper');
8 |
9 | export default class WebsocketConnection {
10 | constructor(options = {}) {
11 | this.options = options;
12 | this.socket = {};
13 | this.listeners = {};
14 |
15 | this.SOCKET_STATES = {
16 | 0: 'CONNECTING',
17 | 1: 'OPEN',
18 | 2: 'CLOSING',
19 | 3: 'CLOSED'
20 | };
21 |
22 | this.keepAlive = {
23 | ping: 'ping',
24 | pong: 'pong'
25 | };
26 | }
27 |
28 | /**
29 | * Connect to a given @websocketURL with given @options query params.
30 | * The client will connect and bind every on "message" event to the
31 | * onMessage() function.
32 | *
33 | * In order to handle a message, the on() member function must be used to add
34 | * an listener. This gives functionality similar to socket.io, in which
35 | * it is possible to so something like:
36 | *
37 | * socket.on('error', err => {})
38 | * as opposed to:
39 | * socket.on('message', message => { if (message.signal === 'error')... })
40 | *
41 | * @param {String} websocketURL - WSS address of websocket API
42 | * @param {Object} options - JSON-formatted connection query params
43 | * @param {String} options.role - Either "initiator" or "receiver" accordingly
44 | * @param {String} options.connId - Last 32 characters of the public key portion of the key-pair
45 | * created for the particular paired connection
46 | * @param {String} options.signed - Private key signed with the private key created for the connection
47 | */
48 | async connect(websocketUrl, options = {}) {
49 | try {
50 | const url = `${websocketUrl}?${queryString.stringify(options)}`;
51 | debug(url);
52 | if (typeof jest !== 'undefined' && typeof window === 'undefined') {
53 | const WebSocket = require('promise-ws').default;
54 | this.socket = await WebSocket.create(url);
55 | this.socket.on('message', this.onMessage.bind(this));
56 | } else {
57 | this.socket = new WebSocket(url);
58 | this.socket.onmessage = this.onMessage.bind(this);
59 | this.socket.onerror = this.onError.bind(this);
60 | this.socket.onopen = this.onOpen.bind(this);
61 | this.socket.onclose = this.onClose.bind(this);
62 |
63 | debug(`extensions used: ${this.socket.extensions} or none`);
64 | debug(`protocol used: ${this.socket.protocol} or default`);
65 | debug(
66 | `binary type used: ${this.socket.binaryType} [either blob or arraybuffer]`
67 | );
68 | }
69 | } catch (e) {
70 | debug('connect error:', e);
71 | }
72 | }
73 |
74 | async disconnect() {
75 | try {
76 | debug('ADD DISCONNECT FUNCTIONALITY');
77 | this.socket.close();
78 | } catch (e) {
79 | debug('disconnect error:', e);
80 | }
81 | }
82 |
83 | getSocketState() {
84 | return this.SOCKET_STATES[this.socket.readyState];
85 | }
86 |
87 | onOpen() {
88 | debug(`websocket onopen = ${this.getSocketState()}`);
89 | // this.pinger = setInterval(() => {
90 | // this.send(this.keepAlive.ping)
91 | // }, 5000)
92 | }
93 |
94 | /**
95 | * On 'message' event, parse the message and if possible,
96 | * call the event listener with the message's particular signal.
97 | *
98 | * Messages are received as stringified JSON objects, that when parsed,
99 | * take the following format:
100 | *
101 | * {
102 | * signal, // This is the signal that the member function on() can bind to
103 | * data, // The actual data payload
104 | * message // Accompanying server message
105 | * }
106 | *
107 | * @param {String} message - Stringified JSON payload sent by the server
108 | * @return {[type]} [description]
109 | */
110 | onMessage(message) {
111 | try {
112 | debugPeer('message', message);
113 | debugPeer('message data', message.data);
114 | let parsedMessage;
115 | if (typeof jest === 'undefined') {
116 | const parsedMessageRaw =
117 | typeof message === 'string' ? JSON.parse(message) : message;
118 | parsedMessage =
119 | typeof parsedMessageRaw.data === 'string'
120 | ? JSON.parse(parsedMessageRaw.data)
121 | : parsedMessageRaw.data;
122 | debugPeer('parsedMessage', parsedMessage);
123 | } else {
124 | parsedMessage =
125 | typeof message === 'string' ? JSON.parse(message) : message;
126 | debugPeer('parsedMessage: message', parsedMessage);
127 | debugPeer('parsedMessage: message data', parsedMessage.data);
128 | }
129 |
130 | if (parsedMessage.signal === 'ping' || parsedMessage.signal === 'pong') {
131 | return;
132 | }
133 | const signal = parsedMessage.signal;
134 | const data = parsedMessage.data;
135 | debug(`onMessage Signal: ${signal}`);
136 | try {
137 | this.listeners[signal].call(this, data);
138 | } catch (e) {
139 | debug(e);
140 | // Unhandled message signal
141 | }
142 | } catch (e) {
143 | debug('ERROR in onMessage', e);
144 | }
145 | }
146 |
147 | onError(errorEvent) {
148 | debug('Websocket ERROR');
149 | debug('websocket error event', errorEvent);
150 | }
151 |
152 | onClose() {
153 | debug(`websocket onClose = ${this.getSocketState()}`);
154 | if (this.listeners['onClose']) {
155 | this.listeners['onClose'].call(this);
156 | }
157 | }
158 |
159 | /**
160 | * Bind an function to a particular message signal event.
161 | * E.G.
162 | * socket.on('error', err => {})
163 | *
164 | * @param {String} signal - The signal to listen for
165 | * @param {Function} fn - Function to perform on message signal
166 | */
167 | on(signal, fn) {
168 | this.listeners[signal] = fn;
169 | }
170 |
171 | /**
172 | * Unbind a particular message signal event listener.
173 | *
174 | * @param {String} signal - The signal to unbind
175 | */
176 | off(signal) {
177 | delete this.listeners[signal];
178 | }
179 |
180 | /**
181 | * Send a data payload to a particular signal.
182 | *
183 | * @param {String} signal - Particular action/signal such as "offersignal"
184 | * @param {[type]} data - Data payload
185 | */
186 | send(signal, data = {}) {
187 | try {
188 | debug(`socket connection state: ${this.getSocketState()}`);
189 | debug(`send signal: ${signal}`);
190 | debug('send data:', data);
191 | const message = JSON.stringify({
192 | action: signal,
193 | data: data
194 | });
195 | this.socket.send(message);
196 | } catch (e) {
197 | debug('ERROR in send', e);
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/src/connectProvider/web3Provider/MEWconnect/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import MEWconnect from '../../../index';
3 | import { Transaction } from 'ethereumjs-tx';
4 | import WalletInterface from '../WalletInterface';
5 | import {
6 | getSignTransactionObject,
7 | sanitizeHex,
8 | getBufferFromHex,
9 | calculateChainIdFromV
10 | } from '../utils';
11 | import { hashPersonalMessage } from 'ethereumjs-utils';
12 | import errorHandler from './errorHandler';
13 | import commonGenerator from '../helpers/commonGenerator';
14 | import Misc from '../helpers/misc';
15 | import debugLogger from 'debug';
16 |
17 | // TODO add debug logging
18 | const debug = debugLogger('MEWconnect:wallet');
19 | // const debugConnectionState = debugLogger('MEWconnect:connection-state');
20 |
21 | const V1_SIGNAL_URL = 'https://connect.mewapi.io';
22 | const V2_SIGNAL_URL = 'wss://connect2.mewapi.io/staging';
23 | const IS_HARDWARE = true;
24 |
25 | class MEWconnectWalletInterface extends WalletInterface {
26 | constructor(
27 | pubkey,
28 | isHardware,
29 | identifier,
30 | txSigner,
31 | msgSigner,
32 | mewConnect,
33 | popUpHandler
34 | ) {
35 | super(pubkey, true, identifier);
36 | this.errorHandler = errorHandler(popUpHandler);
37 | this.txSigner = txSigner;
38 | this.msgSigner = msgSigner;
39 | this.isHardware = isHardware;
40 | this.mewConnect = mewConnect();
41 | }
42 |
43 | getConnection() {
44 | return this.mewConnect;
45 | }
46 |
47 | signTransaction(txParams) {
48 | return super.signTransaction(txParams, this.txSigner);
49 | }
50 |
51 | signMessage(msg) {
52 | return super.signMessage(msg, this.msgSigner);
53 | }
54 | }
55 |
56 | class MEWconnectWallet {
57 | constructor(state, popupCreator, popUpHandler) {
58 | this.identifier = 'mew_connect';
59 | this.isHardware = IS_HARDWARE;
60 | this.mewConnect = new MEWconnect.Initiator({
61 | v1Url: V1_SIGNAL_URL,
62 | v2Url: V2_SIGNAL_URL,
63 | showPopup: true,
64 | popupCreator: popupCreator
65 | });
66 | this.state = state || {};
67 | this.popUpHandler = popUpHandler;
68 | this.txIds = [];
69 | }
70 |
71 | static setConnectionState(connectionState) {
72 | if (!connectionState)
73 | MEWconnect.Initiator.setConnectionState('disconnected');
74 | else MEWconnect.Initiator.setConnectionState(connectionState);
75 | debug('setConnectionState', MEWconnect.Initiator.connectionState);
76 | }
77 |
78 | static getConnectionState() {
79 | debug('getConnectionState', MEWconnect.Initiator.connectionState);
80 |
81 | if (!MEWconnect.Initiator.connectionState) return 'disconnected';
82 | return MEWconnect.Initiator.connectionState;
83 | }
84 |
85 | static getPopupWindowRef() {
86 | if (!MEWconnect.Initiator.connectionState) return 'disconnected';
87 | return MEWconnect.Initiator.connectionState;
88 | }
89 |
90 | async init(qrcodeListener = () => {}) {
91 | this.mewConnect.on('codeDisplay', qrcodeListener);
92 | const txSigner = async tx => {
93 | let tokenInfo;
94 | if (
95 | tx.data.slice(0, 10) === '0xa9059cbb' ||
96 | tx.data.slice(0, 10) === '0x095ea7b3'
97 | ) {
98 | tokenInfo = this.state.network.tokens.find(
99 | entry => entry.address.toLowerCase() === tx.to.toLowerCase()
100 | );
101 | if (tokenInfo) {
102 | tx.currency = {
103 | symbol: tokenInfo.symbol,
104 | decimals: tokenInfo.decimals,
105 | address: tokenInfo.address
106 | };
107 | }
108 | }
109 |
110 | const networkId = tx.chainId;
111 | return new Promise((resolve, reject) => {
112 | if (!tx.gasLimit) {
113 | tx.gasLimit = tx.gas;
114 | }
115 | this.mewConnect.sendRtcMessage('signTx', JSON.stringify(tx));
116 | this.mewConnect.once('signTx', result => {
117 | this.mewConnect.removeAllListeners('reject');
118 | tx = new Transaction(sanitizeHex(result), {
119 | common: commonGenerator(this.state.network)
120 | });
121 | const signedChainId = calculateChainIdFromV(tx.v);
122 | if (signedChainId !== networkId)
123 | throw new Error(
124 | 'Invalid networkId signature returned. Expected: ' +
125 | networkId +
126 | ', Got: ' +
127 | signedChainId,
128 | 'InvalidNetworkId'
129 | );
130 | resolve(getSignTransactionObject(tx));
131 | });
132 | this.mewConnect.once('reject', () => {
133 | debug('signTx rejected');
134 | this.mewConnect.removeAllListeners('signTx');
135 | reject({ reject: true });
136 | });
137 | });
138 | };
139 | const msgSigner = async msg => {
140 | return new Promise((resolve, reject) => {
141 | const msgHash = hashPersonalMessage(Misc.toBuffer(msg));
142 | this.mewConnect.sendRtcMessage('signMessage', {
143 | hash: msgHash.toString('hex'),
144 | text: msg
145 | });
146 | this.mewConnect.once('signMessage', data => {
147 | this.mewConnect.removeAllListeners('reject');
148 | resolve(getBufferFromHex(sanitizeHex(data.sig)));
149 | });
150 | this.mewConnect.once('reject', () => {
151 | debug('signMessage rejected');
152 | this.mewConnect.removeAllListeners('signMessage');
153 | reject({ reject: true });
154 | });
155 | });
156 | };
157 |
158 | const mewConnect = () => {
159 | return this.mewConnect;
160 | };
161 |
162 | const address = await signalerConnect(V1_SIGNAL_URL, this.mewConnect);
163 |
164 | return new MEWconnectWalletInterface(
165 | sanitizeHex(address),
166 | this.isHardware,
167 | this.identifier,
168 | txSigner,
169 | msgSigner,
170 | mewConnect,
171 | this.popUpHandler
172 | );
173 | }
174 | }
175 |
176 | const createWallet = async (state, popupCreator, popUpHandler) => {
177 | const _MEWconnectWallet = new MEWconnectWallet(
178 | state,
179 | popupCreator,
180 | popUpHandler
181 | );
182 | createWallet.connectionState = _MEWconnectWallet.connectionState;
183 | const _tWallet = await _MEWconnectWallet.init();
184 | return _tWallet;
185 | };
186 | createWallet.errorHandler = errorHandler;
187 | const signalerConnect = (url, mewConnect) => {
188 | return new Promise(resolve => {
189 | mewConnect.initiatorStart(url);
190 | mewConnect.on('RtcConnectedEvent', () => {
191 | mewConnect.sendRtcMessage('address', '');
192 | mewConnect.once('address', data => {
193 | resolve(data.address);
194 | });
195 | });
196 |
197 | mewConnect.on('RtcDisconnectEvent', () => {
198 | MEWconnectWallet.setConnectionState('disconnected');
199 | mewConnect;
200 | });
201 | });
202 | };
203 |
204 | createWallet.getConnectionState = MEWconnectWallet.getConnectionState;
205 | createWallet.setConnectionState = MEWconnectWallet.setConnectionState;
206 |
207 | export default createWallet;
208 |
--------------------------------------------------------------------------------
/test/clients/turnReceiver.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const debugLogger = require('debug');
3 | import CryptoUtils from '../utils/crypto-utils'
4 | import WebsocketConnection from '../utils/websocket-connection'
5 | import WebRTCConnection from '../utils/webrtc-connection'
6 | import { stunServers, websocketURL } from '@config'
7 | import { signals, rtcSignals, roles } from '@signals'
8 |
9 | const debug = debugLogger('MEWconnect:receiver-V2');
10 |
11 | export default class Receiver {
12 | constructor(options = {}) {
13 | this.options = options
14 |
15 | this.socket = new WebsocketConnection()
16 | // this.peer = new WebRTCConnection()
17 | this.turnTest = options.turnTest || false;
18 |
19 | this.seenOnce = false;
20 |
21 | this.publicKey
22 | this.privateKey
23 | this.signed
24 | this.connId
25 | }
26 |
27 | /*
28 | ===================================================================================
29 | Keys
30 | ===================================================================================
31 | */
32 |
33 | /**
34 | * Set the public and private keys, connId, and signed that will be used
35 | * for the duration of the pairing process. The receiver must receiver this information
36 | * from the initiator who creates the credentials initially.
37 | *
38 | * @param {String} publicKey - Public key generated by the initiator for
39 | * secure communication during the pairing process.
40 | * @param {String} privateKey - Private key generated by the initiator for
41 | * secure communication during the pairing process.
42 | * @param {String} connId - condId generated by the initiator for secure communication
43 | * during the pairing process.
44 | */
45 | async setKeys(publicKey, privateKey, connId) {
46 | debug(privateKey); // todo remove dev item
47 | this.publicKey = publicKey
48 | this.privateKey = privateKey
49 | this.connId = connId
50 | this.signed = CryptoUtils.signMessage(this.privateKey, this.privateKey)
51 | debug('receiver: ',this.signed); // todo remove dev item
52 | }
53 |
54 | /*
55 | ===================================================================================
56 | Encryption
57 | ===================================================================================
58 | */
59 |
60 | /**
61 | * Using the generated privateKey, encrypt a message.
62 | * The message must be a String, however, if an object is given,
63 | * it will become stringified for proper encryption.
64 | *
65 | * @param {Object} message - String or Object to be encrypted
66 | * @return {Object} - Encrypted message
67 | */
68 | async encrypt(message) {
69 | debug('Receiver encrypt'); // todo remove dev item
70 |
71 | message = typeof message === 'String' ? message : JSON.stringify(message)
72 | return await CryptoUtils.encrypt(message, this.privateKey)
73 | }
74 |
75 | /**
76 | * Decrypt an encrypted message using the generated privateKey.
77 | *
78 | * @param {Object} message - Message to be decrypted.
79 | * @return {Object} - Decrypted message object
80 | */
81 | async decrypt(message) {
82 | debug('Receiver decrypt'); // todo remove dev item
83 |
84 | const decryptedMessageString = await CryptoUtils.decrypt(
85 | message,
86 | this.privateKey
87 | )
88 | return JSON.parse(decryptedMessageString)
89 | }
90 |
91 | /*
92 | ===================================================================================
93 | Websocket
94 | ===================================================================================
95 | */
96 |
97 | /**
98 | * Given a @websocketURL, attempt to connect with given query param @options.
99 | * If no options are given, default to -what should- be the correct parameters.
100 | *
101 | * @param {String} websocketURL - WS/WSS websocket URL
102 | * @param {Object} options - (Optional) Connection query parameters
103 | */
104 | async connect(websocketURL, options = null) {
105 | const queryOptions = options
106 | ? options
107 | : {
108 | role: roles.receiver,
109 | connId: this.connId,
110 | signed: this.signed
111 | }
112 | debug('receiver: ', websocketURL, queryOptions); // todo remove dev item
113 | await this.socket.connect(websocketURL, queryOptions)
114 | }
115 |
116 | /**
117 | * Bind a particular websocket signal/event to a given callback function.
118 | *
119 | * @param {String} signal - Signal to listen to. E.g. 'onoffer'
120 | * @param {Function} fn - Callback function to perform on given signal
121 | */
122 | on(signal, fn) {
123 | this.socket.on(signal, fn)
124 | }
125 |
126 | /**
127 | * Unbind listening to a particular signal that was bound in on()
128 | * @param {String} signal - Signal to stop listening to. E.g. 'onoffer'
129 | */
130 | off(signal) {
131 | this.socket.off(signal)
132 | }
133 |
134 | /**
135 | * Emit a @signal event with a given @data payload.
136 | *
137 | * @param {String} signal - Signal to emit. E.g. 'offersignal'
138 | * @param {Object} data - Data/message payload to send
139 | */
140 | send(signal, data) {
141 | this.socket.send(signal, data)
142 | }
143 |
144 | /*
145 | ===================================================================================
146 | WebRTC
147 | ===================================================================================
148 | */
149 |
150 | canAnswer(){
151 | this.seenOnce = true;
152 | }
153 | /**
154 | * Attempt to create a WebRTC answer in response to the offer created by the initiator.
155 | * Return the encrypted answer for transmission to the initiator.
156 | *
157 | * @return {Object} - Encrypted WebRTC answer
158 | */
159 | async answer(offer) {
160 | debug("RECEIVER ANSWER", this.seenOnce, this.turnTest)
161 | if(!this.turnTest){
162 | this.peer = new WebRTCConnection();
163 | const answer = await this.peer.answer(offer)
164 | return await this.encrypt(answer)
165 | } else if(this.seenOnce){
166 | this.peer = new WebRTCConnection()
167 | const answer = await this.peer.answer(offer)
168 | return await this.encrypt(answer)
169 | }
170 |
171 |
172 | }
173 |
174 | /**
175 | * Disconnect from current WebRTC connection
176 | */
177 | async disconnectRTC() {
178 | this.peer = new WebRTCConnection()
179 | }
180 |
181 | rtcDestroy(){
182 | this.disconnectRTC();
183 | this.peer.destroy();
184 | this.peer = null;
185 | }
186 |
187 | async sendRTC(signal, data = {}){
188 | const message = JSON.stringify({
189 | type: signal,
190 | data: data
191 | })
192 | const encrypted = await this.encrypt(message);
193 | this.peer.peer.send(JSON.stringify(encrypted));
194 | }
195 |
196 | /**
197 | * On a given @signal event from the WebRTC connection, perform callback function.
198 | *
199 | * @param {String} signal - Signal to listen to. E.g. 'data'
200 | * @param {Function} fn - Callback function to perform
201 | */
202 | onRTC(signal, fn) {
203 | this.peer.on(signal, fn)
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/test/clients/receiver.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const debugLogger = require('debug');
3 | import CryptoUtils from '../utils/crypto-utils'
4 | import WebsocketConnection from '../utils/websocket-connection'
5 | import WebRTCConnection from '../utils/webrtc-connection'
6 | import { stunServers, websocketURL } from '@config'
7 | import { signals, rtcSignals, roles } from '@signals'
8 |
9 | const debug = debugLogger('MEWconnect:receiver-V2');
10 |
11 | export default class Receiver {
12 | constructor(options = {}) {
13 | this.options = options
14 |
15 | this.socket = new WebsocketConnection()
16 | // this.peer = new WebRTCConnection()
17 | this.turnTest = options.turnTest || false;
18 |
19 | this.seenOnce = false;
20 |
21 | this.publicKey
22 | this.privateKey
23 | this.signed
24 | this.connId
25 | }
26 |
27 | /*
28 | ===================================================================================
29 | Keys
30 | ===================================================================================
31 | */
32 |
33 | /**
34 | * Set the public and private keys, connId, and signed that will be used
35 | * for the duration of the pairing process. The receiver must receiver this information
36 | * from the initiator who creates the credentials initially.
37 | *
38 | * @param {String} publicKey - Public key generated by the initiator for
39 | * secure communication during the pairing process.
40 | * @param {String} privateKey - Private key generated by the initiator for
41 | * secure communication during the pairing process.
42 | * @param {String} connId - condId generated by the initiator for secure communication
43 | * during the pairing process.
44 | */
45 | async setKeys(publicKey, privateKey, connId) {
46 | debug(privateKey); // todo remove dev item
47 | this.publicKey = publicKey
48 | this.privateKey = privateKey
49 | this.connId = connId
50 | this.signed = CryptoUtils.signMessage(this.privateKey, this.privateKey)
51 | debug('receiver: ',this.signed); // todo remove dev item
52 | }
53 |
54 | /*
55 | ===================================================================================
56 | Encryption
57 | ===================================================================================
58 | */
59 |
60 | /**
61 | * Using the generated privateKey, encrypt a message.
62 | * The message must be a String, however, if an object is given,
63 | * it will become stringified for proper encryption.
64 | *
65 | * @param {Object} message - String or Object to be encrypted
66 | * @return {Object} - Encrypted message
67 | */
68 | async encrypt(message) {
69 | debug('Receiver encrypt'); // todo remove dev item
70 |
71 | message = typeof message === 'String' ? message : JSON.stringify(message)
72 | return await CryptoUtils.encrypt(message, this.privateKey)
73 | }
74 |
75 | /**
76 | * Decrypt an encrypted message using the generated privateKey.
77 | *
78 | * @param {Object} message - Message to be decrypted.
79 | * @return {Object} - Decrypted message object
80 | */
81 | async decrypt(message) {
82 | debug('Receiver decrypt'); // todo remove dev item
83 |
84 | const decryptedMessageString = await CryptoUtils.decrypt(
85 | message,
86 | this.privateKey
87 | )
88 | return JSON.parse(decryptedMessageString)
89 | }
90 |
91 | /*
92 | ===================================================================================
93 | Websocket
94 | ===================================================================================
95 | */
96 |
97 | /**
98 | * Given a @websocketURL, attempt to connect with given query param @options.
99 | * If no options are given, default to -what should- be the correct parameters.
100 | *
101 | * @param {String} websocketURL - WS/WSS websocket URL
102 | * @param {Object} options - (Optional) Connection query parameters
103 | */
104 | async connect(websocketURL, options = null) {
105 | const queryOptions = options
106 | ? options
107 | : {
108 | role: roles.receiver,
109 | connId: this.connId,
110 | signed: this.signed
111 | }
112 | debug('receiver: ', websocketURL, queryOptions); // todo remove dev item
113 | await this.socket.connect(websocketURL, queryOptions)
114 | }
115 |
116 | /**
117 | * Bind a particular websocket signal/event to a given callback function.
118 | *
119 | * @param {String} signal - Signal to listen to. E.g. 'onoffer'
120 | * @param {Function} fn - Callback function to perform on given signal
121 | */
122 | on(signal, fn) {
123 | this.socket.on(signal, fn)
124 | }
125 |
126 | /**
127 | * Unbind listening to a particular signal that was bound in on()
128 | * @param {String} signal - Signal to stop listening to. E.g. 'onoffer'
129 | */
130 | off(signal) {
131 | this.socket.off(signal)
132 | }
133 |
134 | /**
135 | * Emit a @signal event with a given @data payload.
136 | *
137 | * @param {String} signal - Signal to emit. E.g. 'offersignal'
138 | * @param {Object} data - Data/message payload to send
139 | */
140 | send(signal, data) {
141 | this.socket.send(signal, data)
142 | }
143 |
144 | /*
145 | ===================================================================================
146 | WebRTC
147 | ===================================================================================
148 | */
149 |
150 | canAnswer(){
151 | this.seenOnce = true;
152 | }
153 | /**
154 | * Attempt to create a WebRTC answer in response to the offer created by the initiator.
155 | * Return the encrypted answer for transmission to the initiator.
156 | *
157 | * @return {Object} - Encrypted WebRTC answer
158 | */
159 | async answer(offer) {
160 | debug("RECEIVER ANSWER", this.seenOnce, this.turnTest)
161 | if(!this.turnTest){
162 | this.peer = new WebRTCConnection();
163 | const answer = await this.peer.answer(offer)
164 | return await this.encrypt(answer)
165 | } else if(this.seenOnce){
166 | this.seenOnce = false;
167 | this.peer = new WebRTCConnection()
168 | const answer = await this.peer.answer(offer)
169 | return await this.encrypt(answer)
170 | }
171 |
172 |
173 | }
174 |
175 | /**
176 | * Disconnect from current WebRTC connection
177 | */
178 | async disconnectRTC() {
179 | this.peer = new WebRTCConnection()
180 | }
181 |
182 | rtcDestroy(){
183 | this.disconnectRTC();
184 | this.peer.destroy();
185 | this.peer = null;
186 | }
187 |
188 | async sendRTC(signal, data = {}){
189 | const message = JSON.stringify({
190 | type: signal,
191 | data: data
192 | })
193 | const encrypted = await this.encrypt(message);
194 | this.peer.peer.send(JSON.stringify(encrypted));
195 | }
196 |
197 | /**
198 | * On a given @signal event from the WebRTC connection, perform callback function.
199 | *
200 | * @param {String} signal - Signal to listen to. E.g. 'data'
201 | * @param {Function} fn - Callback function to perform
202 | */
203 | onRTC(signal, fn) {
204 | debug('onRTC', signal);
205 | this.peer.on(signal, fn)
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/src/connectWindow/popUpHandler.js:
--------------------------------------------------------------------------------
1 | import { notifierCSS, connectedNotifierCSS } from './popupStyles';
2 | import { noticeHtml, connectedNoticeHtml } from './popupHtml';
3 | import { spaceman, closeIconBlack, closeIconWhite } from './images/index';
4 | import { getMessage } from './messageCreator';
5 |
6 | export default class PopUpHandler {
7 | constructor() {
8 | this.index = 0;
9 | this.checkCount = 0;
10 | this.elementId = 'mew-connect-notice-corner';
11 | this.connectedElementId = this.elementId + '-connected';
12 | this.initialcheckIfIdExists();
13 | this.createNotice();
14 | this.timeoutTracker = null;
15 | this.lastActiveElement = '';
16 | this.connectNoticeVisible = false;
17 | }
18 |
19 | initialcheckIfIdExists() {
20 | const element = window.document.getElementById(this.elementId);
21 | if (element) {
22 | this.checkCount++;
23 | this.elementId = this.elementId + `-${this.checkCount}`;
24 | this.connectedElementId = this.elementId + '-connected';
25 | this.initialcheckIfIdExists();
26 | }
27 | }
28 |
29 | showNotice(text, overrides = null) {
30 | let timeoutTime = 3800;
31 | let timeoutOverride = false;
32 | if (typeof text === 'object') {
33 | text = getMessage(null, text);
34 | } else {
35 | text = getMessage(text);
36 | }
37 | if (!text) {
38 | text = 'Check your phone to continue';
39 | }
40 |
41 | if (typeof overrides === 'number') {
42 | timeoutTime = overrides;
43 | timeoutOverride = true;
44 | }
45 |
46 | const element = window.document.getElementById(this.elementId);
47 | this.lastActiveElement = element;
48 | if (!timeoutOverride) {
49 | element.className = 'show';
50 |
51 | const elementText = window.document.getElementById(
52 | `${this.elementId}-text`
53 | );
54 | elementText.innerHTML = text;
55 |
56 | setTimeout(function() {
57 | element.className = element.className.replace('show', '');
58 | }, timeoutTime);
59 | } else {
60 | element.className = 'show-in';
61 |
62 | const elementText = window.document.getElementById(
63 | `${this.elementId}-text`
64 | );
65 | elementText.innerHTML = text;
66 |
67 | setTimeout(function() {
68 | element.className = element.className.replace('show-in', 'show-out');
69 | }, timeoutTime - 500);
70 | this.timeoutTracker = setTimeout(function() {
71 | element.className = element.className.replace('show-out', '');
72 | }, timeoutTime);
73 | }
74 | }
75 |
76 | showConnectedNotice(text, overrides) {
77 | let timeoutTime = 3800;
78 | let timeoutOverride = false;
79 |
80 | if (typeof overrides === 'number') {
81 | timeoutTime = overrides;
82 | timeoutOverride = true;
83 | }
84 | const element = window.document.getElementById(this.connectedElementId);
85 | this.lastActiveElement = element;
86 | if (!timeoutOverride) {
87 | element.className = 'show';
88 |
89 | setTimeout(function() {
90 | element.className = element.className.replace('show', '');
91 | this.connectNoticeVisible = true;
92 | }, timeoutTime);
93 | } else {
94 | element.className = 'show-in';
95 |
96 | setTimeout(function() {
97 | element.className = element.className.replace('show-in', 'show-out');
98 | this.connectNoticeVisible = true;
99 | }, timeoutTime - 500);
100 | this.timeoutTracker = setTimeout(function() {
101 | element.className = element.className.replace('show-out', '');
102 | this.connectNoticeVisible = false;
103 | this.lastActiveElement = null;
104 | }, timeoutTime);
105 | }
106 | }
107 |
108 | showNoticePersistentEnter(text) {
109 | if (typeof text === 'object') {
110 | text = getMessage(null, text);
111 | } else {
112 | text = getMessage(text);
113 | }
114 |
115 | const element = window.document.getElementById(this.elementId);
116 |
117 | element.className = 'show-persistent';
118 |
119 | const elementText = window.document.getElementById(
120 | `${this.elementId}-text`
121 | );
122 | elementText.innerHTML = text;
123 |
124 | this.timeoutTracker = setTimeout(function() {
125 | element.className = element.className.replace('show-persistent', '');
126 | }, 10800);
127 | }
128 |
129 | showNoticePersistentExit() {
130 | if (this.timeoutTracker) {
131 | clearTimeout(this.timeoutTracker);
132 | const element = window.document.getElementById(this.elementId);
133 | element.className = element.className.replace(
134 | 'show-persistent',
135 | 'show-persistent-leave'
136 | );
137 |
138 | this.timeoutTracker = setTimeout(function() {
139 | element.className = element.className.replace(
140 | 'show-persistent-leave',
141 | ''
142 | );
143 | }, 1800);
144 | }
145 | }
146 |
147 | noShow() {
148 | if (this.timeoutTracker) {
149 | clearTimeout(this.timeoutTracker);
150 | }
151 | const element = window.document.getElementById(this.elementId);
152 | element.className = '';
153 | }
154 |
155 | createNotice() {
156 | this.index++;
157 |
158 | const div = window.document.createElement('div');
159 | div.id = this.elementId;
160 | div.innerHTML = noticeHtml(this.elementId, spaceman, closeIconBlack);
161 | window.document.body.appendChild(div);
162 |
163 | const css = document.createElement('style');
164 | css.type = 'text/css';
165 | if ('textContent' in css) css.textContent = notifierCSS(this.elementId);
166 | else css.innerText = notifierCSS(this.elementId);
167 | document.body.appendChild(css);
168 |
169 | const closeEl = document.getElementById(this.elementId + '-close');
170 | closeEl.addEventListener('click', () => {
171 | const el = document.getElementById(this.elementId);
172 | if (this.timeoutTracker) {
173 | clearTimeout(this.timeoutTracker);
174 | }
175 | el.className = el.className.replace('show', '');
176 | });
177 |
178 | // create connected notice
179 | const divConn = window.document.createElement('div');
180 | divConn.id = this.connectedElementId;
181 | divConn.innerHTML = connectedNoticeHtml(
182 | this.connectedElementId,
183 | spaceman,
184 | closeIconWhite
185 | );
186 | window.document.body.appendChild(divConn);
187 |
188 | const cssConn = document.createElement('style');
189 | cssConn.type = 'text/css';
190 | if ('textContent' in cssConn)
191 | cssConn.textContent = connectedNotifierCSS(this.connectedElementId);
192 | else cssConn.innerText = connectedNotifierCSS(this.connectedElementId);
193 | document.body.appendChild(cssConn);
194 |
195 | const closeElConn = document.getElementById(
196 | this.connectedElementId + '-close'
197 | );
198 | closeElConn.addEventListener('click', () => {
199 | const el = document.getElementById(this.connectedElementId);
200 | if (this.timeoutTracker) {
201 | clearTimeout(this.timeoutTracker);
202 | }
203 | el.className = el.className.replace('show', '');
204 | });
205 | }
206 |
207 | hideNotifier() {
208 | const notify = document.getElementById('Notifications');
209 | if (notify) {
210 | notify.className = 'hidden';
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/src/connectWindow/designTemplates/popupWindow.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 | MEWconnect
11 |
183 |
184 |
185 |
186 |
187 |
188 |
Connect to MEW wallet app
189 |
Scan this code to connect
190 |
191 |
192 |
193 |
194 |

195 |
196 |
197 |
198 | - Open MEW wallet app on your mobile device
199 | -
200 | Click
icon
201 | in the top right corner
202 |
203 | - Scan this code to connect
204 |
205 |
206 |
207 |
208 |
209 |

215 |
216 |
217 |
218 |
Don't have MEW wallet app?
219 |

225 |

230 |
231 |
232 |
233 |
237 |
238 |
239 |
256 |
257 |
258 |
--------------------------------------------------------------------------------