├── .nvmrc ├── public ├── _redirects ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── mstile-150x150.png ├── fonts │ ├── MarkPro-Bold.eot │ ├── MarkPro-Book.eot │ ├── SFMono-Bold.eot │ ├── SFMono-Bold.ttf │ ├── SFMono-Bold.woff │ ├── MarkPro-Bold.woff │ ├── MarkPro-Bold.woff2 │ ├── MarkPro-Book.woff │ ├── MarkPro-Book.woff2 │ ├── MarkPro-Medium.eot │ ├── MarkPro-Medium.woff │ ├── SFMono-Bold.woff2 │ ├── SFMono-Medium.eot │ ├── SFMono-Medium.ttf │ ├── SFMono-Medium.woff │ ├── SFMono-Medium.woff2 │ ├── SFMono-Regular.eot │ ├── SFMono-Regular.ttf │ ├── SFMono-Regular.woff │ ├── SFMono-Semibold.eot │ ├── SFMono-Semibold.ttf │ ├── SFProText-Bold.eot │ ├── SFProText-Bold.ttf │ ├── SFProText-Bold.woff │ ├── MarkPro-Medium.woff2 │ ├── SFMono-Regular.woff2 │ ├── SFMono-Semibold.woff │ ├── SFMono-Semibold.woff2 │ ├── SFProText-Bold.woff2 │ ├── SFProText-Medium.eot │ ├── SFProText-Medium.ttf │ ├── SFProText-Medium.woff │ ├── SFProText-Regular.eot │ ├── SFProText-Regular.ttf │ ├── SFProText-Medium.woff2 │ ├── SFProText-Regular.woff │ ├── SFProText-Regular.woff2 │ ├── SFProText-Semibold.eot │ ├── SFProText-Semibold.ttf │ ├── SFProText-Semibold.woff │ └── SFProText-Semibold.woff2 ├── social-media-card.png ├── android-chrome-144x144.png ├── unregisterServiceWorker.js ├── manifest.json ├── site.webmanifest ├── blockies.min.js ├── index.html └── safari-pinned-tab.svg ├── src ├── dump.rdb ├── assets │ ├── spinner.png │ ├── clipboard.png │ ├── ledger-logo.png │ ├── logo-light.png │ ├── placeholder.png │ ├── qr-code-bnw.png │ ├── trezor-logo.png │ ├── metamask-logo.png │ ├── metamask-white.png │ ├── tab-background.png │ ├── triangles-blue.png │ ├── triangles-dark.png │ ├── metamask-original.png │ ├── tab-background-sprite.png │ ├── eth.svg │ ├── arrow-received.svg │ ├── arrow-sent.svg │ ├── ethplorer-logo.svg │ ├── selector-grey.svg │ ├── arrow-up.svg │ ├── arrow-left.svg │ ├── walletconnect-white.svg │ ├── transactions-tab.svg │ ├── star-tab.svg │ ├── arrow-failed.svg │ ├── help.svg │ ├── etherscan-logo.svg │ ├── cross.svg │ ├── circle.svg │ ├── exchange-icon.svg │ ├── qr-code-transparent.svg │ ├── caret.svg │ ├── walletconnect-blue.svg │ ├── opera-text.svg │ ├── triangles-light.svg │ ├── balances-tab.svg │ ├── caret-small.svg │ ├── opera-logo.svg │ ├── gbp.svg │ ├── trustwallet-logo.svg │ ├── btc.svg │ ├── eur.svg │ ├── firefox-text.svg │ ├── convert-icon.svg │ ├── usd.svg │ ├── chrome-text.svg │ ├── mail.svg │ ├── brave-text.svg │ ├── interactions-tab.svg │ ├── chrome-logo.svg │ ├── globe.svg │ ├── brave-logo.svg │ └── trezor-logo.svg ├── history.js ├── piwik.js ├── references │ ├── smartcontract-methods.json │ ├── time-units.json │ ├── ethereum-networks.json │ ├── supported-wallets.json │ ├── native-currencies.json │ └── ethereum-units.json ├── modals │ ├── ApproveTransactionModal │ │ ├── styles.js │ │ └── index.js │ ├── SuccessModal │ │ └── index.js │ ├── ReceiveModal │ │ └── index.js │ ├── WalletConnectModal.js │ └── index.js ├── helpers │ ├── device.js │ ├── bootIntercom.js │ └── intercom.js ├── components │ ├── GasPriceLineBreak │ │ └── index.js │ ├── Link.js │ ├── GasButton │ │ ├── styles.js │ │ └── index.js │ ├── GasPanel │ │ ├── styles.js │ │ └── index.js │ ├── LedgerLogo.js │ ├── TrezorLogo.js │ ├── MetamaskLogo.js │ ├── WalletConnectLogo.js │ ├── Spinner.js │ ├── Background.js │ ├── AccountType.js │ ├── HoverWrapper.js │ ├── Wrapper.js │ ├── AssetIcon.js │ ├── Form.js │ ├── Column.js │ ├── TextButton.js │ ├── QRCodeDisplay.js │ ├── Blockie.js │ ├── ClickOutside.js │ ├── LineBreak.js │ ├── ToggleIndicator.js │ ├── Notification.js │ ├── Loader.js │ ├── QRCodeReader.js │ ├── Footer.js │ ├── Warning.js │ ├── CopyToClipboard │ │ ├── index.js │ │ └── styles.js │ ├── ReminderRibbon.js │ ├── TransactionStatus.js │ ├── ButtonCustom.js │ ├── Card.js │ ├── Input.js │ └── Button.js ├── handlers │ ├── localstorage.js │ ├── walletconnect.js │ ├── trezor-eth.js │ ├── web3.js │ └── ledger-eth.js ├── reducers │ ├── index.js │ ├── _modal.js │ ├── _notification.js │ ├── _zrxinstant.js │ ├── _ledger.js │ ├── _warning.js │ ├── _trezor.js │ └── _metamask.js ├── pages │ ├── NotFound.js │ ├── Wallet.js │ ├── Metamask.js │ ├── Ledger.js │ └── Trezor.js ├── Root.js ├── index.js ├── Router.js └── views │ └── Account │ └── AccountUniqueTokens.js ├── .prettierrc ├── .gitmodules ├── .eslintrc ├── .editorconfig ├── .gitignore ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── README.md └── package.json /.nvmrc: -------------------------------------------------------------------------------- 1 | 11.2.0 2 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 2 | -------------------------------------------------------------------------------- /src/dump.rdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/dump.rdb -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "parser": "flow" 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/spinner.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /src/assets/clipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/clipboard.png -------------------------------------------------------------------------------- /src/history.js: -------------------------------------------------------------------------------- 1 | import { createBrowserHistory } from 'history'; 2 | export default createBrowserHistory(); 3 | -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/mstile-150x150.png -------------------------------------------------------------------------------- /src/assets/ledger-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/ledger-logo.png -------------------------------------------------------------------------------- /src/assets/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/logo-light.png -------------------------------------------------------------------------------- /src/assets/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/placeholder.png -------------------------------------------------------------------------------- /src/assets/qr-code-bnw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/qr-code-bnw.png -------------------------------------------------------------------------------- /src/assets/trezor-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/trezor-logo.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "public/tokens"] 2 | path = public/tokens 3 | url = https://github.com/balance-io/tokens.git 4 | -------------------------------------------------------------------------------- /public/fonts/MarkPro-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Bold.eot -------------------------------------------------------------------------------- /public/fonts/MarkPro-Book.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Book.eot -------------------------------------------------------------------------------- /public/fonts/SFMono-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Bold.eot -------------------------------------------------------------------------------- /public/fonts/SFMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Bold.ttf -------------------------------------------------------------------------------- /public/fonts/SFMono-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Bold.woff -------------------------------------------------------------------------------- /public/social-media-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/social-media-card.png -------------------------------------------------------------------------------- /src/assets/metamask-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/metamask-logo.png -------------------------------------------------------------------------------- /src/assets/metamask-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/metamask-white.png -------------------------------------------------------------------------------- /src/assets/tab-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/tab-background.png -------------------------------------------------------------------------------- /src/assets/triangles-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/triangles-blue.png -------------------------------------------------------------------------------- /src/assets/triangles-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/triangles-dark.png -------------------------------------------------------------------------------- /public/fonts/MarkPro-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Bold.woff -------------------------------------------------------------------------------- /public/fonts/MarkPro-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Bold.woff2 -------------------------------------------------------------------------------- /public/fonts/MarkPro-Book.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Book.woff -------------------------------------------------------------------------------- /public/fonts/MarkPro-Book.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Book.woff2 -------------------------------------------------------------------------------- /public/fonts/MarkPro-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Medium.eot -------------------------------------------------------------------------------- /public/fonts/MarkPro-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Medium.woff -------------------------------------------------------------------------------- /public/fonts/SFMono-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Bold.woff2 -------------------------------------------------------------------------------- /public/fonts/SFMono-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Medium.eot -------------------------------------------------------------------------------- /public/fonts/SFMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Medium.ttf -------------------------------------------------------------------------------- /public/fonts/SFMono-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Medium.woff -------------------------------------------------------------------------------- /public/fonts/SFMono-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Medium.woff2 -------------------------------------------------------------------------------- /public/fonts/SFMono-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Regular.eot -------------------------------------------------------------------------------- /public/fonts/SFMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Regular.ttf -------------------------------------------------------------------------------- /public/fonts/SFMono-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Regular.woff -------------------------------------------------------------------------------- /public/fonts/SFMono-Semibold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Semibold.eot -------------------------------------------------------------------------------- /public/fonts/SFMono-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Semibold.ttf -------------------------------------------------------------------------------- /public/fonts/SFProText-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Bold.eot -------------------------------------------------------------------------------- /public/fonts/SFProText-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Bold.ttf -------------------------------------------------------------------------------- /public/fonts/SFProText-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Bold.woff -------------------------------------------------------------------------------- /src/assets/metamask-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/metamask-original.png -------------------------------------------------------------------------------- /public/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/android-chrome-144x144.png -------------------------------------------------------------------------------- /public/fonts/MarkPro-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/MarkPro-Medium.woff2 -------------------------------------------------------------------------------- /public/fonts/SFMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Regular.woff2 -------------------------------------------------------------------------------- /public/fonts/SFMono-Semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Semibold.woff -------------------------------------------------------------------------------- /public/fonts/SFMono-Semibold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFMono-Semibold.woff2 -------------------------------------------------------------------------------- /public/fonts/SFProText-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Bold.woff2 -------------------------------------------------------------------------------- /public/fonts/SFProText-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Medium.eot -------------------------------------------------------------------------------- /public/fonts/SFProText-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Medium.ttf -------------------------------------------------------------------------------- /public/fonts/SFProText-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Medium.woff -------------------------------------------------------------------------------- /public/fonts/SFProText-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Regular.eot -------------------------------------------------------------------------------- /public/fonts/SFProText-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Regular.ttf -------------------------------------------------------------------------------- /public/fonts/SFProText-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Medium.woff2 -------------------------------------------------------------------------------- /public/fonts/SFProText-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Regular.woff -------------------------------------------------------------------------------- /public/fonts/SFProText-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Regular.woff2 -------------------------------------------------------------------------------- /public/fonts/SFProText-Semibold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Semibold.eot -------------------------------------------------------------------------------- /public/fonts/SFProText-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Semibold.ttf -------------------------------------------------------------------------------- /public/fonts/SFProText-Semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Semibold.woff -------------------------------------------------------------------------------- /public/fonts/SFProText-Semibold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/public/fonts/SFProText-Semibold.woff2 -------------------------------------------------------------------------------- /src/assets/tab-background-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/rainbow-dashboard/HEAD/src/assets/tab-background-sprite.png -------------------------------------------------------------------------------- /src/piwik.js: -------------------------------------------------------------------------------- 1 | import PiwikReactRouter from 'piwik-react-router'; 2 | 3 | const piwik = PiwikReactRouter({ 4 | url: 'https://matomo.balance.io', 5 | siteId: 1, 6 | }); 7 | 8 | export default piwik; 9 | -------------------------------------------------------------------------------- /public/unregisterServiceWorker.js: -------------------------------------------------------------------------------- 1 | navigator.serviceWorker.getRegistrations().then(function(registrations) { 2 | for (let registration of registrations) { 3 | registration.unregister(); 4 | } 5 | }); 6 | -------------------------------------------------------------------------------- /src/assets/eth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/references/smartcontract-methods.json: -------------------------------------------------------------------------------- 1 | { 2 | "token_transfer": { 3 | "method": "transfer(address,uint256)", 4 | "hash": "0xa9059cbb" 5 | }, 6 | "token_balance": { 7 | "method": "balanceOf(address)", 8 | "hash": "0x70a08231" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/assets/arrow-received.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier"], 3 | "extends": ["react-app", "prettier"], 4 | "rules": { 5 | "jsx-a11y/href-no-hash": "off", 6 | "array-callback-return": "off", 7 | "prettier/prettier": "error" 8 | }, 9 | "globals": { 10 | "document": true, 11 | "window": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/references/time-units.json: -------------------------------------------------------------------------------- 1 | { 2 | "ms": { 3 | "second": 1000, 4 | "minute": 60000, 5 | "hour": 3600000, 6 | "day": 86400000 7 | }, 8 | "secs": { 9 | "minute": 60, 10 | "hour": 3600, 11 | "day": 86400 12 | }, 13 | "mins": { 14 | "hour": 60, 15 | "day": 1440 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/assets/arrow-sent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/references/ethereum-networks.json: -------------------------------------------------------------------------------- 1 | { 2 | "mainnet": { 3 | "id": 1, 4 | "value": "Mainnet" 5 | }, 6 | "ropsten": { 7 | "id": 3, 8 | "value": "Ropsten" 9 | }, 10 | "rinkeby": { 11 | "id": 4, 12 | "value": "Rinkeby" 13 | }, 14 | "kovan": { 15 | "id": 42, 16 | "value": "Kovan" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/modals/ApproveTransactionModal/styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const StyledApproveTransaction = styled.div` 4 | padding: 22px; 5 | display: flex; 6 | flex-direction: column; 7 | align-items: center; 8 | & > div { 9 | margin-top: 15px; 10 | } 11 | & > p { 12 | margin-top: 32px; 13 | } 14 | `; 15 | -------------------------------------------------------------------------------- /src/assets/ethplorer-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/references/supported-wallets.json: -------------------------------------------------------------------------------- 1 | { 2 | "balance_wallet": { 3 | "color": "white", 4 | "value": "Balance Wallet" 5 | }, 6 | "metamask": { 7 | "color": "orange", 8 | "value": "MetaMask" 9 | }, 10 | "ledger": { 11 | "color": "blue", 12 | "value": "Ledger" 13 | }, 14 | "trezor": { 15 | "color": "black", 16 | "value": "Trezor" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Balance Manager", 3 | "name": "Balance Manager", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # Matches multiple files with brace expansion notation 14 | # Set default charset 15 | [*.{js,py}] 16 | charset = utf-8 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | IGNORE_* 24 | package-lock.json 25 | -------------------------------------------------------------------------------- /src/assets/selector-grey.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### PR Checklist (check all) 2 | 3 | * [ ] Updated `CHANGELOG.md` to describe the included fixes and changes made 4 | * [ ] Included issue number on the description of the PR 5 | * [ ] Commented on the relevant issue thread about this PR 6 | 7 | ### Issue number 8 | 9 | 10 | 11 | ### Changelog 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/helpers/device.js: -------------------------------------------------------------------------------- 1 | import bowser from 'bowser'; 2 | 3 | const isMobile = () => { 4 | const browser = bowser.getParser(window.navigator.userAgent); 5 | 6 | return browser.some(['mobile', 'tablet']); 7 | }; 8 | 9 | const isValidBrowser = () => { 10 | const browser = bowser.getParser(window.navigator.userAgent); 11 | 12 | return !browser.some(['Internet Explorer', 'Microsoft Edge', 'Safari']); 13 | }; 14 | 15 | export { isMobile, isValidBrowser }; 16 | -------------------------------------------------------------------------------- /src/assets/arrow-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/arrow-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/walletconnect-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/transactions-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What is this issue about? (select one) 2 | 3 | * [ ] Bug report 4 | * [ ] Feature request 5 | * [ ] Enhancement 6 | 7 | ### Issue Description 8 | 9 | 10 | 11 | ## Steps to reproduce 12 | 13 | 1. 14 | 2. 15 | 3. 16 | 17 | ### Expected Behavior 18 | 19 | 20 | 21 | ### Actual Behavior 22 | 23 | 24 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /src/components/GasPriceLineBreak/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LineBreak from '../../components/LineBreak'; 3 | 4 | const GasPriceLineBreak = ({ gasPriceOption }) => ( 5 | 18 | ); 19 | 20 | export default GasPriceLineBreak; 21 | -------------------------------------------------------------------------------- /src/assets/star-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/helpers/bootIntercom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc boot intercom 3 | * @return {Intercom} 4 | */ 5 | export const bootIntercom = () => { 6 | let appID; 7 | switch (process.env.NODE_ENV) { 8 | case 'development': 9 | break; 10 | case 'test': 11 | appID = 'k8c9ptl1'; 12 | break; 13 | case 'production': 14 | appID = 'j0fl7v0m'; 15 | break; 16 | default: 17 | return; 18 | } 19 | const setup = () => window.Intercom('boot', { app_id: appID }); 20 | if (typeof window.Intercom !== 'undefined') setup(); 21 | else setTimeout(setup, 500); 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/Link.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import { Link } from 'react-router-dom'; 5 | 6 | const SLink = styled(Link)` 7 | text-decoration: none; 8 | color: inherit; 9 | margin: 0; 10 | padding: 0; 11 | width: ${({ width }) => (width ? width : null)}; 12 | `; 13 | 14 | const LinkWrapper = ({ children, ...props }) => ( 15 | {children} 16 | ); 17 | 18 | LinkWrapper.propTypes = { 19 | children: PropTypes.node.isRequired, 20 | }; 21 | 22 | export default LinkWrapper; 23 | -------------------------------------------------------------------------------- /src/components/GasButton/styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | import Button from '../../components/Button'; 4 | 5 | export const StyledGasButton = styled(Button)` 6 | min-height: 54px; 7 | width: 100%; 8 | 9 | & p { 10 | line-height: 20px; 11 | margin-top: 2px; 12 | } 13 | 14 | & p:first-child { 15 | font-weight: 500; 16 | } 17 | 18 | & p:last-child { 19 | font-weight: 400; 20 | font-size: 12px; 21 | } 22 | 23 | &:hover, 24 | &:active, 25 | &:focus, 26 | &:disabled { 27 | outline: none !important; 28 | box-shadow: none !important; 29 | } 30 | `; 31 | -------------------------------------------------------------------------------- /src/components/GasButton/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { lang } from 'balance-common'; 4 | 5 | import { StyledGasButton } from './styles'; 6 | 7 | const GasButton = ({ gasPrice, speed, onClick }) => ( 8 | onClick(speed)}> 9 |

{`${lang.t(`modal.gas_${speed}`)}: ${ 10 | gasPrice && gasPrice.txFee.native 11 | ? gasPrice.txFee.native.value.display 12 | : '$0.00' 13 | }`}

14 |

{`~ ${gasPrice ? gasPrice.estimatedTime.display : '0 secs'}`}

15 |
16 | ); 17 | 18 | export default GasButton; 19 | -------------------------------------------------------------------------------- /src/handlers/localstorage.js: -------------------------------------------------------------------------------- 1 | import { commonStorage } from 'balance-common'; 2 | 3 | /** 4 | * @desc get suppress reminder ribbon setting 5 | * @return {Boolean} 6 | */ 7 | export const getSupressReminderRibbon = async () => { 8 | const reminderRibbon = await commonStorage.getLocal('supressreminderribbon'); 9 | return reminderRibbon ? reminderRibbon.data : null; 10 | }; 11 | 12 | /** 13 | * @desc save suppress reminder ribbon setting 14 | * @param {Boolean} [supress state] 15 | */ 16 | export const saveSupressReminderRibbon = async state => { 17 | await commonStorage.saveLocal('supressreminderribbon', { data: state }); 18 | }; 19 | -------------------------------------------------------------------------------- /src/assets/arrow-failed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/help.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/etherscan-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import exchange from './_exchange'; 3 | import modal from './_modal'; 4 | import ledger from './_ledger'; 5 | import trezor from './_trezor'; 6 | import metamask from './_metamask'; 7 | import walletconnect from './_walletconnect'; 8 | import notification from './_notification'; 9 | import warning from './_warning'; 10 | import zrxinstant from './_zrxinstant'; 11 | import { account, send } from 'balance-common'; 12 | 13 | export default combineReducers({ 14 | exchange, 15 | send, 16 | account, 17 | modal, 18 | ledger, 19 | trezor, 20 | metamask, 21 | notification, 22 | warning, 23 | walletconnect, 24 | zrxinstant, 25 | }); 26 | -------------------------------------------------------------------------------- /src/components/GasPanel/styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | import { colors } from '../../styles'; 4 | 5 | export const StyledGasOptions = styled.div` 6 | display: flex; 7 | justify-content: space-between; 8 | padding: 0; 9 | 10 | & button { 11 | background-color: transparent; 12 | box-shadow: none; 13 | color: rgb(${colors.darkGrey}); 14 | min-height: 64px; 15 | margin: 0; 16 | border-radius: 0; 17 | 18 | &:hover, 19 | &:active, 20 | &:focus { 21 | box-shadow: none !important; 22 | outline: none !important; 23 | background-color: transparent !important; 24 | color: rgb(${colors.darkGrey}) !important; 25 | } 26 | } 27 | `; 28 | -------------------------------------------------------------------------------- /src/pages/NotFound.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { lang } from 'balance-common'; 4 | import BaseLayout from '../layouts/base'; 5 | import Link from '../components/Link'; 6 | 7 | const StyledWrapper = styled.div` 8 | width: 100%; 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | padding: 20px; 13 | text-transform: uppercase; 14 | text-align: center; 15 | height: 360px; 16 | `; 17 | 18 | const NotFound = () => ( 19 | 20 | 21 | 22 |

{lang.t('message.page_not_found')}

23 | 24 |
25 |
26 | ); 27 | export default NotFound; 28 | -------------------------------------------------------------------------------- /src/components/LedgerLogo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import ledgerLogo from '../assets/ledger-logo.png'; 5 | 6 | const StyledLedgerLogo = styled.div` 7 | width: ${({ size }) => `${size}px`}; 8 | height: ${({ size }) => `${size * 0.25}px`}; 9 | & img { 10 | width: 100%; 11 | } 12 | `; 13 | 14 | const LedgerLogo = ({ size, ...props }) => ( 15 | 16 | ledger 17 | 18 | ); 19 | 20 | LedgerLogo.propTypes = { 21 | size: PropTypes.number, 22 | }; 23 | 24 | LedgerLogo.defaultProps = { 25 | size: 300, 26 | }; 27 | 28 | export default LedgerLogo; 29 | -------------------------------------------------------------------------------- /src/components/TrezorLogo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import trezorLogo from '../assets/trezor-logo.png'; 5 | 6 | const StyledTrezorLogo = styled.div` 7 | width: ${({ size }) => `${size}px`}; 8 | height: ${({ size }) => `${size * 0.3}px`}; 9 | & img { 10 | width: 100%; 11 | } 12 | `; 13 | 14 | const TrezorLogo = ({ size, ...props }) => ( 15 | 16 | trezor 17 | 18 | ); 19 | 20 | TrezorLogo.propTypes = { 21 | size: PropTypes.number, 22 | }; 23 | 24 | TrezorLogo.defaultProps = { 25 | size: 275, 26 | }; 27 | 28 | export default TrezorLogo; 29 | -------------------------------------------------------------------------------- /src/assets/cross.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/MetamaskLogo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import metamaskOriginal from '../assets/metamask-original.png'; 5 | 6 | const StyledMetamaskLogo = styled.div` 7 | width: ${({ size }) => `${size}px`}; 8 | height: ${({ size }) => `${size * 0.925}px`}; 9 | & img { 10 | width: 100%; 11 | } 12 | `; 13 | 14 | const MetamaskLogo = ({ size, ...props }) => ( 15 | 16 | metamask 17 | 18 | ); 19 | 20 | MetamaskLogo.propTypes = { 21 | size: PropTypes.number, 22 | }; 23 | 24 | MetamaskLogo.defaultProps = { 25 | size: 200, 26 | }; 27 | 28 | export default MetamaskLogo; 29 | -------------------------------------------------------------------------------- /src/Root.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createStore, applyMiddleware } from 'redux'; 3 | import { Provider } from 'react-redux'; 4 | import { Router } from 'react-router-dom'; 5 | import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'; 6 | import ReduxThunk from 'redux-thunk'; 7 | import history from './history'; 8 | import piwik from './piwik'; 9 | import reducers from './reducers'; 10 | import WalletRouter from './Router'; 11 | 12 | const store = createStore( 13 | reducers, 14 | composeWithDevTools(applyMiddleware(ReduxThunk)), 15 | ); 16 | 17 | const Root = () => ( 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | 25 | export default Root; 26 | -------------------------------------------------------------------------------- /src/assets/circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | circle 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/references/native-currencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "USD": { 3 | "symbol": "$", 4 | "currency": "USD", 5 | "decimals": 2, 6 | "alignment": "left", 7 | "assetLimit": 1 8 | }, 9 | "GBP": { 10 | "symbol": "£", 11 | "currency": "GBP", 12 | "decimals": 2, 13 | "alignment": "left", 14 | "assetLimit": 1 15 | }, 16 | "EUR": { 17 | "symbol": "€", 18 | "currency": "EUR", 19 | "decimals": 2, 20 | "alignment": "left", 21 | "assetLimit": 1 22 | }, 23 | "BTC": { 24 | "symbol": "₿", 25 | "currency": "BTC", 26 | "decimals": 8, 27 | "alignment": "right", 28 | "assetLimit": 0.0001 29 | }, 30 | "ETH": { 31 | "symbol": "Ξ", 32 | "currency": "ETH", 33 | "decimals": 8, 34 | "alignment": "right", 35 | "assetLimit": 0.001 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/components/WalletConnectLogo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import walletConnectBlue from '../assets/walletconnect-blue.svg'; 5 | 6 | const StyledWalletConnectLogo = styled.div` 7 | width: ${({ size }) => `${size}px`}; 8 | height: ${({ size }) => `${size * 0.68}px`}; 9 | & img { 10 | width: 100%; 11 | } 12 | `; 13 | 14 | const WalletConnectLogo = ({ size, ...props }) => ( 15 | 16 | WalletConnect 17 | 18 | ); 19 | 20 | WalletConnectLogo.propTypes = { 21 | size: PropTypes.number, 22 | }; 23 | 24 | WalletConnectLogo.defaultProps = { 25 | size: 250, 26 | }; 27 | 28 | export default WalletConnectLogo; 29 | -------------------------------------------------------------------------------- /src/components/Spinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled, { keyframes } from 'styled-components'; 4 | import spinnerImg from '../assets/spinner.png'; 5 | 6 | const spin = keyframes` 7 | 0% { 8 | transform: rotate(0deg); 9 | } 10 | 100% { 11 | transform: rotate(360deg); 12 | } 13 | `; 14 | 15 | const StyledSpinner = styled.img` 16 | width: ${({ size }) => `${size}px`}; 17 | height: ${({ size }) => `${size}px`}; 18 | 19 | animation: ${spin} 0.8s linear infinite; 20 | `; 21 | 22 | const Spinner = ({ size, ...props }) => ( 23 | 24 | ); 25 | 26 | Spinner.propTypes = { 27 | size: PropTypes.number, 28 | }; 29 | 30 | Spinner.defaultProps = { 31 | size: 8, 32 | }; 33 | 34 | export default Spinner; 35 | -------------------------------------------------------------------------------- /src/components/Background.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const StyledBackgroundFixed = styled.div` 5 | position: fixed; 6 | top: 0; 7 | left: 0; 8 | width: 100vw; 9 | height: 100vh; 10 | z-index: -99999; 11 | `; 12 | 13 | const StyledBackgroundRelative = styled.div` 14 | position: relative; 15 | width: 100%; 16 | height: 100%; 17 | `; 18 | 19 | const StyledBackgroundBlue = styled.div` 20 | position: fixed; 21 | bottom: 0; 22 | left: 0; 23 | width: 150px; 24 | height: 225px; 25 | & img { 26 | width: 100%; 27 | } 28 | `; 29 | 30 | const Background = () => ( 31 | 32 | 33 | 34 | 35 | 36 | ); 37 | 38 | export default Background; 39 | -------------------------------------------------------------------------------- /src/components/AccountType.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import MetamaskLogo from './MetamaskLogo'; 4 | import LedgerLogo from './LedgerLogo'; 5 | import TrezorLogo from './TrezorLogo'; 6 | import WalletConnectLogo from './WalletConnectLogo'; 7 | 8 | const AccountType = ({ accountType, ...props }) => { 9 | switch (accountType) { 10 | case 'METAMASK': 11 | return ; 12 | case 'LEDGER': 13 | return ; 14 | case 'TREZOR': 15 | return ; 16 | case 'WALLETCONNECT': 17 | return ; 18 | default: 19 | return
; 20 | } 21 | }; 22 | 23 | AccountType.propTypes = { 24 | accountType: PropTypes.string.isRequired, 25 | }; 26 | 27 | export default AccountType; 28 | -------------------------------------------------------------------------------- /src/references/ethereum-units.json: -------------------------------------------------------------------------------- 1 | { 2 | "basic_tx": 21000, 3 | "noether": 0, 4 | "wei": 1, 5 | "kwei": 1000, 6 | "Kwei": 1000, 7 | "babbage": 1000, 8 | "femtoether": 1000, 9 | "mwei": 1000000, 10 | "Mwei": 1000000, 11 | "lovelace": 1000000, 12 | "picoether": 1000000, 13 | "gwei": 1000000000, 14 | "Gwei": 1000000000, 15 | "shannon": 1000000000, 16 | "nanoether": 1000000000, 17 | "nano": 1000000000, 18 | "szabo": 1000000000000, 19 | "microether": 1000000000000, 20 | "micro": 1000000000000, 21 | "finney": 1000000000000000, 22 | "milliether": 1000000000000000, 23 | "milli": 1000000000000000, 24 | "ether": 1000000000000000000, 25 | "kether": 1000000000000000000000, 26 | "grand": 1000000000000000000000, 27 | "mether": 1000000000000000000000000, 28 | "gether": 1000000000000000000000000000, 29 | "tether": 1000000000000000000000000000000 30 | } 31 | -------------------------------------------------------------------------------- /src/reducers/_modal.js: -------------------------------------------------------------------------------- 1 | // -- Constants ------------------------------------------------------------- // 2 | 3 | const MODAL_OPEN = 'modal/MODAL_OPEN'; 4 | const MODAL_CLOSE = 'modal/MODAL_CLOSE'; 5 | 6 | // -- Actions --------------------------------------------------------------- // 7 | 8 | export const modalOpen = (modal, props) => ({ 9 | type: MODAL_OPEN, 10 | payload: modal, 11 | }); 12 | 13 | export const modalClose = () => ({ type: MODAL_CLOSE }); 14 | 15 | // -- Reducer --------------------------------------------------------------- // 16 | const INITIAL_STATE = { 17 | modal: '', 18 | }; 19 | 20 | export default (state = INITIAL_STATE, action) => { 21 | switch (action.type) { 22 | case MODAL_OPEN: 23 | return { ...state, modal: action.payload }; 24 | case MODAL_CLOSE: 25 | return { ...state, modal: '' }; 26 | default: 27 | return state; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/HoverWrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import { shadows } from '../styles'; 5 | 6 | const StyledHoverWrapper = styled.div` 7 | position: relative; 8 | width: 100%; 9 | z-index: ${({ hover }) => (hover ? 20 : 0)}; 10 | 11 | &:before { 12 | bottom: 0; 13 | box-shadow: ${shadows.big}; 14 | content: " "; 15 | left: 0; 16 | opacity: ${({ hover }) => (hover ? 1 : 0)} 17 | position: absolute; 18 | right: 0; 19 | top: 0; 20 | } 21 | `; 22 | 23 | const HoverWrapper = ({ hover, children, ...props }) => ( 24 | 25 | {children} 26 | 27 | ); 28 | 29 | HoverWrapper.propTypes = { 30 | children: PropTypes.node.isRequired, 31 | hover: PropTypes.bool.isRequired, 32 | }; 33 | 34 | export default HoverWrapper; 35 | -------------------------------------------------------------------------------- /src/components/Wrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled, { keyframes } from 'styled-components'; 4 | 5 | const fadeIn = keyframes` 6 | 0% { 7 | opacity: 0; 8 | } 9 | 100% { 10 | opacity: 1; 11 | } 12 | `; 13 | 14 | const StyledWrapper = styled.div` 15 | will-change: transform, opacity; 16 | animation: ${fadeIn} 0.7s ease 0s normal 1; 17 | min-height: 200px; 18 | display: flex; 19 | flex-wrap: wrap; 20 | justify-content: center; 21 | align-items: ${({ center }) => (center ? `center` : `flex-start`)}; 22 | `; 23 | 24 | const Wrapper = ({ children, center, ...props }) => ( 25 | 26 | {children} 27 | 28 | ); 29 | 30 | Wrapper.propTypes = { 31 | children: PropTypes.node.isRequired, 32 | center: PropTypes.bool, 33 | }; 34 | 35 | Wrapper.defaultProps = { 36 | center: false, 37 | }; 38 | 39 | export default Wrapper; 40 | -------------------------------------------------------------------------------- /src/components/GasPanel/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import GasPriceLineBreak from '../../components/GasPriceLineBreak'; 4 | import GasButton from '../../components/GasButton'; 5 | 6 | import { StyledGasOptions } from './styles'; 7 | 8 | // Not fully looking the same as before 9 | const GasPanel = ({ gasPriceOption, gasPrices, updateGasPrice }) => ( 10 | 11 | 12 | 13 | 18 | 23 | 28 | 29 | 30 | ); 31 | 32 | export default GasPanel; 33 | -------------------------------------------------------------------------------- /src/helpers/intercom.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | (function() { 3 | var w = window; 4 | var ic = w.Intercom; 5 | if (typeof ic === 'function') { 6 | ic('reattach_activator'); 7 | ic('update', intercomSettings); 8 | } else { 9 | var d = document; 10 | var i = function() { 11 | i.c(arguments); 12 | }; 13 | i.q = []; 14 | i.c = function(args) { 15 | i.q.push(args); 16 | }; 17 | w.Intercom = i; 18 | function l() { 19 | var s = d.createElement('script'); 20 | s.type = 'text/javascript'; 21 | s.async = true; 22 | s.src = `https://widget.intercom.io/widget/${ 23 | process.env.NODE_ENV === 'production' ? 'j0fl7v0m' : 'k8c9ptl1' 24 | }`; 25 | var x = d.getElementsByTagName('script')[0]; 26 | x.parentNode.insertBefore(s, x); 27 | } 28 | if (w.attachEvent) { 29 | w.attachEvent('onload', l); 30 | } else { 31 | w.addEventListener('load', l, false); 32 | } 33 | } 34 | })(); 35 | -------------------------------------------------------------------------------- /src/handlers/walletconnect.js: -------------------------------------------------------------------------------- 1 | import WalletConnect from 'walletconnect'; 2 | 3 | const dappName = 'Balance Manager'; 4 | const bridgeUrl = process.env.REACT_APP_WALLETCONNECT_BRIDGE_v7; 5 | 6 | /** 7 | * @desc init WalletConnect webConnector instance 8 | * @return {Object} 9 | */ 10 | export const walletConnectGetSession = async () => { 11 | const webConnector = new WalletConnect({ bridgeUrl, dappName }); 12 | await webConnector.initSession(); 13 | return webConnector; 14 | }; 15 | 16 | /** 17 | * @desc WalletConnect send transaction 18 | * @param {Object} transaction { from, to, data, value, gasPrice, gasLimit } 19 | * @return {String} 20 | */ 21 | export const walletConnectSignTransaction = async transaction => { 22 | const webConnector = await walletConnectGetSession(); 23 | if (webConnector.isConnected) { 24 | return await webConnector.sendTransaction(transaction); 25 | } else { 26 | throw new Error('WalletConnect session has expired. Please reconnect.'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/assets/exchange-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | exchange-icon 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/AssetIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import eth from '../assets/eth.svg'; 5 | import erc20 from '../assets/erc20.svg'; 6 | 7 | const StyledIcon = styled.img` 8 | width: ${({ size }) => `${size}px`}; 9 | height: ${({ size }) => `${size}px`}; 10 | `; 11 | 12 | const buildAssetSourceUrl = asset => { 13 | if (!asset) return erc20; 14 | if (asset.toUpperCase() === 'ETH') return eth; 15 | return `/tokens/images/${asset}.png`; 16 | }; 17 | 18 | const AssetIcon = ({ asset, image, size }) => ( 19 | (event.target.src = erc20)} 21 | size={size} 22 | src={image || buildAssetSourceUrl(asset)} 23 | /> 24 | ); 25 | 26 | AssetIcon.propTypes = { 27 | asset: PropTypes.string, 28 | image: PropTypes.string, 29 | size: PropTypes.number, 30 | }; 31 | 32 | AssetIcon.defaultProps = { 33 | asset: null, 34 | image: '', 35 | size: 20, 36 | }; 37 | 38 | export default AssetIcon; 39 | -------------------------------------------------------------------------------- /src/components/Form.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | 5 | import { responsive } from '../styles'; 6 | 7 | const StyledForm = styled.form` 8 | width: 100%; 9 | display: block; 10 | 11 | & > * { 12 | padding: 16px 16px 0; 13 | } 14 | 15 | & > *:last-child { 16 | padding: 16px; 17 | } 18 | 19 | @media screen and (${responsive.xs.max}) { 20 | & > * { 21 | padding: 16px 8px 0; 22 | } 23 | 24 | & > *:last-child { 25 | padding: 16px 8px; 26 | } 27 | } 28 | `; 29 | 30 | class Form extends Component { 31 | componentWillUnmount() { 32 | document.activeElement.blur(); 33 | } 34 | render = () => { 35 | const { children, ...props } = this.props; 36 | return ( 37 | 38 | {children} 39 | 40 | ); 41 | }; 42 | } 43 | 44 | Form.propTypes = { 45 | children: PropTypes.node.isRequired, 46 | }; 47 | 48 | export default Form; 49 | -------------------------------------------------------------------------------- /src/components/Column.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | 5 | const StyledColumn = styled.div` 6 | position: relative; 7 | width: 100%; 8 | height: ${({ spanHeight }) => (spanHeight ? '100%' : 'auto')}; 9 | max-width: ${({ maxWidth }) => `${maxWidth}px`}; 10 | margin: 0 auto; 11 | display: flex; 12 | flex-direction: column; 13 | align-items: center; 14 | justify-content: ${({ center }) => (center ? 'center' : 'flex-start')}; 15 | `; 16 | 17 | const Column = ({ children, spanHeight, maxWidth, center, ...props }) => ( 18 | 24 | {children} 25 | 26 | ); 27 | 28 | Column.propTypes = { 29 | children: PropTypes.node.isRequired, 30 | spanHeight: PropTypes.bool, 31 | maxWidth: PropTypes.number, 32 | center: PropTypes.bool, 33 | }; 34 | 35 | Column.defaultProps = { 36 | spanHeightL: false, 37 | maxWidth: 600, 38 | center: false, 39 | }; 40 | 41 | export default Column; 42 | -------------------------------------------------------------------------------- /src/assets/qr-code-transparent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/components/TextButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import { colors, fonts, transitions } from '../styles'; 5 | 6 | const StyledTextButton = styled.button` 7 | transition: ${transitions.base}; 8 | display: block; 9 | border: none; 10 | border-style: none; 11 | box-sizing: border-box; 12 | background: transparent; 13 | color: ${({ color }) => `rgb(${colors[color]})`}; 14 | font-size: ${fonts.size.medium}; 15 | font-weight: ${fonts.weight.normal}; 16 | margin: 5px; 17 | cursor: pointer; 18 | will-change: transform; 19 | line-height: normal; 20 | 21 | @media (hover: hover) { 22 | &:hover { 23 | opacity: 0.6; 24 | } 25 | } 26 | `; 27 | 28 | const TextButton = ({ children, ...props }) => ( 29 | {children} 30 | ); 31 | 32 | TextButton.propTypes = { 33 | children: PropTypes.node.isRequired, 34 | fetching: PropTypes.bool, 35 | color: PropTypes.string, 36 | }; 37 | 38 | TextButton.defaultProps = { 39 | fetching: false, 40 | color: 'darkGrey', 41 | }; 42 | 43 | export default TextButton; 44 | -------------------------------------------------------------------------------- /src/assets/caret.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/components/QRCodeDisplay.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import QRCode from 'qrcode'; 5 | 6 | const StyledWrapper = styled.div` 7 | width: 100%; 8 | margin: 10px auto; 9 | display: flex; 10 | align-items: center; 11 | justify-content: center; 12 | `; 13 | 14 | class QRCodeDisplay extends Component { 15 | componentDidMount() { 16 | QRCode.toCanvas( 17 | this.canvas, 18 | this.props.data, 19 | { 20 | errorCorrectionLevel: this.props.errorCorrectionLevel, 21 | scale: this.props.scale, 22 | }, 23 | error => { 24 | if (error) console.error(error); 25 | }, 26 | ); 27 | } 28 | render = () => ( 29 | 30 | (this.canvas = c)} /> 31 | 32 | ); 33 | } 34 | 35 | QRCodeDisplay.propTypes = { 36 | data: PropTypes.string.isRequired, 37 | errorCorrectionLevel: PropTypes.string, 38 | scale: PropTypes.number, 39 | }; 40 | 41 | QRCodeDisplay.defaultProps = { 42 | errorCorrectionLevel: 'L', 43 | scale: 7, 44 | }; 45 | 46 | export default QRCodeDisplay; 47 | -------------------------------------------------------------------------------- /src/assets/walletconnect-blue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/reducers/_notification.js: -------------------------------------------------------------------------------- 1 | // -- Constants ------------------------------------------------------------- // 2 | const NOTIFICATION_SHOW = 'notification/NOTIFICATION_SHOW'; 3 | const NOTIFICATION_HIDE = 'notification/NOTIFICATION_HIDE'; 4 | 5 | // -- Actions --------------------------------------------------------------- // 6 | let timeoutHide; 7 | 8 | export const notificationShow = (message, error = false) => dispatch => { 9 | clearTimeout(timeoutHide); 10 | dispatch({ type: NOTIFICATION_SHOW, payload: { message, error } }); 11 | timeoutHide = setTimeout(() => dispatch({ type: NOTIFICATION_HIDE }), 15000); 12 | }; 13 | 14 | // -- Reducer --------------------------------------------------------------- // 15 | const INITIAL_STATE = { 16 | show: false, 17 | error: false, 18 | message: '', 19 | }; 20 | 21 | export default (state = INITIAL_STATE, action) => { 22 | switch (action.type) { 23 | case NOTIFICATION_SHOW: 24 | return { 25 | ...state, 26 | show: true, 27 | message: action.payload.message, 28 | error: action.payload.error, 29 | }; 30 | case NOTIFICATION_HIDE: 31 | return { ...state, show: false, message: '', error: false }; 32 | default: 33 | return state; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/assets/opera-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/triangles-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | triangles 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/components/Blockie.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | 5 | const StyledWrapper = styled.div` 6 | width: ${({ size }) => (size ? `${size}px` : '32px')}; 7 | height: ${({ size }) => (size ? `${size}px` : '32px')}; 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | border-radius: 3px; 12 | margin-right: 10px; 13 | overflow: hidden; 14 | & img { 15 | width: 100%; 16 | } 17 | `; 18 | 19 | const Blockie = ({ seed, color, bgcolor, size, scale, spotcolor }) => { 20 | const imgUrl = window.blockies 21 | .create({ seed, color, bgcolor, size, scale, spotcolor }) 22 | .toDataURL(); 23 | return ( 24 | 25 | address 26 | 27 | ); 28 | }; 29 | 30 | Blockie.propTypes = { 31 | seed: PropTypes.string.isRequired, 32 | color: PropTypes.string, 33 | bgcolor: PropTypes.string, 34 | size: PropTypes.number, 35 | scale: PropTypes.number, 36 | spotcolor: PropTypes.string, 37 | }; 38 | 39 | Blockie.defaultProps = { 40 | color: null, 41 | bgcolor: null, 42 | size: null, 43 | scale: null, 44 | spotcolor: null, 45 | }; 46 | 47 | export default Blockie; 48 | -------------------------------------------------------------------------------- /src/modals/ApproveTransactionModal/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { capitalize, lang } from 'balance-common'; 4 | 5 | import MetamaskLogo from '../../components/MetamaskLogo'; 6 | import LedgerLogo from '../../components/LedgerLogo'; 7 | import TrezorLogo from '../../components/TrezorLogo'; 8 | 9 | import Button from '../../components/Button'; 10 | 11 | import { StyledApproveTransaction } from './styles'; 12 | import { StyledParagraph, StyledActions } from '../modalStyles'; 13 | 14 | const ApproveTransactionModal = ({ accountType, onClose }) => ( 15 | 16 | {(() => { 17 | switch (accountType) { 18 | case 'METAMASK': 19 | return ; 20 | case 'LEDGER': 21 | return ; 22 | case 'TREZOR': 23 | return ; 24 | default: 25 | return
; 26 | } 27 | })()} 28 | 29 | 30 | {lang.t('modal.approve_tx', { 31 | walletType: capitalize(accountType), 32 | })} 33 | 34 | 35 | 36 | 37 | 38 | 39 | ); 40 | 41 | export default ApproveTransactionModal; 42 | -------------------------------------------------------------------------------- /src/assets/balances-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/ClickOutside.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export default class ClickOutside extends Component { 5 | static propTypes = { 6 | onClickOutside: PropTypes.func.isRequired, 7 | }; 8 | 9 | constructor(props) { 10 | super(props); 11 | this.isTouch = false; 12 | } 13 | 14 | handleContainerRef = ref => { 15 | this.containerRef = ref; 16 | }; 17 | 18 | componentDidMount() { 19 | document.addEventListener('touchend', this.handle, true); 20 | document.addEventListener('click', this.handle, true); 21 | } 22 | 23 | componentWillUnmount() { 24 | document.removeEventListener('touchend', this.handle, true); 25 | document.removeEventListener('click', this.handle, true); 26 | } 27 | 28 | handle = event => { 29 | if (event.type === 'touchend') this.isTouch = true; 30 | if (event.type === 'click' && this.isTouch) return; 31 | const { onClickOutside } = this.props; 32 | const el = this.containerRef; 33 | if (!el.contains(event.target)) onClickOutside(event); 34 | }; 35 | 36 | render() { 37 | const { children, onClickOutside, ...props } = this.props; 38 | return ( 39 |
40 | {children} 41 |
42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/assets/caret-small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dropdownArrow Copy 5 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/assets/opera-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/blockies.min.js: -------------------------------------------------------------------------------- 1 | !function(){function e(e){for(var o=0;o>19^e^e>>8,(c[3]>>>0)/(1<<31>>>0)}function r(){var e=Math.floor(360*o()),r=60*o()+40+"%",t=25*(o()+o()+o()+o())+"%",l="hsl("+e+","+r+","+t+")";return l}function t(e){for(var r=e,t=e,l=Math.ceil(r/2),n=r-l,a=[],c=0;t>c;c++){for(var i=[],f=0;l>f;f++)i[f]=Math.floor(2.3*o());var s=i.slice(0,n);s.reverse(),i=i.concat(s);for(var h=0;h ( 15 | 16 | 17 | 18 | {`Success`} 19 | 20 | 21 |
22 | 23 | {`${lang.t('modal.tx_hash')}:`} 24 | 25 | {` ${txHash}`} 26 |
27 | 28 | 29 | 36 | {lang.t('modal.tx_verify')} 37 | 38 | 39 | 40 | 41 | 44 | 45 |
46 | ); 47 | 48 | export default SuccessModal; 49 | -------------------------------------------------------------------------------- /src/assets/gbp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gbp 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './helpers/intercom'; 4 | import { injectGlobal } from 'styled-components'; 5 | import { globalStyles } from './styles'; 6 | import { bootIntercom } from './helpers/bootIntercom'; 7 | import Root from './Root'; 8 | import Storage from '@devshack/react-native-storage'; 9 | import { commonStorage, lang, resources } from 'balance-common'; 10 | 11 | const storage = new Storage({ 12 | size: 1000, 13 | storageBackend: window.localStorage, 14 | defaultExpires: null, 15 | enableCache: true, 16 | }); 17 | 18 | window.storage = storage; 19 | 20 | // Languages (i18n) 21 | lang.init({ 22 | lng: 'en', 23 | fallbackLng: 'en', 24 | debug: process.env.NODE_ENV === 'development', 25 | resources, 26 | }); 27 | 28 | commonStorage 29 | .getLanguage() 30 | .then(language => { 31 | lang.init({ 32 | lng: language, 33 | fallbackLng: 'en', 34 | debug: process.env.NODE_ENV === 'development', 35 | resources, 36 | }); 37 | }) 38 | .catch(error => { 39 | lang.init({ 40 | lng: 'en', 41 | fallbackLng: 'en', 42 | debug: process.env.NODE_ENV === 'development', 43 | resources, 44 | }); 45 | }); 46 | 47 | // eslint-disable-next-line 48 | injectGlobal`${globalStyles}`; 49 | 50 | // Intercom 51 | bootIntercom(); 52 | 53 | ReactDOM.render(, document.getElementById('root')); 54 | -------------------------------------------------------------------------------- /src/assets/trustwallet-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/LineBreak.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import { colors } from '../styles'; 5 | 6 | const StyledLineBreakWrapper = styled.div` 7 | position: relative; 8 | width: 100% !important; 9 | padding: 0 !important; 10 | margin: 0 !important; 11 | margin-top: ${({ noMargin }) => 12 | noMargin ? `0 !important` : `25px !important`}; 13 | border-top: 2px solid rgb(241, 242, 246); 14 | `; 15 | 16 | const StyledLineBreakFiller = styled.div` 17 | transition: 0.32s cubic-bezier(0.77, 0, 0.175, 1); 18 | position: absolute; 19 | left: 0; 20 | bottom: 0; 21 | width: 100%; 22 | transform-origin: 0; 23 | transform: ${({ percentage }) => `scale3d(${percentage / 100}, 1, 1)`}; 24 | border-top: ${({ color }) => 25 | color ? `2px solid rgb(${colors[color]})` : `2px solid rgb(241, 242, 246)`}; 26 | `; 27 | 28 | const LineBreak = ({ noMargin, color, percentage, ...props }) => ( 29 | 30 | 31 | 32 | ); 33 | 34 | LineBreak.propTypes = { 35 | noMargin: PropTypes.bool, 36 | color: PropTypes.string, 37 | percentage: PropTypes.number, 38 | }; 39 | 40 | LineBreak.defaultProps = { 41 | noMargin: false, 42 | color: '', 43 | percentage: 0, 44 | }; 45 | 46 | export default LineBreak; 47 | -------------------------------------------------------------------------------- /src/assets/btc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | BTC 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/eur.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | eur 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Balance Manager 2 | 3 | Balance Manager Preview 4 | 5 | #### Ethereum Wallet Manager for MetaMask, Ledger, Trezor and WalletConnect 6 | 7 | ### Getting started 8 | 9 | We use submodules to sync [Balance Token image assets](https://github.com/balance-io/tokens) into this project 10 | After cloning `balance-manager`, run this command to install all `git submodules` 11 | 12 | ``` 13 | git submodule update --init --recursive 14 | ``` 15 | 16 | Then install all project dependencies 17 | 18 | ``` 19 | yarn 20 | - or - 21 | npm install 22 | ``` 23 | 24 | ## How to run Manager 25 | 26 | For development 27 | 28 | ``` 29 | yarn start 30 | - or - 31 | npm run start 32 | ``` 33 | 34 | For production 35 | 36 | ``` 37 | yarn build 38 | - or - 39 | npm run build 40 | ``` 41 | 42 | ## Want to help us? 43 | 44 | We really appreciate any time you can spare. We need help with design, engineering, translation and security audit. 45 | 46 | Issues: https://github.com/balance-io/balance-manager/issues 47 | 48 | Community: https://spectrum.chat/balance/manager 49 | 50 | Stuck on something? Got questions? Want to chat privately? Send @ricburton a Direct Message (DM) on Twitter at any time: twitter.com/ricburton 51 | 52 | ## How to contribute to Manager 53 | 54 | Always clone or fork from the `latest` branch. 55 | We are going to work on making this process as simple as possible. 56 | At this stage we would encourage you to comment on issues you want to work on and reach out to us over Spectrum or Twitter. 57 | -------------------------------------------------------------------------------- /src/Router.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Route, Switch, withRouter } from 'react-router-dom'; 3 | import { connect } from 'react-redux'; 4 | import PropTypes from 'prop-types'; 5 | import Homepage from './pages'; 6 | import Wallet from './pages/Wallet'; 7 | import Metamask from './pages/Metamask'; 8 | import Ledger from './pages/Ledger'; 9 | import Trezor from './pages/Trezor'; 10 | import NotFound from './pages/NotFound'; 11 | import { warningOnline, warningOffline } from './reducers/_warning'; 12 | 13 | class Router extends Component { 14 | componentDidMount() { 15 | window.browserHistory = this.context.router.history; 16 | window.onoffline = () => this.props.warningOffline(); 17 | window.ononline = () => this.props.warningOnline(); 18 | } 19 | 20 | render = () => ( 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | Router.contextTypes = { 33 | router: PropTypes.object.isRequired, 34 | store: PropTypes.object.isRequired, 35 | email: PropTypes.string, 36 | signup: PropTypes.any, 37 | }; 38 | 39 | const reduxProps = ({ account }) => ({ 40 | language: account.language, 41 | }); 42 | 43 | export default withRouter( 44 | connect( 45 | reduxProps, 46 | { 47 | warningOffline, 48 | warningOnline, 49 | }, 50 | )(Router), 51 | ); 52 | -------------------------------------------------------------------------------- /src/components/ToggleIndicator.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import balancesTabIcon from '../assets/balances-tab.svg'; 5 | import circle from '../assets/circle.svg'; 6 | import { colors, fonts } from '../styles'; 7 | 8 | const StyledToggleIndicator = styled.div` 9 | display: flex; 10 | align-items: center; 11 | cursor: pointer; 12 | 13 | &:not(:last-child) { 14 | padding-right: 16px; 15 | } 16 | 17 | @media (hover: hover) { 18 | &:hover span { 19 | color: rgb(${colors.darkGrey}); 20 | } 21 | } 22 | `; 23 | 24 | const StyledToggleIndicatorIcon = styled.span` 25 | display: inline-flex; 26 | height: 16px; 27 | width: 16px; 28 | margin-right: 8px; 29 | mask: ${({ show }) => 30 | show 31 | ? `url(${circle}) center no-repeat` 32 | : `url(${balancesTabIcon}) center no-repeat`}; 33 | background-color: rgb(${colors.grey}); 34 | `; 35 | 36 | const StyledToggleIndicatorText = styled.p` 37 | display: inline-flex; 38 | text-align: left; 39 | font-family: ${fonts.family.SFProText}; 40 | font-weight: ${fonts.weight.medium}; 41 | font-size: 13px; 42 | color: rgb(${colors.grey}); 43 | `; 44 | 45 | const ToggleIndicator = ({ children, show, ...props }) => ( 46 | 47 | 48 | {children} 49 | 50 | ); 51 | 52 | ToggleIndicator.propTypes = { 53 | show: PropTypes.bool, 54 | }; 55 | 56 | ToggleIndicator.defaultProps = { 57 | show: false, 58 | }; 59 | 60 | export default ToggleIndicator; 61 | -------------------------------------------------------------------------------- /src/assets/firefox-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Notification.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import PropTypes from 'prop-types'; 4 | import { connect } from 'react-redux'; 5 | import { colors, shadows, responsive, transitions } from '../styles'; 6 | 7 | const StyledNotification = styled.div` 8 | position: fixed; 9 | z-index: 20; 10 | width: calc(100% - 20px); 11 | max-width: 400px; 12 | top: 0; 13 | right: 0; 14 | margin: 10px; 15 | text-align: center; 16 | padding: 15px 20px; 17 | border-radius: 8px; 18 | text-align: center; 19 | transition: ${transitions.base}; 20 | background: rgb(${colors.white}); 21 | color: ${({ error }) => 22 | error ? `rgb(${colors.red})` : `rgb(${colors.dark})`}; 23 | box-shadow: ${shadows.medium}; 24 | transform: ${({ show }) => 25 | show ? 'translate3d(0, 0, 0)' : 'translate3d(0, -1000px, 0);'}; 26 | 27 | @media screen and (${responsive.sm.max}) { 28 | top: auto; 29 | left: 0; 30 | bottom: 0; 31 | margin: 0 auto; 32 | transform: ${({ show }) => 33 | show ? 'translate3d(0, 0, 0)' : 'translate3d(0, 1000px, 0);'}; 34 | } 35 | `; 36 | 37 | const Notification = ({ show, error, message, ...props }) => ( 38 | 39 | {message} 40 | 41 | ); 42 | 43 | Notification.propTypes = { 44 | show: PropTypes.bool.isRequired, 45 | error: PropTypes.bool.isRequired, 46 | message: PropTypes.string.isRequired, 47 | }; 48 | 49 | const reduxProps = ({ notification }) => ({ 50 | error: notification.error, 51 | show: notification.show, 52 | message: notification.message, 53 | }); 54 | 55 | export default connect( 56 | reduxProps, 57 | null, 58 | )(Notification); 59 | -------------------------------------------------------------------------------- /src/assets/convert-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/usd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | usd 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/assets/chrome-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pages/Wallet.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import styled from 'styled-components'; 5 | import BaseLayout from '../layouts/base'; 6 | import Account from '../views/Account'; 7 | import Card from '../components/Card'; 8 | import { lang } from 'balance-common'; 9 | import { fonts, colors } from '../styles'; 10 | 11 | const StyledWrapper = styled.div` 12 | width: 100%; 13 | `; 14 | 15 | const StyledMessage = styled.div` 16 | display: flex; 17 | align-items: center; 18 | justify-content: center; 19 | color: rgb(${colors.grey}); 20 | font-weight: ${fonts.weight.medium}; 21 | `; 22 | 23 | class Wallet extends Component { 24 | componentDidMount() { 25 | if (!this.props.accountAddress) { 26 | console.log('wallet page does not have account address'); 27 | this.props.history.push('/'); 28 | } 29 | } 30 | 31 | render = () => ( 32 | 33 | 34 | {this.props.fetching || this.props.accountAddress ? ( 35 | 36 | ) : ( 37 | 38 | 39 | {lang.t('message.walletconnect_not_unlocked')} 40 | 41 | 42 | )} 43 | 44 | 45 | ); 46 | } 47 | 48 | Wallet.propTypes = { 49 | accountAddress: PropTypes.string, 50 | fetching: PropTypes.bool.isRequired, 51 | match: PropTypes.object.isRequired, 52 | }; 53 | 54 | Wallet.defaultProps = { 55 | accountAddress: null, 56 | }; 57 | 58 | const reduxProps = ({ walletconnect }) => ({ 59 | fetching: walletconnect.fetching, 60 | accountAddress: walletconnect.accountAddress, 61 | }); 62 | 63 | export default connect( 64 | reduxProps, 65 | null, 66 | )(Wallet); 67 | -------------------------------------------------------------------------------- /src/components/Loader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled, { keyframes } from 'styled-components'; 4 | import { fonts, colors } from '../styles'; 5 | 6 | const load = keyframes` 7 | 0% { 8 | transform: rotate(0deg); 9 | } 10 | 100% { 11 | transform: rotate(360deg); 12 | } 13 | `; 14 | 15 | const StyledLoader = styled.div` 16 | position: relative; 17 | font-size: ${fonts.size.tiny}; 18 | margin: 0 auto; 19 | text-indent: -9999em; 20 | width: ${({ size }) => `${size}px`}; 21 | height: ${({ size }) => `${size}px`}; 22 | border-radius: 50%; 23 | background ${({ color }) => `rgb(${colors[color]})`}; 24 | background: ${({ background, color }) => 25 | `linear-gradient(to right, rgb(${colors[color]}) 10%, rgba(${ 26 | colors[background] 27 | }, 0) 42%)`}; 28 | animation: ${load} 1s infinite linear; 29 | transform: translateZ(0); 30 | 31 | &:before { 32 | width: 50%; 33 | height: 50%; 34 | background ${({ color }) => `rgb(${colors[color]})`}; 35 | border-radius: 100% 0 0 0; 36 | position: absolute; 37 | top: 0; 38 | left: 0; 39 | content: ''; 40 | } 41 | 42 | &:after { 43 | background: ${({ background }) => `rgb(${colors[background]})`}; 44 | width: 75%; 45 | height: 75%; 46 | border-radius: 50%; 47 | content: ''; 48 | margin: auto; 49 | position: absolute; 50 | top: 0; 51 | left: 0; 52 | bottom: 0; 53 | right: 0; 54 | } 55 | `; 56 | 57 | const Loader = ({ size, color, background, ...props }) => ( 58 | 59 | ); 60 | 61 | Loader.propTypes = { 62 | size: PropTypes.number, 63 | color: PropTypes.string, 64 | background: PropTypes.string, 65 | }; 66 | 67 | Loader.defaultProps = { 68 | size: 50, 69 | color: 'white', 70 | background: 'dark', 71 | }; 72 | 73 | export default Loader; 74 | -------------------------------------------------------------------------------- /src/assets/mail.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Shape@2x 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/brave-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Balance Manager 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 40 |
41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /src/assets/interactions-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | interactions-tab 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/QRCodeReader.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import QrReader from 'react-qr-reader'; 5 | import Column from './Column'; 6 | import cross from '../assets/cross.svg'; 7 | import { colors } from '../styles'; 8 | 9 | const StyledWrapper = styled.div` 10 | position: fixed; 11 | top: 0; 12 | left: 0; 13 | right: 0; 14 | bottom: 0; 15 | z-index: 5; 16 | margin: 0 auto !important; 17 | background: rgb(${colors.black}); 18 | `; 19 | 20 | const StyledClose = styled.img` 21 | position: absolute; 22 | z-index: 10; 23 | top: 15px; 24 | right: 15px; 25 | width: 30px; 26 | height: 30px; 27 | mask: url(${cross}) center no-repeat; 28 | mask-size: 95%; 29 | background-color: rgb(${colors.grey}); 30 | 31 | @media (hover: hover) { 32 | &:hover { 33 | opacity: 0.6; 34 | } 35 | } 36 | `; 37 | 38 | class QRCodeReader extends Component { 39 | state = { 40 | delay: 500, 41 | }; 42 | stopRecording = () => this.setState({ delay: false }); 43 | handleScan = data => { 44 | if (data) { 45 | const validate = this.props.onValidate(data); 46 | if (validate.result) { 47 | this.stopRecording(); 48 | this.props.onScan(validate.data); 49 | } else { 50 | validate.onError(); 51 | } 52 | } 53 | }; 54 | handleError = error => { 55 | console.error(error); 56 | this.props.onError(error); 57 | }; 58 | onClose = () => { 59 | this.stopRecording(); 60 | this.props.onClose(); 61 | }; 62 | componentWillUnmount() { 63 | this.stopRecording(); 64 | } 65 | render() { 66 | return ( 67 | 68 | 69 | 70 | 76 | 77 | 78 | ); 79 | } 80 | } 81 | 82 | QRCodeReader.propTypes = { 83 | onScan: PropTypes.func.isRequired, 84 | onError: PropTypes.func.isRequired, 85 | onClose: PropTypes.func.isRequired, 86 | onValidate: PropTypes.func.isRequired, 87 | }; 88 | 89 | export default QRCodeReader; 90 | -------------------------------------------------------------------------------- /src/modals/ReceiveModal/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import styled from 'styled-components'; 5 | 6 | import { capitalize, lang } from 'balance-common'; 7 | 8 | import Card from '../../components/Card'; 9 | import Button from '../../components/Button'; 10 | 11 | import arrowUp from '../../assets/arrow-up.svg'; 12 | 13 | import { modalClose } from '../../reducers/_modal'; 14 | 15 | import { 16 | StyledContainer, 17 | StyledQRCodeDisplay, 18 | StyledIcon, 19 | StyledSubTitle, 20 | StyledJustifyContent, 21 | StyledCopyToClipboard, 22 | } from '../modalStyles'; 23 | 24 | const reduxProps = ({ account }) => ({ 25 | accountAddress: account.accountAddress, 26 | accountType: account.accountType, 27 | }); 28 | 29 | const StyledCardContainer = styled.div` 30 | max-width: 440px; 31 | width: 100%; 32 | `; 33 | 34 | class ReceiveModal extends Component { 35 | static propTypes = { 36 | modalClose: PropTypes.func.isRequired, 37 | accountAddress: PropTypes.string.isRequired, 38 | accountType: PropTypes.string.isRequired, 39 | }; 40 | 41 | onClose = () => { 42 | this.props.modalClose(); 43 | }; 44 | 45 | render = () => { 46 | return ( 47 | 48 | 49 | 50 | 51 | 52 | 53 | {lang.t('modal.receive_title', { 54 | walletName: capitalize( 55 | `${this.props.accountType}${lang.t( 56 | 'modal.default_wallet', 57 | )}`, 58 | ), 59 | })} 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | ); 69 | }; 70 | } 71 | 72 | export default connect( 73 | reduxProps, 74 | { 75 | modalClose, 76 | }, 77 | )(ReceiveModal); 78 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { lang } from 'balance-common'; 4 | import OpenSeaLogo from '../assets/opensea-logo.svg'; 5 | import { fonts, responsive } from '../styles'; 6 | 7 | const Container = styled.div` 8 | border-top: solid #e1e4e8 1px; 9 | display: flex; 10 | 11 | @media screen and (${responsive.sm.max}) { 12 | flex-direction: column-reverse; 13 | } 14 | `; 15 | 16 | const ContainerLogo = styled.div` 17 | border-left: solid #e1e4e8 1px; 18 | display: flex; 19 | flex-basis: 25%; 20 | flex-direction: column; 21 | justify-content: center; 22 | padding: 20px; 23 | 24 | @media screen and (${responsive.sm.max}) { 25 | border-left: none; 26 | flex-basis: 100%; 27 | padding-bottom: 0; 28 | } 29 | `; 30 | 31 | const TextField = styled.div` 32 | padding: 20px; 33 | width: 75%; 34 | 35 | @media screen and (${responsive.sm.max}) { 36 | width: 100%; 37 | } 38 | `; 39 | 40 | const Header = styled.p` 41 | font-size: ${fonts.size.large}; 42 | font-weight: 500; 43 | margin-bottom: 5px; 44 | `; 45 | 46 | const Text = styled.p` 47 | font-size: ${fonts.size.medium}; 48 | line-height: 24px; 49 | `; 50 | 51 | const Link = styled.a` 52 | color: #6783e0; 53 | `; 54 | 55 | const LinkFat = styled.a` 56 | color: #6783e0; 57 | font-weight: bold; 58 | `; 59 | 60 | const PowerUp = styled.div` 61 | margin: 0; 62 | font-weight: 500; 63 | color: #91939f; 64 | padding-bottom: 10px; 65 | display: inline; 66 | `; 67 | 68 | const Footer = () => ( 69 | 70 | 71 |
{lang.t('message.opensea_header')}
72 | 73 | 78 | OpenSea 79 | 80 | {lang.t('message.opensea_footer')} 81 | 86 | {lang.t('button.learn_more')} 87 | 88 | 89 |
90 | 91 | {lang.t('message.power_by')} 92 | OpenSea Logo 93 | 94 |
95 | ); 96 | 97 | export default Footer; 98 | -------------------------------------------------------------------------------- /src/views/Account/AccountUniqueTokens.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import PropTypes from 'prop-types'; 4 | import styled from 'styled-components'; 5 | import { lang } from 'balance-common'; 6 | import Card from '../../components/Card'; 7 | import Footer from '../../components/Footer'; 8 | import UniqueToken from '../../components/UniqueToken'; 9 | import { colors, fonts } from '../../styles'; 10 | 11 | const UniqueTokensContainer = styled.div` 12 | background: #ffffff; 13 | `; 14 | 15 | const StyledContainer = styled.div` 16 | background: #f7f8fc; 17 | border: 2px solid #e2e2e2; 18 | border-radius: 15px; 19 | padding: 20px 10px 0px; 20 | margin: 15px; 21 | `; 22 | 23 | const StyledCard = styled(Card)` 24 | box-shadow: none; 25 | padding: 0 16px; 26 | `; 27 | 28 | const StyledMessage = styled.div` 29 | display: flex; 30 | align-items: center; 31 | justify-content: center; 32 | color: rgb(${colors.grey}); 33 | font-weight: ${fonts.weight.medium}; 34 | `; 35 | 36 | class AccountUniqueTokens extends Component { 37 | render() { 38 | const { uniqueTokens } = this.props; 39 | if (!uniqueTokens) return null; 40 | 41 | return !!uniqueTokens.length ? ( 42 | !this.props.fetchingUniqueTokens ? ( 43 | 44 | 45 | {uniqueTokens.map(token => ( 46 | 47 | ))} 48 | 49 |