"
8 | ],
9 | "description": "Collateralized Debt Position Portal for creating and managing Single-Collateral Dai CDPs in the Dai Stablecoin System.",
10 | "private": true,
11 | "homepage": "https://cdp.makerdao.com",
12 | "dependencies": {
13 | "@ledgerhq/hw-app-eth": "^4.7.3",
14 | "@ledgerhq/hw-transport-u2f": "^4.7.3",
15 | "axios": "^0.19.0",
16 | "bignumber.js": "^7.2.1",
17 | "create-react-class": "^15.6.3",
18 | "ethereumjs-tx": "^1.3.4",
19 | "hdkey": "^0.8.0",
20 | "ismobilejs": "^0.5.1",
21 | "jazzicon": "^1.5.0",
22 | "markdown-to-jsx": "^6.10.3",
23 | "mixpanel-browser": "^2.29.0",
24 | "mobx": "^5.13.0",
25 | "mobx-react": "^6.1.3",
26 | "rc-steps": "^3.5.0",
27 | "react": "^16.9.0",
28 | "react-document-title": "^2.0.3",
29 | "react-dom": "^16.9.0",
30 | "react-ga": "^2.6.0",
31 | "react-rangeslider": "^2.2.0",
32 | "react-router-dom": "^5.0.1",
33 | "react-scripts": "3.1.1",
34 | "react-select": "^1.2.1",
35 | "react-slick": "^0.25.2",
36 | "react-tooltip": "^3.10.0",
37 | "trezor-connect": "^7.0.5",
38 | "walletlink": "^1.0.0",
39 | "web3": "^0.20.6",
40 | "web3-provider-engine": "^14.0.4"
41 | },
42 | "scripts": {
43 | "build-css": "node-sass-chokidar src/scss/ -o src/scss/ --recursive",
44 | "watch-css": "yarn build-css && node-sass-chokidar src/scss/ -o src/scss/ --recursive --watch",
45 | "start-js": "craco start",
46 | "start": "npm-run-all -p watch-css start-js",
47 | "build": "yarn build-css && craco build",
48 | "test": "craco test",
49 | "postinstall": "patch-package"
50 | },
51 | "eslintConfig": {
52 | "extends": "react-app"
53 | },
54 | "browserslist": {
55 | "production": [
56 | ">0.2%",
57 | "not dead",
58 | "not op_mini all"
59 | ],
60 | "development": [
61 | "last 1 chrome version",
62 | "last 1 firefox version",
63 | "last 1 safari version"
64 | ]
65 | },
66 | "devDependencies": {
67 | "@craco/craco": "^5.3.0",
68 | "fancy-log": "^1.3.3",
69 | "gulp": "^4.0.2",
70 | "gulp-cloudfront-invalidate": "^0.1.5",
71 | "gulp-s3-upload": "^1.7.3",
72 | "node-sass-chokidar": "^1.3.5",
73 | "npm-run-all": "^4.1.5",
74 | "patch-package": "^6.1.4",
75 | "postinstall-postinstall": "^2.0.0"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/patches/web3+0.20.7.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/web3/lib/utils/config.js b/node_modules/web3/lib/utils/config.js
2 | index 5c16262..984e760 100644
3 | --- a/node_modules/web3/lib/utils/config.js
4 | +++ b/node_modules/web3/lib/utils/config.js
5 | @@ -72,7 +72,7 @@ module.exports = {
6 | ETH_SIGNATURE_LENGTH: 4,
7 | ETH_UNITS: ETH_UNITS,
8 | ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },
9 | - ETH_POLLING_TIMEOUT: 1000/2,
10 | + ETH_POLLING_TIMEOUT: 10000,
11 | defaultBlock: 'latest',
12 | defaultAccount: undefined
13 | };
14 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CDP Portal
7 |
8 |
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 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "CDP Portal",
3 | "name": "CDP Portal",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "./android-chrome-192x192.png",
12 | "sizes": "192x192",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "./android-chrome-512x512.png",
17 | "sizes": "512x512",
18 | "type": "image/png"
19 | }
20 | ],
21 | "start_url": "./index.html",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#202930"
25 | }
26 |
--------------------------------------------------------------------------------
/public/static/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/static/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/static/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/static/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/static/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/static/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/static/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/public/static/dai-400px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/static/dai-400px.png
--------------------------------------------------------------------------------
/public/static/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/static/favicon-16x16.png
--------------------------------------------------------------------------------
/public/static/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/static/favicon-32x32.png
--------------------------------------------------------------------------------
/public/static/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/static/mstile-150x150.png
--------------------------------------------------------------------------------
/public/static/og-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/public/static/og-image.png
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render( , div);
8 | });
9 |
--------------------------------------------------------------------------------
/src/abi/proxyregistry.json:
--------------------------------------------------------------------------------
1 | {
2 | "abi": [{"constant":false,"inputs":[],"name":"build","outputs":[{"name":"proxy","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"proxies","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"address"}],"name":"build","outputs":[{"name":"proxy","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"factory_","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}],
3 | "bytecode": ""
4 | }
--------------------------------------------------------------------------------
/src/abi/saiProxyCreateAndExecute.json:
--------------------------------------------------------------------------------
1 | {
2 | "abi": [{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"wad","type":"uint256"}],"name":"draw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"jam","type":"uint256"},{"name":"wad","type":"uint256"},{"name":"otc_","type":"address"}],"name":"wipeAndFree","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"wad","type":"uint256"}],"name":"lockAndDraw","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"wad","type":"uint256"}],"name":"lockAndDraw","outputs":[{"name":"cup","type":"bytes32"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"registry_","type":"address"},{"name":"tub_","type":"address"}],"name":"createAndOpen","outputs":[{"name":"proxy","type":"address"},{"name":"cup","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"otc_","type":"address"}],"name":"shut","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"wad","type":"uint256"},{"name":"otc_","type":"address"}],"name":"wipe","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"wad","type":"uint256"}],"name":"wipe","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"}],"name":"open","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"}],"name":"shut","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"}],"name":"lock","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"registry_","type":"address"},{"name":"tub_","type":"address"},{"name":"wad","type":"uint256"}],"name":"createOpenLockAndDraw","outputs":[{"name":"proxy","type":"address"},{"name":"cup","type":"bytes32"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"lad","type":"address"}],"name":"give","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"registry_","type":"address"},{"name":"tub_","type":"address"}],"name":"createOpenAndLock","outputs":[{"name":"proxy","type":"address"},{"name":"cup","type":"bytes32"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"jam","type":"uint256"}],"name":"free","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tub_","type":"address"},{"name":"cup","type":"bytes32"},{"name":"jam","type":"uint256"},{"name":"wad","type":"uint256"}],"name":"wipeAndFree","outputs":[],"payable":true,"stateMutability":"payable","type":"function"}],
3 | "bytecode": ""
4 | }
--------------------------------------------------------------------------------
/src/abi/saivaluesaggregator.json:
--------------------------------------------------------------------------------
1 | {
2 | "abi": [{"constant":true,"inputs":[],"name":"sin","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"skr","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"gov","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tub","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"cup","type":"bytes32"}],"name":"aggregateCDPValues","outputs":[{"name":"blockNumber","type":"uint256"},{"name":"lad","type":"address"},{"name":"safe","type":"bool"},{"name":"r","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"vox","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"gem","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"sai","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"addr","type":"address"},{"name":"proxy","type":"address"}],"name":"aggregateValues","outputs":[{"name":"blockNumber","type":"uint256"},{"name":"pipVal","type":"bytes32"},{"name":"pipSet","type":"bool"},{"name":"pepVal","type":"bytes32"},{"name":"pepSet","type":"bool"},{"name":"sStatus","type":"bool[]"},{"name":"sValues","type":"uint256[]"},{"name":"tValues","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"proxyRegistry","type":"address"},{"name":"addr","type":"address"}],"name":"getContractsAddrs","outputs":[{"name":"blockNumber","type":"uint256"},{"name":"saiContracts","type":"address[]"},{"name":"proxy","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pep","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pip","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pit","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tap","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"top","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_top","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}],
3 | "bytecode": ""
4 | }
5 |
--------------------------------------------------------------------------------
/src/assets/fonts/slick.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/fonts/slick.eot
--------------------------------------------------------------------------------
/src/assets/fonts/slick.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Generated by Fontastic.me
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/assets/fonts/slick.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/fonts/slick.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/slick.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/fonts/slick.woff
--------------------------------------------------------------------------------
/src/assets/images/cdp-created-icon-1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/cdp-created-icon-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
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 |
--------------------------------------------------------------------------------
/src/assets/images/cdp-created.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/cdp-creating-1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/cdp-creating-2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/cdp-creating-3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/cdp-creating-6.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/history-icon-borrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Icon Borrow
5 | Created with Sketch.
6 |
7 |
8 |
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 |
--------------------------------------------------------------------------------
/src/assets/images/history-icon-unknown.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Icon Unknown
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/assets/images/icon-arrow-right.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/icon-check.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/icon-clock.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/icon-close-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/icon-close.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/icon-help.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
17 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/icon-home.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
9 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/icon-settings.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
22 |
23 |
--------------------------------------------------------------------------------
/src/assets/images/icon-stop.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/assets/images/icon-warning.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/ledger-nano-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/images/ledger-nano-logo.png
--------------------------------------------------------------------------------
/src/assets/images/maker-logo-footer.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/menu-icon-ledger.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/menu-icon-trezor.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/menu-icon-web.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | menu-icon-web
5 | Created with Sketch.
6 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/src/assets/images/parity-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/images/parity-logo.png
--------------------------------------------------------------------------------
/src/assets/images/send-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/images/send-icon.png
--------------------------------------------------------------------------------
/src/assets/images/slick-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/images/slick-loader.gif
--------------------------------------------------------------------------------
/src/assets/images/trezor-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/images/trezor-logo.png
--------------------------------------------------------------------------------
/src/assets/images/wallet-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makerdao/scd-cdp-portal/3a54112a0d5ea5a96680182dbabf088792b84176/src/assets/images/wallet-icon.png
--------------------------------------------------------------------------------
/src/components/App.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {observer, Provider} from "mobx-react";
4 | import {BrowserRouter} from "react-router-dom";
5 | import ReactGA from 'react-ga';
6 |
7 | // Components
8 | import Modal from "./Modal";
9 | import Notify from "./Notify";
10 | import NotifySetUp from "./NotifySetUp";
11 | import PriceModal from "./PriceModal";
12 | import Routes from "./Routes";
13 |
14 | // Stores
15 | import rootStore from "../stores/Root";
16 |
17 | // Utils
18 | import * as blockchain from "../utils/blockchain";
19 | import { gaInit, mixpanelInit } from '../utils/analytics';
20 |
21 | // Styles
22 | import "../scss/styles.css";
23 |
24 | // Convenient console access
25 | window.blockchain = blockchain;
26 | window.dialog = rootStore.dialog;
27 | window.network = rootStore.network;
28 | window.profile = rootStore.profile;
29 | window.system = rootStore.system;
30 | window.transactions = rootStore.transactions;
31 | window.content = rootStore.content;
32 |
33 | // Analytics
34 | mixpanelInit();
35 | gaInit();
36 | ReactGA.pageview(window.location.pathname + window.location.search);
37 |
38 | @observer
39 | class App extends React.Component {
40 | render() {
41 | return (
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | )
55 | }
56 | }
57 |
58 | export default App;
59 |
--------------------------------------------------------------------------------
/src/components/Dashboard.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 | import checkIsMobile from "ismobilejs";
5 |
6 | // Components
7 | import Cup from "./Cup";
8 | import LegacyCupsAlert from "./LegacyCupsAlert";
9 | import CupMobile from "./CupMobile";
10 |
11 | @inject("system")
12 | @observer
13 | class Dashboard extends React.Component {
14 | render() {
15 | const cupId = this.props.system.tub.cupId ? this.props.system.tub.cupId : Object.keys(this.props.system.tub.cups)[0];
16 | return (
17 |
18 |
19 | {
20 | checkIsMobile.any
21 | ?
22 | :
23 | }
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Dashboard;
30 |
--------------------------------------------------------------------------------
/src/components/DropdownMenu.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 |
4 | export function MenuItems(props) {
5 | return (
6 |
7 | { props.children }
8 |
9 | );
10 | }
11 |
12 | export function MenuItem(props) {
13 | return (
14 |
15 | {
16 | props.iconsvg ? props.iconsvg : props.icon &&
17 | }
18 | { props.text }
19 |
20 | );
21 | }
22 |
23 | export function MenuFooter(props) {
24 | return (
25 |
26 | { props.children }
27 |
28 | );
29 | }
30 |
31 | export class DropdownMenu extends React.Component {
32 | render() {
33 | return (
34 |
35 |
36 |
37 |
38 | { this.props.children }
39 |
40 |
41 | )
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/Footer.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {Link} from "react-router-dom";
4 |
5 | // Images
6 | import makerLogoFooter from "images/maker-logo-footer.svg";
7 |
8 | class Footer extends React.Component {
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 |
Maker
16 |
17 |
18 | The Sai Credit System was developed by Maker .
19 | Our team consists of developers, economists and designers from all over the world. Our decentralized autonomous organization is governed by our token holders.
20 |
21 |
26 |
27 |
28 | )
29 | }
30 | }
31 |
32 | export default Footer;
33 |
--------------------------------------------------------------------------------
/src/components/GeneralNotifications.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from 'react';
3 | import { inject, observer } from 'mobx-react';
4 |
5 | // Components
6 | import InlineNotification from './InlineNotification';
7 | import StabilityFeeAlert from './StabilityFeeAlert';
8 |
9 | @inject('content')
10 | @inject('network')
11 | @observer
12 | class GeneralNotifications extends React.Component {
13 | render() {
14 | return (
15 | (this.props.network.isConnected || this.props.network.defaultAccount) &&
16 | (this.props.content.shouldShowGeneralNotifications() || this.props.content.shouldShowStabilityFeeAlert()) && (
17 |
18 | {this.props.content.shouldShowGeneralNotifications() &&
19 | Object.entries(this.props.content.getGeneralNotifications()).map(
20 | ([key, notification]) =>
21 | notification.show && (
22 | this.props.content.hideGeneralNotification(key)}
26 | />
27 | )
28 | )}
29 |
30 |
31 | )
32 | );
33 | }
34 | }
35 |
36 | export default GeneralNotifications;
37 |
--------------------------------------------------------------------------------
/src/components/Help.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {Link} from "react-router-dom";
4 | import DocumentTitle from "react-document-title";
5 | import checkIsMobile from "ismobilejs";
6 |
7 | // Components
8 | import Menu from "./Menu";
9 |
10 | class Help extends React.Component {
11 | columnFormatting = () => {
12 | return checkIsMobile.any
13 | ? "col col-extra-padding"
14 | : "col col-2 col-extra-padding";
15 | }
16 |
17 | columnStyle = () => {
18 | return checkIsMobile.any
19 | ? { marginTop: "-120px" }
20 | : { paddingLeft: "2.5em" }
21 | }
22 |
23 | render() {
24 | return (
25 |
26 |
27 |
28 | {
29 |
30 | }
31 |
32 |
33 |
36 |
37 |
38 |
FAQ
39 |
First steps
40 |
41 | What is a Collateralized Debt Position (CDP)?
42 | What is the best way to lower my risk of liquidation?
43 | What is the Stability Fee?
44 | When do I have to pay the Stability Fee?
45 | What is PETH?
46 | How do I get MKR tokens?
47 |
48 |
49 |
50 |
51 |
Most asked questions
52 |
53 | How does the avatar work?
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | )
63 | }
64 | }
65 |
66 | export default Help;
67 |
--------------------------------------------------------------------------------
/src/components/HelpItem.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 | import {Link} from "react-router-dom";
5 | import Markdown from "markdown-to-jsx";
6 | import DocumentTitle from "react-document-title";
7 |
8 | // Components
9 | import Menu from "./Menu";
10 | import NotFound from "./NotFound";
11 |
12 | @inject("content")
13 | @observer
14 | class HelpItem extends React.Component {
15 | render() {
16 | const helpId = this.props.match.params.helpId || null;
17 | const helpItem = this.props.content.getHelpItem(helpId);
18 | if (!helpId || (this.props.content.contentLoaded && !helpItem)) return ;
19 |
20 | return (
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
FAQ{ helpItem ? helpItem.title : "Loading..." }
33 |
34 | {
35 | this.props.content.contentLoaded &&
36 |
37 | }
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | )
47 | }
48 | }
49 |
50 | export default HelpItem;
51 |
--------------------------------------------------------------------------------
/src/components/InlineNotification.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 |
4 | const icon = (
5 |
6 |
7 |
8 | );
9 |
10 | class InlineNotification extends React.Component {
11 | render() {
12 | return (
13 |
14 | {
15 | //this.props.onCloseButtonClick &&
16 | //
{ e.preventDefault(); this.props.onCloseButtonClick() } } className="close-button" width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
17 | //
18 | //
19 | }
20 | { this.props.caption && icon }
21 | {
22 | this.props.caption &&
23 |
24 | { this.props.caption }
25 |
26 | }
27 | { !this.props.caption && icon }
28 |
29 | { this.props.message || this.props.children }
30 | {
31 | this.props.onButtonClick && { this.props.buttonText || "OK" }
32 | }
33 |
34 |
35 |
36 | )
37 | }
38 | }
39 |
40 | export default InlineNotification;
41 |
--------------------------------------------------------------------------------
/src/components/LegacyCupsAlert.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 |
5 | // Components
6 | import InlineNotification from "./InlineNotification";
7 |
8 | @inject("network")
9 | @inject("system")
10 | @observer
11 | class LegacyCupsAlert extends React.Component {
12 | constructor(props){
13 | super(props);
14 | this.state = { show: true }
15 | }
16 |
17 | render() {
18 | return (
19 | this.props.system.showLegacyAlert && this.state.show && !localStorage.getItem(`LegacyCDPsAlertClosed-${this.props.network.defaultAccount}`) &&
20 | { localStorage.setItem(`LegacyCDPsAlertClosed-${this.props.network.defaultAccount}`, true); this.setState({show: false}); } }
26 | onButtonClick={ () => this.props.setOpenMigrate(true) }
27 | />
28 | )
29 | }
30 | }
31 |
32 | export default LegacyCupsAlert;
33 |
--------------------------------------------------------------------------------
/src/components/LoadingSpinner.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 |
4 | class LoadingSpinner extends React.Component {
5 | render() {
6 | return (
7 |
14 | )
15 | }
16 | }
17 |
18 | export default LoadingSpinner;
19 |
--------------------------------------------------------------------------------
/src/components/McdAlert.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import { observer } from "mobx-react";
4 |
5 | // Components
6 | import InlineNotification from "./InlineNotification";
7 |
8 | @observer
9 | class McdAlert extends React.Component {
10 | constructor(props){
11 | super(props);
12 | this.state = { show: true }
13 | }
14 |
15 | render() {
16 | return (
17 | this.state.show &&
18 | { localStorage.setItem('ScdAlertClosed', true); this.setState({show: false}); } }
23 | onButtonClick={ () => window.open("https://migrate.makerdao.com", "_blank") }
24 | >
25 | Single Collateral Dai (SCD) was shutdown at 16:00 UTC on Tuesday, May 12, 2020. From now on,
26 | it will only be possible to redeem Sai and CDPs from the official MakerDAO Migration Portal
27 | at migrate.makerdao.com .
28 |
29 | )
30 | }
31 | }
32 |
33 | export default McdAlert;
34 |
--------------------------------------------------------------------------------
/src/components/Modal.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {observer} from "mobx-react";
4 |
5 | @observer
6 | class Modal extends React.Component {
7 | constructor() {
8 | super();
9 | this.handleKeyDown = this.handleKeyDown.bind(this);
10 | }
11 | componentWillMount() {
12 | window.addEventListener("keydown", this.handleKeyDown.bind(this));
13 | }
14 | componentWillUnmount() {
15 | window.removeEventListener("keydown", this.handleKeyDown.bind(this));
16 | }
17 | handleKeyDown(event) {
18 | if (event.keyCode === 27) this.props.close();
19 | }
20 | handleInnerClick(e) {
21 | e.stopPropagation();
22 | }
23 | render() {
24 | return (
25 |
26 | {
27 | this.props.show &&
28 |
29 |
30 | { this.props.children }
31 |
32 |
33 | }
34 |
35 | )
36 | }
37 | }
38 |
39 | export default Modal;
40 |
--------------------------------------------------------------------------------
/src/components/NewCupMobile.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React, {Component} from "react";
3 | import {inject, observer} from "mobx-react";
4 | import mixpanel from 'mixpanel-browser';
5 |
6 | // Components
7 | import InlineNotification from "./InlineNotification";
8 |
9 | //Utils
10 | import {printNumber, formatAmount} from "../utils/helpers";
11 | import CupInfoMobile from "./CupInfoMobile";
12 |
13 | @inject("system")
14 | @observer
15 | class NewCupMobile extends Component {
16 | usdValue = eth => {
17 | const ethPrice = this.props.system.pip.val / 1000000000000000000;
18 | return eth * ethPrice;
19 | }
20 |
21 | render() {
22 | const {
23 | checkValues,
24 | daiText,
25 | error,
26 | dai,
27 | eth,
28 | ethText,
29 | liqPrice,
30 | maxDaiAvail,
31 | ratio,
32 | submitEnabled,
33 | warning
34 | } = this.props.newCupProps;
35 |
36 | return (
37 |
38 |
39 |
40 |
How much ETH would you like to collateralize?
41 |
42 |
this.eth = input } type="number" id="inputETH" className="number-input" required step="0.000000000000000001" placeholder="0.000" value={ ethText } onChange={ e => { checkValues("eth", e.target.value) } } onKeyDown={ e => { if (e.keyCode === 38 || e.keyCode === 40 || e.keyCode === 189) e.preventDefault() } } style={{marginBottom: "5px"}} />
43 |
ETH
44 |
45 | Worth ${ printNumber(this.usdValue(eth)) }
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
How much SAI would you like to generate?
54 |
55 |
this.dai = input } type="number" id="inputDAI" className="number-input" required step="0.000000000000000001" placeholder="0.000" value={ daiText } style={{marginBottom: "5px"}} onChange={ e => { checkValues("dai", e.target.value) } } onKeyDown={ e => { if (e.keyCode === 38 || e.keyCode === 40 || e.keyCode === 189) e.preventDefault() } } />
56 |
DAI
57 | {
58 | maxDaiAvail &&
59 |
Max SAI available to generate: { printNumber(maxDaiAvail) } SAI
60 | }
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | { warning &&
}
69 | { error &&
}
70 |
71 |
72 |
73 |
74 | mixpanel.track('btn-click', { id: 'collateralize-generate', mobile: true, product: 'scd-cdp-portal', collateral: formatAmount(eth), debt: formatAmount(dai) })} type="submit" disabled={ !submitEnabled }>continue
75 |
76 |
77 |
78 | );
79 | }
80 | }
81 |
82 | export default NewCupMobile;
83 |
--------------------------------------------------------------------------------
/src/components/NotFound.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 |
4 | // Images
5 | import image404 from "images/404.svg";
6 |
7 | class NotFound extends React.Component {
8 | render() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
Page not found – Error 404
22 |
You spotted a black hole.
23 |
Don’t go too close – it sucks up pages and contents.
24 |
25 |
26 |
27 |
28 |
29 |
30 |
We are confident you will find what you were looking for on the main page.
31 |
{ window.location = '/'; }}>GO TO MAIN PAGE
32 |
33 |
34 |
35 | )
36 | }
37 | }
38 |
39 | export default NotFound;
40 |
--------------------------------------------------------------------------------
/src/components/Notify.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 |
5 | class Item extends React.Component {
6 | displayName = "Item";
7 |
8 | hideNotification = () => {
9 | this.props.hideNotification(this.props.id);
10 | }
11 |
12 | render() {
13 | return (
14 | React.createElement("div", { className: "col " + this.props.classNames.join(" ") },
15 | React.createElement("button", { className: "close-box" , onClick: this.hideNotification}),
16 | React.createElement("h3", { className: "notification-headline" }, this.props.title),
17 | React.createElement("div", { className: "" }, this.props.msg)
18 | )
19 | )
20 | }
21 | };
22 |
23 | @inject("network")
24 | @inject("transactions")
25 | @observer
26 | class Notify extends React.Component {
27 | displayName = "Notify";
28 | key = 0;
29 |
30 | constructor() {
31 | super();
32 | this.state = {}
33 | }
34 |
35 | componentDidMount = () => {
36 | this.props.transactions.notificator = this.props.network.notificator = this;
37 | }
38 |
39 | getInitialState = () => {
40 | return {};
41 | }
42 |
43 | success = (key, title, msg, time, onClose = () => null) => {
44 | this.addNotify(key, title, msg, time, ["nf-success"], onClose);
45 | }
46 |
47 | error = (key, title, msg, time, onClose = () => null) => {
48 | this.addNotify(key, title, msg, time, ["nf-error"], onClose);
49 | }
50 |
51 | info = (key, title, msg, time, onClose = () => null) => {
52 | this.addNotify(key, title, msg, time, ["nf-info"], onClose);
53 | }
54 |
55 | notice = (key, title, msg, time, onClose = () => null) => {
56 | this.addNotify(key, title, msg, time, ["nf-notice", "bright-style"], onClose);
57 | }
58 |
59 | addNotify = (key, title, msg, time, classNames, onClose = () => null) => {
60 | const state = {...this.state}
61 | state[key] = { title, msg, time, classNames, onClose };
62 | this.setState(state);
63 | this.countToHide(time, key);
64 | }
65 |
66 | countToHide = (duration, key) => {
67 | if (duration) {
68 | var that = this;
69 | setTimeout(function () {
70 | that.hideNotification(key);
71 | }, duration);
72 | }
73 | }
74 |
75 | hideNotification = key => {
76 | if (this.state[key]) {
77 | this.state[key].onClose();
78 | }
79 | delete this.state[key];
80 | this.setState(this.state);
81 | }
82 |
83 | render = () => {
84 | var keys = Object.keys(this.state);
85 | var state = this.state;
86 | var hide = this.hideNotification;
87 | var el = keys.map(function (key) {
88 | return React.createElement(Item, {
89 | id: key,
90 | key: key,
91 | classNames: state[key].classNames,
92 | hideNotification: hide,
93 | title: state[key].title,
94 | msg: state[key].msg
95 | }
96 | )
97 | });
98 | return (React.createElement("div", { className: "notifications-container" }, el));
99 | }
100 | };
101 |
102 | export default Notify;
103 |
--------------------------------------------------------------------------------
/src/components/NotifySetUp.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 |
5 | // Utils
6 | import {etherscanTx} from "../utils/helpers";
7 |
8 | // Images
9 | import cdpCreated from "images/cdp-created.svg";
10 | import cdpCreatedIcon1 from "images/cdp-created-icon-1.svg";
11 | import cdpCreatedIcon2 from "images/cdp-created-icon-2.svg";
12 | import cdpCreatedIcon3 from "images/cdp-created-icon-3.svg";
13 |
14 | import cdpCreating1 from "images/cdp-creating-1.svg";
15 | import cdpCreating2 from "images/cdp-creating-2.svg";
16 | import cdpCreating3 from "images/cdp-creating-3.svg";
17 | import cdpCreating4 from "images/cdp-creating-4.svg";
18 | import cdpCreating5 from "images/cdp-creating-5.svg";
19 | import cdpCreating6 from "images/cdp-creating-6.svg";
20 |
21 | const cdpCreatingAnimation = [cdpCreating1, cdpCreating2, cdpCreating3, cdpCreating4, cdpCreating5, cdpCreating6];
22 |
23 | class CreatingCDPAnimation extends React.Component {
24 | constructor(props){
25 | super(props);
26 | this.state = { currentCount: 1 }
27 | }
28 | timer() {
29 | this.setState({
30 | currentCount: this.state.currentCount === 6 ? 1 : this.state.currentCount + 1
31 | })
32 | }
33 | componentDidMount() {
34 | this.intervalId = setInterval(this.timer.bind(this), 2000);
35 | }
36 | componentWillUnmount() {
37 | clearInterval(this.intervalId);
38 | }
39 | render() {
40 | return(
41 |
42 |
43 |
44 | );
45 | }
46 | }
47 |
48 | @inject("transactions")
49 | @inject("system")
50 | @inject("network")
51 | @observer
52 | class NotifySetUp extends React.Component {
53 | render() {
54 | const txs = Object.keys(this.props.transactions.registry).filter(tx => this.props.transactions.registry[tx].cdpCreationTx);
55 | const txHash = txs[0] || null;
56 |
57 | return (
58 | this.props.transactions.showCreatingCdpModal &&
59 |
60 |
61 | {
62 | this.props.transactions.registry[txs[0]].pending || Object.keys(this.props.system.tub.cups).length === 0
63 | ?
64 |
65 | Creating your CDP
66 |
67 |
68 | {
69 | txHash
70 | ?
71 | etherscanTx(this.props.network.network, "View transaction", txHash)
72 | :
73 | "Creating your new CDP..."
74 | }
75 |
76 |
77 | :
78 |
79 | Congratulations on your new CDP
80 |
81 |
82 | Welcome to the CDP Portal where you can view and manage your collateral and debt position on a decentralized system.
83 |
84 |
85 |
86 |
87 | Check current collateral to debt position
88 |
89 |
90 |
91 | Deposit or withdraw collateral
92 |
93 |
94 |
95 | Generate or pay back SAI
96 |
97 |
98 |
99 | this.props.transactions.cleanCdpCreationProperty(txs[0]) } style={ {width: "13rem"} }>OK
100 |
101 |
102 | }
103 |
104 |
105 | )
106 | }
107 | }
108 |
109 | export default NotifySetUp;
110 |
--------------------------------------------------------------------------------
/src/components/OasisAlert.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import { observer } from "mobx-react";
4 |
5 | // Components
6 | import InlineNotification from "./InlineNotification";
7 |
8 | @observer
9 | class OasisAlert extends React.Component {
10 | constructor(props){
11 | super(props);
12 | this.state = { show: true }
13 | }
14 |
15 | render() {
16 | return (
17 | this.state.show &&
18 | { localStorage.setItem('OasisAlertClosed', true); this.setState({show: false}); } }
23 | onButtonClick={ () => window.open("https://oasis.app/borrow", "_blank") }
24 | >
25 | New Multi Collateral Dai (MCD) Vaults can be created from the Oasis App
26 | at oasis.app . For more information please visit
27 | our Forum at forum.makerdao.com or
28 | our Chat at chat.makerdao.com .
29 |
30 | )
31 | }
32 | }
33 |
34 | export default OasisAlert;
35 |
--------------------------------------------------------------------------------
/src/components/PriceModal.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 | import Slider from "react-rangeslider";
5 |
6 | import "react-rangeslider/lib/index.css";
7 |
8 | @inject("transactions")
9 | @observer
10 | class PriceModal extends React.Component {
11 | constructor (props, context) {
12 | super(props, context);
13 | this.state = {
14 | gasPrice: props.transactions.standardGasPrice,
15 | timeEstimate: this.estimateTxTime(props.transactions.standardGasPrice)
16 | };
17 | this.stdGasPrice = props.transactions.standardGasPrice;
18 | }
19 |
20 | setPriceAndSend = e => {
21 | e.preventDefault();
22 | this.props.transactions.setPriceAndSend(this.state.gasPrice);
23 | };
24 |
25 | // TODO: Use an external source to estimate tx time
26 | estimateTxTime = gasPrice => {
27 | return Math.round((99 - gasPrice) / 2) + " mins";
28 | };
29 |
30 | handleChange = value => {
31 | this.setState({
32 | gasPrice: value,
33 | timeEstimate: this.estimateTxTime(value)
34 | });
35 | };
36 |
37 | render() {
38 | const { gasPrice } = this.state;
39 | return (
40 |
41 | Set your gas price
42 | Gas is used to pay for transactions. A higher gas price results in faster confirmation times.
43 | { gasPrice } Gwei { gasPrice === this.stdGasPrice ? " (Standard)" : "" }
44 | {/* ~{ this.state.timeEstimate }
*/}
45 |
64 |
65 | )
66 | }
67 | }
68 |
69 | export default PriceModal;
70 |
--------------------------------------------------------------------------------
/src/components/Routes.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {observer} from "mobx-react";
4 | import {Route, Switch, withRouter} from "react-router-dom";
5 | import ReactGA from 'react-ga';
6 | import mixpanel from 'mixpanel-browser';
7 |
8 | // Components
9 | import Help from "./Help";
10 | import HelpItem from "./HelpItem";
11 | import Home from "./Home";
12 | import NotFound from "./NotFound";
13 | import Terms from "./Terms";
14 |
15 | @withRouter
16 | @observer
17 | class Routes extends React.Component {
18 | componentDidUpdate = prevProps => {
19 | if (this.props.location.pathname !== prevProps.location.pathname) {
20 | window.scrollTo(0, 0);
21 | }
22 | console.debug(`[Analytics] Tracked: ${this.props.location.pathname}`);
23 | ReactGA.pageview(this.props.location.pathname);
24 | mixpanel.track('Pageview', { product: 'scd-cdp-portal' });
25 | }
26 |
27 | render() {
28 | return (
29 |
30 |
31 |
32 | } />
33 |
34 |
35 |
36 | )
37 | }
38 | }
39 |
40 | export default Routes;
41 |
--------------------------------------------------------------------------------
/src/components/StabilityFeeAlert.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 |
5 | // Components
6 | import InlineNotification from "./InlineNotification";
7 |
8 | @inject("content")
9 | @inject("network")
10 | @observer
11 | class StabilityFeeAlert extends React.Component {
12 | render() {
13 | return (
14 | this.props.content.shouldShowStabilityFeeAlert() &&
15 | (this.props.network.isConnected ||
16 | this.props.network.defaultAccount) &&
17 | this.props.content.hideStabilityFeeContent()}
20 | />
21 | )
22 | }
23 | }
24 |
25 | export default StabilityFeeAlert;
26 |
--------------------------------------------------------------------------------
/src/components/SystemInfo.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 |
5 | // Utils
6 | import {printNumber, wdiv, wmul, capitalize} from "../utils/helpers";
7 |
8 | @inject("network")
9 | @inject("system")
10 | @observer
11 | class SystemInfo extends React.Component {
12 | render() {
13 | return (
14 |
15 |
16 |
{ this.props.network.network === "main" ? "Main Ethereum" : capitalize(this.props.network.network) + " Test" } Network
17 |
18 |
19 |
20 |
Price Info
21 |
ETH/USD
22 |
23 | {
24 | this.props.system.pip.val && this.props.system.pip.val.gt(0)
25 | ?
26 | { printNumber(this.props.system.pip.val) } USD
27 | :
28 | Loading...
29 | }
30 |
31 |
PETH/ETH
32 |
33 | {
34 | this.props.system.tub.per.gte(0)
35 | ?
36 | { printNumber(this.props.system.tub.per) } ETH
37 | :
38 | Loading...
39 | }
40 |
41 |
SAI/USD
42 |
43 | {
44 | this.props.system.vox.par.gte(0)
45 | ?
46 | { printNumber(this.props.system.vox.par) } USD
47 | :
48 | Loading...
49 | }
50 |
51 |
MKR/USD
52 |
53 | {
54 | this.props.system.pep.val && this.props.system.pep.val.gt(0)
55 | ?
56 | { printNumber(this.props.system.pep.val) } USD
57 | :
58 | Loading...
59 | }
60 |
61 |
62 |
63 |
64 |
Global CDP Info
65 |
Global CDP Collateralization
66 |
67 | {
68 | this.props.system.gem.tubBalance.gte(0) && this.props.system.pip.val.gte(0) && this.props.system.dai.totalSupply.gte(0) && this.props.system.vox.par.gte(0)
69 | ?
70 |
71 | {
72 | printNumber(
73 | this.props.system.dai.totalSupply.eq(0)
74 | ? 0
75 | : wdiv(wmul(this.props.system.gem.tubBalance, this.props.system.pip.val), wmul(this.props.system.dai.totalSupply, this.props.system.vox.par)).times(100)
76 | )
77 | }
78 | %
79 |
80 | :
81 | "Loading..."
82 | }
83 |
84 |
Maximum Global SAI Available
85 |
86 | {
87 | this.props.system.dai.totalSupply && this.props.system.dai.totalSupply.gt(0)
88 | ?
89 | { printNumber(this.props.system.dai.totalSupply) } $
90 | :
91 | Loading...
92 | }
93 |
94 | {
95 | this.props.network.network === "main" &&
96 |
97 | }
98 |
99 |
100 |
101 |
102 | )
103 | }
104 | }
105 |
106 | export default SystemInfo;
107 |
--------------------------------------------------------------------------------
/src/components/Terms.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 | import Markdown from "markdown-to-jsx";
5 | import DocumentTitle from "react-document-title";
6 |
7 | // Components
8 | import Menu from "./Menu";
9 |
10 | @inject("content")
11 | @observer
12 | class Terms extends React.Component {
13 | render() {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Terms;
30 |
--------------------------------------------------------------------------------
/src/components/ToggleSwitch.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import PropTypes from "prop-types";
3 | import React from "react";
4 |
5 | const tickIcon =
6 |
7 | const lockIcon =
8 |
9 | function ToggleSwitch({on, pending, onClick, onDisabledClick, enabled, className, children}) {
10 | const classes = ["switch", className, (on ? "on " : ""), (enabled ? "" : "disabled ")].join(" ");
11 | return (
12 | enabled ? onClick(e) : onDisabledClick(e)}>
13 |
14 | {
15 | on ?
16 | pending ?
: tickIcon
17 | :
18 | pending ?
: lockIcon
19 | }
20 |
21 |
22 | );
23 | }
24 |
25 | ToggleSwitch.propTypes = {
26 | on: PropTypes.bool.isRequired,
27 | onClick: PropTypes.func.isRequired,
28 | enabled: PropTypes.bool,
29 | className: PropTypes.string
30 | };
31 |
32 | ToggleSwitch.defaultProps = {
33 | enabled: true,
34 | className: "",
35 | onDisabledClick: () => {}
36 | };
37 |
38 | export default ToggleSwitch;
39 |
--------------------------------------------------------------------------------
/src/components/TooltipHint.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import ReactTooltip from "react-tooltip";
4 | import {inject, observer} from "mobx-react";
5 |
6 | @inject("content")
7 | @observer
8 | class TooltipHint extends React.Component {
9 | static rebuildTooltips() {
10 | ReactTooltip.rebuild();
11 | }
12 | render() {
13 | return (
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 | export default TooltipHint;
24 |
--------------------------------------------------------------------------------
/src/components/WalletClientDownload.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 | import walletIcons from './WalletIcons';
5 |
6 |
7 | @inject("network")
8 | @observer
9 | class WalletClientDownload extends React.Component {
10 | render() {
11 | return (
12 |
13 |
14 |
{ this.props.network.downloadClient = false } }>
15 |
16 |
17 |
18 |
19 |
Get a Wallet
20 |
21 |
36 |
37 | )
38 | }
39 | }
40 |
41 | export default WalletClientDownload;
42 |
--------------------------------------------------------------------------------
/src/components/WalletClientSelector.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 |
5 | // Utils
6 | import {getWebClientProviderName} from "../utils/blockchain";
7 | import walletIcons from "./WalletIcons";
8 |
9 | @inject("network")
10 | @observer
11 | class WalletClientSelector extends React.Component {
12 | render() {
13 | const providerName = getWebClientProviderName();
14 | return (
15 |
16 |
17 |
Connect a Wallet
18 |
19 |
51 |
52 | )
53 | }
54 | }
55 |
56 | export default WalletClientSelector;
57 |
--------------------------------------------------------------------------------
/src/components/WalletMobileClientDownload.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from 'react';
3 | import { inject, observer } from 'mobx-react';
4 | import walletIcons from './WalletIcons'
5 |
6 | @inject('network')
7 | @observer
8 | class WalletMobileClientDownload extends React.Component {
9 | render() {
10 | return (
11 |
12 |
13 |
{
16 | this.props.network.downloadClient = false;
17 | }}
18 | >
19 |
25 |
30 |
31 |
32 |
Get a Mobile Wallet
33 |
34 |
66 |
67 | );
68 | }
69 | }
70 |
71 | export default WalletMobileClientDownload;
72 |
--------------------------------------------------------------------------------
/src/components/WalletMobileConnect.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from 'react';
3 | import { inject } from 'mobx-react';
4 |
5 | @inject('network')
6 | class WalletMobileConnect extends React.Component {
7 | render() {
8 | return (
9 |
10 | {
14 | e.preventDefault();
15 | this.props.network.setWeb3WebClient();
16 | }}
17 | >
18 | CONNECT
19 |
20 |
21 | );
22 | }
23 | }
24 |
25 | export default WalletMobileConnect;
26 |
--------------------------------------------------------------------------------
/src/components/WalletNoAccount.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject} from "mobx-react";
4 |
5 | // Components
6 | import LoadingSpinner from "./LoadingSpinner";
7 |
8 | // Utils
9 | import {getCurrentProviderName} from "../utils/blockchain";
10 |
11 | @inject("network")
12 | class NoAccount extends React.Component {
13 | render() {
14 | return (
15 |
16 |
Log In to { this.props.formatClientName(getCurrentProviderName()) }
17 |
Please unlock your { this.props.formatClientName(getCurrentProviderName()) } account to continue.
18 |
19 |
20 | Cancel
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default NoAccount;
28 |
--------------------------------------------------------------------------------
/src/components/WalletSendToken.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 | import {inject, observer} from "mobx-react";
4 |
5 | // Utils
6 | import {printNumber, formatNumber, isAddress, toWei} from "../utils/helpers";
7 |
8 | @inject("profile")
9 | @inject("system")
10 | @observer
11 | class WalletSendToken extends React.Component {
12 | constructor() {
13 | super();
14 | this.state = {
15 | fieldErrors: {}
16 | }
17 | }
18 |
19 | setAmount = () => {
20 | this.amount.value = formatNumber(this.props.system[this.props.sendToken].myBalance, false);
21 | }
22 |
23 | transfer = e => {
24 | e.preventDefault();
25 | const token = this.props.sendToken;
26 | const amount = this.amount.value;
27 | const destination = this.destination.value;
28 | this.setState({ fieldErrors: {} });
29 |
30 | if (!destination || !isAddress(destination)) {
31 | this.setState({ fieldErrors: { address: "Please enter a valid address" } });
32 | } else if (!amount) {
33 | this.setState({ fieldErrors: { amount: "Please enter a valid amount" } });
34 | } else if (this.props.system[token].myBalance.lt(toWei(amount))) {
35 | this.setState({ fieldErrors: { amount: `Not enough balance to transfer ${amount} ${this.props.tokenName(token)}` } });
36 | } else {
37 | this.props.system.transferToken(token, destination, amount);
38 | this.amount.value = "";
39 | this.destination.value = "";
40 | this.props.closeSendBox();
41 | }
42 | }
43 |
44 | render() {
45 | return (
46 |
47 |
48 |
49 |
54 |
Send { this.props.tokenName(this.props.sendToken) }
55 |
56 |
81 |
82 |
83 | )
84 | }
85 | }
86 |
87 | export default WalletSendToken;
88 |
--------------------------------------------------------------------------------
/src/components/Welcome.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import React from "react";
3 |
4 | // Components
5 | import LegacyCupsAlert from "./LegacyCupsAlert";
6 |
7 | // Images
8 | import welcomeSatellite from "images/welcome-satellite.svg";
9 |
10 | // Utils
11 | import { mobileToggle } from "../utils/helpers";
12 |
13 | class Welcome extends React.Component {
14 | render() {
15 | return (
16 |
17 |
18 |
21 |
22 |
23 | You have no CDPs open at this time.
24 |
25 |
26 | { e.preventDefault(); this.props.setOpenCDPWizard() } }>Open CDP
27 |
28 |
29 |
30 |
31 |
32 |
33 | )
34 | }
35 | }
36 |
37 | export default Welcome;
38 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 |
4 | import App from "./components/App";
5 |
6 | ReactDOM.render((
7 |
8 | ), document.getElementById("root"));
9 |
--------------------------------------------------------------------------------
/src/scss/_breakpoints.scss:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | // BREAKPOINTS
5 | @mixin respond-to($breakpoint) {
6 | @if $breakpoint == "s" { // small size screens = iphones, smartphones, phablet
7 | @media only screen and (max-width: 480px) {
8 | @content;
9 | }
10 | }
11 | @if $breakpoint == "s+" { // small size screens 768px and under
12 | @media only screen and (max-width: 768px) {
13 | @content;
14 | }
15 | }
16 | @if $breakpoint == "m" { // medium size screens
17 | @media only screen and (max-width: 1024px) {
18 | @content;
19 | }
20 | }
21 | @if $breakpoint == "l" { // large size screens = ipad portrait, laptops and above
22 | @media only screen and (max-width: 1280px) {
23 | @content;
24 | }
25 | }
26 | // screen sizes in between 1281 and 1599 px are defined with no media queries
27 |
28 |
29 | @if $breakpoint == " *, .bright-style {
44 | color: $black;
45 | }
46 |
47 | // CSS Font Color Classes
48 | .typo-white { color: $white; }
49 | .typo-mid-grey { color: $mid-grey; }
50 | .typo-grid-grey { color: $grid-grey; }
51 |
52 | // Background CSS-Classes
53 | // border CSS-Classes
54 |
--------------------------------------------------------------------------------
/src/scss/_cp-cup-history.scss:
--------------------------------------------------------------------------------
1 | .cup-history-items {
2 | overflow: hidden;
3 | max-height: 0;
4 | min-height: 435px;
5 | transition: max-height 0.15s ease-out;
6 |
7 | &.expanded {
8 | max-height: 10000px;
9 | transition: max-height 0.25s ease-in;
10 | }
11 | }
12 |
13 | .history-cointainer {
14 | clear: both;
15 | margin-top: 35px;
16 | position: relative;
17 | .history-icon {
18 | float: left;
19 | height: 100px;
20 | width: 80px;
21 | img {
22 | position: absolute;
23 | display: block;
24 | width: auto;
25 | height: 48px;
26 | }
27 | .vertical-line {
28 | position: relative;
29 | width: 1px;
30 | height: calc(100% - 65px);
31 | left: 23px;
32 | top: 57px;
33 | border-left: 1px solid #313d47;
34 | }
35 | }
36 | .history-details {
37 | position: relative;
38 | top: 6px;
39 | @include respond-to(xl) {
40 | top: 2px;
41 | }
42 | line-height: 1.5;
43 | }
44 | .history-date {
45 | font-size: 0.85em;
46 | }
47 | .history-tx-links {
48 | margin-left: 10px;
49 | position: relative;
50 | top: -1px;
51 | .pipe-separator {
52 | font-size: 0.9em;
53 | padding: 0 1px;
54 | color: rgba(154, 163, 173, 0.65);
55 | }
56 | a {
57 | text-decoration: none;
58 | border-bottom: 1px solid rgba(154, 163, 173, 0.65);
59 | padding-bottom: 2px;
60 | position: relative;
61 | font-size: 0.85em;
62 | display: inline-block;
63 | line-height: 1;
64 | }
65 | }
66 | }
67 | .cup-history-items.hide-expander .history-cointainer:last-child .vertical-line {
68 | display: none;
69 | }
70 |
71 | .history-expand {
72 | clear: both;
73 | cursor: pointer;
74 | user-select: none;
75 | &.hide-expander {
76 | display: none;
77 | }
78 | .history-icon {
79 | float: left;
80 | height: 32px;
81 | width: 80px;
82 | svg {
83 | position: absolute;
84 | display: block;
85 | width: auto;
86 | height: 32px;
87 | margin-left: 7px;
88 | z-index: 1;
89 | }
90 | }
91 | &:hover .history-icon svg path {
92 | fill: #ced0d2;
93 | }
94 | .history-details {
95 | padding-top: 5px;
96 | @include respond-to(xl) {
97 | padding-top: 2px;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/scss/_cp-cup.scss:
--------------------------------------------------------------------------------
1 |
2 | h1.dashboard-headline span {
3 | color: rgba(154, 163, 173, 0.75);
4 | padding-left: 0.5rem;
5 | @include respond-to(s) {
6 | display: block;
7 | margin-top: 5px;
8 | padding-left: 0;
9 | }
10 | }
11 |
12 | .cup-top-right-buttons {
13 | float: right;
14 | height: 0;
15 | position: relative;
16 | top: -47px;
17 | @include respond-to(xl) {
18 | top: -58px;
19 | }
20 |
21 | a {
22 | display: inline-block;
23 | text-align: center;
24 | text-decoration: none;
25 | font-size: 0.8rem;
26 | margin-right: 1.5rem;
27 | &:last-child {
28 | margin-right: 0.5rem;
29 | }
30 | svg {
31 | width: 1.4rem;
32 | height: 1.4rem;
33 | path {
34 | stroke: #9aa3ad;
35 | transition: stroke .2s ease-in;
36 | }
37 | }
38 | &:hover svg path {
39 | stroke: #fff;
40 | }
41 | span {
42 | display: block;
43 | padding-top: 0.2rem;
44 | }
45 | }
46 | }
47 |
48 | .row.cup-price-information {
49 | .text-yellow {
50 | &, & * {
51 | color: #FBAE17;
52 | }
53 | }
54 | .text-red {
55 | &, & * {
56 | color: #C0392B;
57 | }
58 | }
59 | .strong-text {
60 | &, * {
61 | font-weight: 500;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/scss/_cp-dropdown-menu.scss:
--------------------------------------------------------------------------------
1 | // Dropdown menu
2 | .dropdown {
3 | position: relative;
4 | cursor: pointer;
5 | user-select: none;
6 | z-index: 1;
7 |
8 | // When dropdown-button becomes an SVG, use this to change 'fill' style on hover
9 | // .dropdown-button {
10 | // :hover > & {
11 | // }
12 | // }
13 |
14 | // Arrow
15 | svg.dropdown-arrow {
16 | display: none;
17 | position: absolute;
18 | right: -3px;
19 | bottom: -22px;
20 | }
21 | // Show arrow on hover
22 | &:hover svg.dropdown-arrow {
23 | display: block;
24 | }
25 | // Dropdown content (hidden by default)
26 | .dropdown-content {
27 | display: none;
28 | border-radius: 2px;
29 | right: -19px;
30 | // This padding allows the element to be up higher so that the mouse hover remains
31 | padding-top: 21px;
32 | top: 16px;
33 | overflow: hidden;
34 | box-shadow: 0 4px 12px 0 rgba(0,0,0,0.50);
35 | position: absolute;
36 | box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
37 |
38 | .dropdown-item-icon {
39 | float: left;
40 | width: 18px;
41 | height: 18px;
42 | }
43 | .dropdown-item:first-child {
44 | border-top-left-radius: 2px;
45 | border-top-right-radius: 2px;
46 | }
47 | .dropdown-item {
48 | color: black;
49 | font-size: 1.05rem;
50 | padding: 0.8rem 0 0.8rem 1.1rem;
51 | &:first-child {
52 | padding-top: 0.9rem;
53 | }
54 | &:last-child {
55 | padding-bottom: 0.9rem;
56 | }
57 | text-decoration: none;
58 | display: block;
59 | font-weight: 400;
60 | white-space: nowrap;
61 | &.has-icon {
62 | padding-right: 18px;
63 | }
64 | background-color: #d8d8d8;
65 | &:hover {
66 | background-color: #e1e1e1;
67 | }
68 | span {
69 | padding-right: 1.5rem;
70 | padding-left: 1.1rem;
71 | }
72 | }
73 | }
74 | // Show dropdown on hover
75 | &:hover .dropdown-content {
76 | display: block;
77 | }
78 | }
79 |
80 | // Implementation-specific styles
81 | .dropdown {
82 | float: right;
83 | width: 17px;
84 | height: 17px;
85 |
86 | img.dropdown-button {
87 | width: 17px;
88 | height: 17px;
89 | }
90 | .dropdown-footer {
91 | padding: 0;
92 | background-color: transparent;
93 | a {
94 | width: 50%;
95 | display: inline-block;
96 | background-color: #2D3337;
97 | &:hover {
98 | background-color: #4F565B;
99 | }
100 | padding-top: 0.8rem;
101 | padding-bottom: 0.8rem;
102 | text-align: center;
103 | font-size: 1rem;
104 | font-weight: 200;
105 | text-decoration: none;
106 | color: #fff;
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/scss/_cp-help.scss:
--------------------------------------------------------------------------------
1 | .help-page {
2 |
3 | .breadcrumbs {
4 | a.breadcrumb-root {
5 | font-size: 24px;
6 | line-height: 1.3;
7 | text-decoration: none;
8 | &::after {
9 | display: inline-block;
10 | content: '\00bb';
11 | margin: 0 .6em;
12 | color: rgba(154, 163, 173, 0.8);
13 | }
14 | }
15 | .breadcrumb-page {
16 | display: inline-block;
17 | font-size: 21px;
18 | line-height: 1.3;
19 | color: #bec4cc;
20 | }
21 | }
22 |
23 | .help-faq-item-markdown-container {
24 | margin-right: 3rem;
25 |
26 | span.help-faq-item-markdown, p.help-faq-item-markdown {
27 | display: block;
28 | max-width: 650px;
29 | font-size: 1.2rem;
30 | font-weight: 200;
31 | color: #9aa3ad;
32 | }
33 |
34 | .help-faq-item-markdown {
35 | padding: 1.5rem 0;
36 | font-size: 1.2rem;
37 |
38 | ul {
39 | list-style-type: disc;
40 | padding-left: 2.3rem;
41 | }
42 |
43 | & * {
44 | user-select: text !important;
45 | }
46 |
47 | h1 {
48 | letter-spacing: 0.1px;
49 | font-size: 1.4rem;
50 | line-height: 1.3;
51 | color: #fff;
52 | font-weight: 300;
53 | }
54 |
55 | h2 {
56 | font-size: 1.5rem;
57 | line-height: 1.3;
58 | margin-bottom: 1.8rem;
59 | font-weight: 200;
60 | color: #fff;
61 | letter-spacing: 0.02rem;
62 | margin-top: 4.5rem;
63 |
64 | &:first-of-type {
65 | margin-top: 3rem;
66 | }
67 | }
68 |
69 | h3 {
70 | font-size: 1.5rem;
71 | line-height: 1.3;
72 | margin-bottom: 1.5rem;
73 | margin-top: 3rem;
74 | font-weight: 200;
75 | color: #dedede;
76 | letter-spacing: 0.02rem;
77 | }
78 |
79 | h2 + h3 {
80 | margin-top: 2rem;
81 | }
82 |
83 | p {
84 | max-width: 650px;
85 | margin-top: 0;
86 | font-size: 1.2rem;
87 | font-weight: 200;
88 | color: #9aa3ad;
89 | }
90 |
91 | b, strong {
92 | color: #a2aab3;
93 | }
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/scss/_cp-inline-notification.scss:
--------------------------------------------------------------------------------
1 | .inline-notification {
2 | display: inline-block;
3 | position: relative;
4 | clear: both;
5 | background-color: $white-two;
6 | color: #26323a;
7 | padding: 1rem 1.3rem !important;
8 | margin: 2rem 0 1rem;
9 | border-radius: 2px;
10 | min-width: 250px;
11 | .caption {
12 | position: relative;
13 | font-size: 1.3rem;
14 | font-weight: 300;
15 | margin-bottom: 0.5rem;
16 | margin-left: 2.4rem;
17 | }
18 | .message {
19 | position: relative;
20 | font-size: 1.1rem;
21 | @include respond-to(xl) {
22 | font-size: 1rem;
23 | }
24 | font-weight: 200;
25 | &.has-button {
26 | padding-right: 13rem;
27 | @include respond-to('s+') {
28 | padding-right: 0;
29 | padding-bottom: 4rem;
30 | }
31 | }
32 | &.no-caption {
33 | margin-left: 2.7rem;
34 | @include respond-to(xl) {
35 | margin-left: 2.5rem;
36 | }
37 | }
38 | }
39 | button {
40 | min-width: 10rem;
41 | position: absolute;
42 | bottom: 0;
43 | right: 0;
44 | margin-bottom: 0;
45 | }
46 | // Close button
47 | svg.close-button {
48 | position: relative;
49 | float: right;
50 | cursor: pointer;
51 | overflow: hidden;
52 | width: 20px;
53 | height: 20px;
54 | z-index: 1;
55 | path + g {
56 | stroke: #2B3943;
57 | }
58 | &:hover path + g {
59 | stroke: lighten(#2B3943, 20%);
60 | }
61 | }
62 | // Icon
63 | svg.notification-icon {
64 | float: left;
65 | position: absolute;
66 | width: 21px;
67 | height: 19px;
68 | top: 1.1rem;
69 | @include respond-to(xl) {
70 | top: 1.2rem;
71 | }
72 | path {
73 | fill: #26323A;
74 | }
75 | }
76 | &.is-warning {
77 | svg.notification-icon path {
78 | fill: #202930;
79 | }
80 | & {
81 | background-color: #FBAE17;
82 | color: #2B3943;
83 | }
84 | }
85 | &.is-error {
86 | svg.notification-icon path {
87 | fill: $white;
88 | }
89 | & {
90 | background-color: #C0392B;
91 | color: $white;
92 | }
93 | }
94 | &.is-stability-fee-warning {
95 | border-radius: 5px;
96 | padding: unset !important;
97 | padding-left: 15px !important;
98 | padding-right: 15px !important;
99 | }
100 | }
101 |
102 | // General notifications
103 | .general-notifications .inline-notification {
104 | margin: 0.5rem 0 0.7rem;
105 | min-width: 100%;
106 | }
107 | .main-column > div.row.general-notifications {
108 | padding: 1.7em 3.4em 1.5em;
109 | }
110 |
111 | // McdAlert notification
112 | .inline-notification.mcd-alert {
113 | display: block;
114 | width: 90%;
115 | background-color: #FBAE17;
116 | padding: 1rem 1.5rem 1.1rem !important;
117 | margin: 1rem auto;
118 | background-color: #FBAE17;
119 | .message {
120 | font-weight: 300;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/scss/_cp-loading-spinner.scss:
--------------------------------------------------------------------------------
1 | @keyframes spinner {
2 | to {
3 | transform: rotate(360deg);
4 | }
5 | }
6 |
7 | .spinner {
8 | position: relative;
9 | width: 120px;
10 | height: 120px;
11 | margin: 2rem auto;
12 | &:before {
13 | content: '';
14 | box-sizing: border-box;
15 | position: absolute;
16 | top: 0;
17 | left: 0;
18 | width: 100%;
19 | height: 100%;
20 | border-radius: 50%;
21 | border: 1px solid #ccc;
22 | border-top-color: #1bc4a6;
23 | animation: spinner .6s linear infinite;
24 | }
25 | .maker-logo {
26 | position: relative;
27 | margin: 0 auto;
28 | width: 45%;
29 | height: 32.5%;
30 | top: 50%;
31 | svg {
32 | position: relative;
33 | margin: 0 auto;
34 | width: 100%;
35 | height: 100%;
36 | top: -50%;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/scss/_cp-markdown.scss:
--------------------------------------------------------------------------------
1 | .markdown {
2 | padding: 1.5rem 0;
3 |
4 | & * {
5 | user-select: text !important;
6 | }
7 |
8 | h1 {
9 | font-size: 2.5rem !important;
10 | border-color: #313d47;
11 | border-style: solid;
12 | border-width: 0 0 1px 0;
13 | padding-bottom: 1.7rem;
14 | }
15 |
16 | h2 {
17 | font-size: 1.85rem;
18 | line-height: 1.3;
19 | margin-bottom: 1.8rem;
20 | font-weight: 200;
21 | color: #fff;
22 | letter-spacing: 0.02rem;
23 | margin-top: 4.5rem;
24 |
25 | &:first-of-type {
26 | margin-top: 3rem;
27 | }
28 | }
29 |
30 | h3 {
31 | font-size: 1.5rem;
32 | line-height: 1.3;
33 | margin-bottom: 1.5rem;
34 | margin-top: 3rem;
35 | font-weight: 200;
36 | color: #dedede;
37 | letter-spacing: 0.02rem;
38 | }
39 |
40 | h2 + h3 {
41 | margin-top: 2rem;
42 | }
43 |
44 | p {
45 | max-width: 75%;
46 | font-size: 1.2rem;
47 | font-weight: 200;
48 | color: #9aa3ad;
49 | }
50 |
51 | b, strong {
52 | color: #a2aab3;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/scss/_cp-menu-bar.scss:
--------------------------------------------------------------------------------
1 | .menu-bar {
2 | background-color: $black;
3 | margin: 0;
4 | padding: 0;
5 | width: 65px;
6 | width: 5rem;
7 | height: 100%;
8 | display: block;
9 | position: fixed;
10 | left: 0;
11 | top: 0;
12 | z-index: 1;
13 | overflow: hidden;
14 | user-select: none;
15 |
16 | .logo {
17 | cursor: pointer;
18 | position: absolute;
19 | top:0;
20 | left:0;
21 | z-index: 3;
22 | display: block;
23 | background: $white;
24 | text-align: center;
25 | height: 65px;
26 | height: 5rem;
27 | width: 100%;
28 | padding: 26px 13px;
29 | padding: 1.53846rem 1rem;
30 | overflow: hidden;
31 | display: flex;
32 | flex-direction: column;
33 | justify-content: center;
34 | img, svg {
35 | display: inline-block;
36 | width: 100%;
37 | height: auto;
38 | min-width: 0;
39 | min-height: 0;
40 | }
41 | }
42 | .menu-label {
43 | display: none;
44 | }
45 | nav {
46 | position: absolute;
47 | top:0;
48 | left: 0;
49 | display: inline;
50 | padding: 0;
51 | margin: 0;
52 | height: 100%;
53 | width: 100%;
54 | }
55 | .menu {
56 | z-index: 2;
57 | text-indent: 0;
58 | padding: 65px 0 0;
59 | padding: 5rem 0 0;
60 | margin: 0 0 0;
61 | position: relative;
62 | height: 100%;
63 | width: 100%;
64 |
65 | li.cdp-id-item {
66 | a {
67 | text-decoration: none;
68 | padding: 1rem;
69 | @include respond-to(m) {
70 | padding: 0;
71 | }
72 | }
73 | @include respond-to(m) {
74 | padding: 10px 0;
75 | font-size: 0.8rem;
76 | }
77 | @include respond-to(s) {
78 | padding: 13px 0;
79 | font-size: 0.8rem;
80 | }
81 | }
82 | li a {
83 | padding: 1.76rem;
84 | @include respond-to(m) {
85 | padding: 0;
86 | }
87 | width: 100%;
88 | height: 100%;
89 | }
90 | li, &>* {
91 | cursor: pointer;
92 | list-style-type: none;
93 | padding: 0;
94 | margin: 0;
95 | text-indent: 0;
96 | width: 100%;
97 | height: 65px;
98 | height: 5rem;
99 | text-align: center;
100 | display: inline-block;
101 | float: left;
102 | display: flex;
103 | flex-direction: column;
104 | justify-content: center;
105 | transition: background-color .2s linear, color .2s linear;
106 |
107 | &:hover, &.active {
108 | background-color: $bg-darkgrey;
109 | color: $white;
110 | img { opacity: 1; }
111 | }
112 | &:active {
113 | img { opacity: 0.5; }
114 | }
115 | &[value="settings"]{
116 | position: absolute;
117 | transform: translateY(-1px);
118 | bottom: 65px;
119 | bottom: 5rem;
120 | }
121 | &[value="help"]{
122 | position: absolute;
123 | bottom: 0;
124 | }
125 |
126 | img {
127 | width: 100%;
128 | height: auto;
129 | max-width: 100%;
130 | opacity: 0.5;
131 | transition: opacity .2s ease-in;
132 | }
133 | }
134 | }
135 |
136 | @include respond-to(m) {
137 |
138 | width: 100%;
139 | height: 50px;
140 | position: relative;
141 | padding: 0;
142 |
143 | .logo {
144 | height: 50px;
145 | width: 50px;
146 | padding: 10px 12px;
147 | }
148 | .menu {
149 | padding: 0 0 0 50px;
150 |
151 | li, &>* {
152 | height: 100%;
153 | width: 50px;
154 | padding: 16px;
155 | display: inline-block;
156 | &[value="help"], &[value="settings"]{
157 | transform: none;
158 | position: relative;
159 | bottom: auto;
160 | float: right;
161 | margin-left: 1px;
162 | }
163 | }
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/scss/_cp-migrate-legacy-cups.scss:
--------------------------------------------------------------------------------
1 | // Customized inline notification
2 | .inline-notification.migrate-cups {
3 | padding: 1rem 1.5rem 1.1rem !important;
4 | .message {
5 | font-weight: 300;
6 | }
7 | }
8 |
9 | // Migrate cups menu item
10 | ul.menu {
11 | li.migrate-cups {
12 | padding-top: 12px;
13 | padding-bottom: 10px;
14 | height: auto;
15 |
16 | color: #dedede;
17 | &.active, &:hover {
18 | color: #fff;
19 | svg path {
20 | fill: #fff;
21 | }
22 | }
23 |
24 | svg {
25 | display: block;
26 | margin: 0 auto 5px;
27 | width: 20px;
28 | height: auto;
29 | path {
30 | transition: fill 0.2s linear;
31 | }
32 | }
33 |
34 | @include respond-to(m) {
35 | height: 100%;
36 | padding: 5px 10px;
37 | font-size: 0.8rem;
38 | width: auto;
39 | svg {
40 | margin: 2px auto 4px;
41 | width: 18px;
42 | }
43 | }
44 | }
45 | }
46 |
47 | // Migrate cups page
48 | .migrate-cups-section {
49 |
50 | .number-of-cdps-to-migrate {
51 | font-size: 1.1rem;
52 | font-weight: 200;
53 | letter-spacing: 0.02rem;
54 | clear: both;
55 | padding-top: 0.5rem;
56 | }
57 |
58 | .cup-to-migrate {
59 |
60 | .cdp-id-heading {
61 | margin-top: 3rem;
62 | margin-bottom: 0.4rem
63 | }
64 |
65 | table {
66 | float: left;
67 | border: 1px solid #728391;
68 | padding: 0.7rem 1rem 0.6rem;
69 | width: calc(100% - 200px);
70 | @include respond-to(xl) {
71 | width: calc(100% - 230px);
72 | }
73 | th, tr {
74 | text-align: left;
75 | color: #fff;
76 | letter-spacing: 0.01rem;
77 | }
78 | th {
79 | text-transform: uppercase;
80 | font-weight: 300;
81 | font-size: 0.9rem;
82 | white-space: nowrap;
83 | &.status-column {
84 | width: 75px;
85 | }
86 | }
87 | tr {
88 | font-weight: 200;
89 | font-size: 1.2rem;
90 | color: rgba(255, 255, 255, 0.85);
91 | td {
92 | padding-top: 3px;
93 | &.cdp-status {
94 | svg {
95 | margin-right: 8px;
96 | }
97 | }
98 | }
99 | }
100 | }
101 | .migrate-button {
102 | float: right;
103 | margin-top: 1.2rem;
104 | button {
105 | padding-left: 1.5rem;
106 | padding-right: 1.5rem;
107 | }
108 | }
109 |
110 | .migrate-success {
111 | display: inline-block;
112 | min-width: 12rem;
113 | background: #27AE60;
114 | padding: 12px 1.5rem 12px 1.5rem;
115 | margin-bottom: 1em;
116 | color: #fff;
117 | text-align: center;
118 | font-weight: normal;
119 | letter-spacing: 0.0025em;
120 | outline: 0;
121 | margin: 0;
122 | border-radius: 2px;
123 | user-select: none;
124 | font-size: 100%;
125 | line-height: 1.15;
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/scss/_cp-modal.scss:
--------------------------------------------------------------------------------
1 | #root > .modal-open {
2 | @include filter(blur, 3px);
3 | }
4 | .modal {
5 | position: fixed;
6 | left: 0px;
7 | right: 0px;
8 | top: 0px;
9 | bottom: 0px;
10 | background: rgba(0, 0, 0, 0.25);
11 | z-index: 997;
12 | .modal-inner {
13 | position: relative;
14 | width: 29.2rem;
15 | background: #202930;
16 | z-index: 998;
17 | margin: 175px auto 0;
18 | box-shadow: 0 4px 12px 0 rgba(0,0,0,0.50);
19 | border-radius: 3px;
20 |
21 | h2 {
22 | color: #fff;
23 | text-align: center;
24 | padding-top: 2.4rem;
25 | letter-spacing: 0.02rem;
26 | margin-bottom: 1rem;
27 | }
28 | h3 {
29 | font-size: 1.4rem;
30 | line-height: 1;
31 | color: #fff;
32 | text-align: center;
33 | letter-spacing: 0.02rem;
34 | margin: 1rem 0;
35 | }
36 | p {
37 | color: #A3A3A3;
38 | font-size: 0.9rem;
39 | line-height: 1.75;
40 | text-align: center;
41 | width: 65%;
42 | margin: 0 auto 2.3rem;
43 | user-select: none;
44 | }
45 | }
46 | }
47 |
48 | .modal.create-cdp {
49 | @include respond-to('s+') {
50 | position: absolute;
51 | }
52 | }
53 |
54 | .modal.create-cdp .modal-inner {
55 | width: 54rem;
56 | max-width: 90%;
57 | margin-top: 10vh;
58 | @include respond-to('s+') {
59 | margin-top: 2rem;
60 | }
61 | h2 {
62 | color: #fff;
63 | text-align: center;
64 | padding: 0;
65 | font-size: 1.4rem;
66 | letter-spacing: 0.02rem;
67 | font-weight: 200;
68 | padding: 1.5rem 0;
69 | border-bottom: 1px solid #313D47;
70 | }
71 | img.main {
72 | display: block;
73 | margin: 0 auto;
74 | margin-top: 4rem;
75 | width: 488px;
76 | height: 176px;
77 | max-width: 100%;
78 | }
79 | p {
80 | color: #879099;
81 | font-size: 1.1rem;
82 | line-height: 1.4;
83 | letter-spacing: 0.02rem;
84 | margin: 2rem auto 1.5rem;
85 | font-weight: 200;
86 | }
87 | ul {
88 | display: block;
89 | font-size: 1rem;
90 | font-weight: 300;
91 | color: #fff;
92 | letter-spacing: 0.02rem;
93 | text-align: center;
94 | margin: 0;
95 | padding-bottom: 3.7rem;
96 | li {
97 | display: inline-block;
98 | margin: 1rem 3rem 0;
99 | @include respond-to('s+') {
100 | margin: 1rem 0.5rem 0;
101 | min-width: 5rem;
102 | }
103 | min-width: 10rem;
104 | &:first-child {
105 | margin-left: 0;
106 | }
107 | &:last-child {
108 | margin-right: 0;
109 | }
110 | div.icon {
111 | height: 30px;
112 | margin-bottom: 0.7rem;
113 | img {
114 | width: auto;
115 | height: 24px;
116 | }
117 | }
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/scss/_cp-not-found.scss:
--------------------------------------------------------------------------------
1 | .not-found {
2 | width: 100%;
3 | height: 588px;
4 | background: linear-gradient(to bottom, #202124, #303B41);
5 | img {
6 | width: auto;
7 | height: 546px;
8 | margin-top: 100px;
9 | }
10 | .not-found-text-container-1 {
11 | width: 80%;
12 | margin: 0 auto;
13 | white-space: nowrap;
14 | }
15 | .not-found-text-container-2 {
16 | float: left;
17 | }
18 | h1 {
19 | color: #50E3C2;
20 | font-size: 1rem;
21 | margin: 2rem 0 1rem;
22 | }
23 | h2 {
24 | font-size: 2.3rem;
25 | margin: 1rem 0 0.5rem;
26 | color: #fff;
27 | }
28 | h3 {
29 | font-size: 2.3rem;
30 | margin: 1rem 0 0.5rem;
31 | color: #fff;
32 | }
33 | p {
34 | color: #808B97;
35 | font-size: 1.3rem;
36 | margin: 0.5rem 0;
37 | user-select: none;
38 | }
39 | }
40 | .not-found-2 {
41 | .not-found-text-container-1 {
42 | width: 80%;
43 | margin: 0 auto;
44 | }
45 | p {
46 | color: #808B97;
47 | font-size: 1.5rem;
48 | margin: 3rem 0 1rem;
49 | user-select: none;
50 | }
51 | button {
52 | margin: 1rem 0;
53 | padding-left: 2rem;
54 | padding-right: 2rem;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/scss/_cp-notify.scss:
--------------------------------------------------------------------------------
1 | // boxes in alerts
2 | .notifications-container {
3 | position: fixed;
4 | width: 340px;
5 | z-index: 999;
6 | right: 0;
7 | top: 0;
8 |
9 | & > * {
10 | padding: 32px 44px;
11 | position: relative;
12 | border: 0;
13 | border-radius: 2px;
14 | margin-top: 0.7rem;
15 | right: 0.7rem;
16 | p {
17 | max-width: 30em;
18 | }
19 | }
20 | h3 {
21 | margin-top: 0px;
22 | }
23 | .nf-error {
24 | background-color: rgba($error-red, 0.85);
25 | color: $white;
26 | .notification-headline {
27 | &:after {
28 | content: url('"~images/icon-stop.svg');
29 | position: absolute;
30 | left: -1.5em;
31 | top: auto;
32 | margin-top: 0.05em;
33 | }
34 | }
35 | }
36 | .nf-info {
37 | background-color: rgba($neutral-blue, 0.85);
38 | color: $white;
39 | .notification-headline {
40 | &:after {
41 | content: url('"~images/icon-clock.svg');
42 | position: absolute;
43 | left: -1.5em;
44 | top: auto;
45 | margin-top: 0.05em;
46 | }
47 | }
48 | }
49 | .nf-success {
50 | background-color: rgba($success-green, 0.85);
51 | color: $white;
52 | .notification-headline {
53 | &:after {
54 | content: url('"~images/icon-check.svg');
55 | position: absolute;
56 | left: -1.5em;
57 | top: auto;
58 | margin-top: 0.05em;
59 | }
60 | }
61 | }
62 | .nf-notice {
63 | background-color: rgba(#EAEAEA, 0.85);
64 | .notification-headline {
65 | color: #C0392B;
66 | &:after {
67 | content: url("~images/icon-warning.svg");
68 | position: absolute;
69 | left: -30px;
70 | top: auto;
71 | margin-top: 3px;
72 | }
73 | }
74 | div.grouped-section {
75 | color: #C0392B;
76 | font-size: 1.05rem;
77 | letter-spacing: 0.01rem;
78 | margin-top: 1em;
79 | margin-bottom: 1em;
80 | }
81 | .dark-text {
82 | color: #202930;
83 | }
84 | .indented-section {
85 | position: relative;
86 | padding-left: 2.5rem;
87 | }
88 | .line-indent {
89 | width: 7px;
90 | height: 94%;
91 | top: 3%;
92 | position: absolute;
93 | left: 10px;
94 | border-bottom: 1px solid #313D47;
95 | &:after {
96 | border-left: 1px solid #313D47;
97 | width: 1px;
98 | height: 100%;
99 | content: ' ';
100 | position: absolute;
101 | left: 3px;
102 | }
103 | }
104 | }
105 | .close-box {
106 | position: absolute;
107 | top: 0.785em;
108 | right: 0.785em;
109 | }
110 | .notification-headline {
111 | @include fontweight(bold);
112 | position: relative;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/scss/_cp-range-slider.scss:
--------------------------------------------------------------------------------
1 | .horizontal-slider {
2 | width: 225px;
3 | margin: 0 auto;
4 | cursor: pointer;
5 |
6 | .rangeslider.rangeslider-horizontal {
7 | height: 4px;
8 | border-radius: 0;
9 | background-color: #9AA3AD;
10 | width: 100%;
11 | -webkit-box-shadow: none;
12 | box-shadow: none;
13 | margin: 20px 0 16px;
14 |
15 | .rangeslider__handle {
16 | outline: none;
17 | width: 18px;
18 | height: 18px;
19 | border-radius: 50%;
20 | -webkit-box-shadow: none;
21 | box-shadow: none;
22 | background-color: #1ABC9C;
23 | border: none;
24 | &:after {
25 | display: none;
26 | }
27 | }
28 |
29 | .rangeslider__fill {
30 | -webkit-box-shadow: none;
31 | box-shadow: none;
32 | border-radius: 0;
33 | background-color: #20af93;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/scss/_cp-steps.scss:
--------------------------------------------------------------------------------
1 | header {
2 | .rc-steps {
3 | @include inline-flex;
4 | width: unset;
5 | }
6 |
7 | .rc-steps-item-custom {
8 | -ms-flex: unset;
9 | flex: unset;
10 | user-select: none;
11 | white-space: nowrap;
12 | .rc-steps-item-icon {
13 | font-size: 1rem;
14 | background: initial;
15 | height: unset;
16 | width: unset;
17 | margin-right: 0.6rem;
18 | border-radius: 50%;
19 | background-color: $bg-grey;
20 | border: solid 1px $line-grey;
21 | @include transition(background-color 0.5s, border-color 0.5s);
22 |
23 | & > .rc-steps-icon {
24 | color: $text-grey;
25 | font-size: unset;
26 | top: unset;
27 | width: unset;
28 | height: unset;
29 | @include transition(color 0.5s);
30 | }
31 | }
32 | .rc-steps-item-icon-inner {
33 | border: 2px solid $bg-grey;
34 | background-color: $line-grey;
35 | width: 2em;
36 | height: 2em;
37 | line-height: calc(2em - 4px);
38 | text-align: center;
39 | border-radius: 50%;
40 | font-weight: normal;
41 | font-size: 1em;
42 | }
43 | .rc-steps-item-content {
44 | margin-top: 2px;
45 | // Step text
46 | .rc-steps-item-title {
47 | color: $text-grey;
48 | font-weight: 300;
49 | font-size: 1.3rem;
50 | }
51 | // Line separator
52 | .rc-steps-item-title:after {
53 | top: 50%;
54 | background-color: $text-grey;
55 | }
56 | }
57 | // Line separator width
58 | &:not(:last-child) .rc-steps-item-title {
59 | margin-right: 35px;
60 | }
61 |
62 | // Active step element styles
63 | &.rc-steps-item-process {
64 | .rc-steps-item-icon {
65 | background-color: $bg-grey;
66 | border-color: darken($white, 5%);
67 | & > .rc-steps-icon {
68 | color: $white;
69 | }
70 | }
71 | // Step text
72 | .rc-steps-item-title {
73 | color: $white;
74 | }
75 | // Step separator (line)
76 | .rc-steps-item-title:after {
77 | background-color: $white;
78 | }
79 | }
80 |
81 | // Finished step element styles
82 | &.rc-steps-item-finish {
83 | // Step separator (line)
84 | .rc-steps-item-title:after {
85 | background-color: $text-grey;
86 | }
87 | }
88 |
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/scss/_cp-toggle-switch.scss:
--------------------------------------------------------------------------------
1 | .switch {
2 | position: relative;
3 | width: 44px;
4 | height: 22px;
5 | border-radius: 11px;
6 | cursor: pointer;
7 | display: inline-block;
8 | background-color: #4f565b;
9 | transition: background-color 0.2s ease-in-out;
10 | line-height: 1;
11 | font-size: 14px;
12 |
13 | &.on {
14 | background-color: #1abc9c;
15 |
16 | & .toggle-switch {
17 | background-color: #fff;
18 | left: calc(100% - 20px);
19 |
20 | svg {
21 | top: 2px;
22 | width: 9px;
23 | height: 10px;
24 | }
25 | }
26 |
27 | .switch-spinner:before {
28 | border-top-color: #16927a;
29 | }
30 | }
31 |
32 | &.disabled {
33 | cursor: not-allowed;
34 | }
35 |
36 | .toggle-switch {
37 | position: absolute;
38 | left: 3px;
39 | top: 2px;
40 | width: 18px;
41 | height: 18px;
42 | border-radius: 50%;
43 | background-color: #152128;
44 | transition: left 0.2s ease-in-out, background-color 0.2s ease-in-out;
45 | text-align: center;
46 |
47 | svg {
48 | position: relative;
49 | top: 1px;
50 | width: 10px;
51 | height: 10px;
52 | }
53 | }
54 | @keyframes switch-spinner {
55 | to {
56 | transform: rotate(360deg);
57 | }
58 | }
59 |
60 | .switch-spinner {
61 | position: relative;
62 | width: 100%;
63 | height: 100%;
64 |
65 | &:before {
66 | content: '';
67 | box-sizing: border-box;
68 | position: absolute;
69 | top: 0;
70 | left: 0;
71 | width: 100%;
72 | height: 100%;
73 | border-radius: 50%;
74 | border: 1px solid transparent;
75 | border-top-color: #1bc4a6;
76 | animation: switch-spinner 0.6s ease-in-out infinite;
77 | }
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/scss/_cp-tooltip.scss:
--------------------------------------------------------------------------------
1 | .__react_component_tooltip {
2 | background-color: #ffffff;
3 | box-shadow: 0 -2px 8px 0 rgba(0, 0, 0, 0.4);
4 | opacity: 1 !important;
5 | z-index: 10000;
6 | pointer-events: all;
7 | max-width: 410px !important;
8 | @include respond-to(s) {
9 | max-width: 200px !important;
10 | }
11 | a:hover {
12 | color: $maker-green;
13 | }
14 | a.more-info {
15 | // margin-left: 5px;
16 | }
17 | }
18 |
19 | .tooltip-hint {
20 | display: inline-block;
21 | position: relative;
22 | cursor: pointer;
23 | margin-left: 0.4rem;
24 | top: 0.15rem;
25 | width: 12px;
26 | height: 12px;
27 | @include respond-to(xl) {
28 | width: 13px;
29 | height: 13px;
30 | top: 1px;
31 | }
32 |
33 | path {
34 | fill: $text-grey;
35 | }
36 | &:hover path {
37 | fill: $silver;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/scss/_cp-wizard.scss:
--------------------------------------------------------------------------------
1 | svg.wizard.expand-section-btn {
2 | float: right;
3 | }
4 |
5 | .wizard-section {
6 | .input-values-container {
7 | display: inline-block;
8 | input.number-input {
9 | min-width: 15rem;
10 | }
11 | @include respond-to('s+') {
12 | input.number-input {
13 | font-size: 1.5em;
14 | max-width: 77%;
15 | min-width: unset;
16 | width: 29.25rem;
17 | height: 39px;
18 | & + .unit {
19 | font-size: 1.2em;
20 | width: 20%;
21 | max-width: 4em;
22 | min-width: unset;
23 | padding: 0;
24 | height: 39px;
25 | line-height: 3.1em;
26 | }
27 | }
28 | }
29 | }
30 | }
31 |
32 | .wizard-automated-transactions {
33 | user-select: none;
34 | overflow: hidden;
35 | max-height: 0;
36 | transition: max-height 0.15s ease-out;
37 |
38 | &.expanded {
39 | max-height: 1000px;
40 | transition: max-height 0.25s ease-in;
41 | }
42 |
43 | .step-cointainer {
44 | clear: both;
45 | &:first-child {
46 | padding-top: 2.5rem;
47 | }
48 | &:last-child {
49 | padding-bottom: 3.5rem;
50 | }
51 |
52 | .step-icon {
53 | float: left;
54 | height: 5.6rem;
55 | width: 4.5rem;
56 |
57 | .vertical-line {
58 | position: relative;
59 | width: 1px;
60 | height: calc(100% - 3.8rem);
61 | left: 1rem;
62 | top: 0.85rem;
63 | border-left: 1px solid $line-grey;
64 | }
65 | }
66 |
67 | &:last-child .step-icon {
68 | height: 1px;
69 | .vertical-line {
70 | display: none;
71 | }
72 | }
73 |
74 | .step-message {
75 | float: left;
76 | line-height: 1.5;
77 | margin-top: 3px;
78 | }
79 |
80 | .steps-item {
81 | display: inline-block;
82 | font-size: 1rem;
83 | margin-right: 0.6rem;
84 | border-radius: 50%;
85 | background-color: $bg-grey;
86 | border: solid 1px darken($white, 5%);
87 |
88 | .steps-item-inner {
89 | color: darken($white, 5%);
90 | border: 2px solid $bg-grey;
91 | background-color: $line-grey;
92 | width: 2em;
93 | height: 2em;
94 | line-height: calc(2em - 4px);
95 | text-align: center;
96 | border-radius: 50%;
97 | font-weight: normal;
98 | font-size: 1em;
99 | }
100 | }
101 |
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/scss/_forecast-mode.scss:
--------------------------------------------------------------------------------
1 |
2 |
3 | .forecast-mode {
4 |
5 | .value {
6 |
7 | &:before {
8 | content: 'forecast *';
9 | white-space: nowrap;
10 | position: absolute;
11 | right: 100%;
12 | padding-right: 0.5em;
13 | top: -0.5em;
14 | @include fontsize(cxs);
15 | color: $maker-green;
16 | }
17 | }
18 |
19 |
20 | .chart-container .chart .line-chart .x.axis g.tick:last-child {
21 | text {
22 | fill: $maker-green;
23 | }
24 | line {
25 | stroke: $maker-green-alpha;
26 | stroke-width: 4em;
27 | stroke-linecap: butt;
28 | stroke-dasharray: 0.1% 0.1%;
29 | }
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/scss/_forms.scss:
--------------------------------------------------------------------------------
1 | // LABELS
2 |
3 | label, .form-label {
4 | margin-bottom: 0.5em;
5 | display: block;
6 |
7 | input + & {
8 | margin-top: 2em;
9 | }
10 | }
11 |
12 | // FIELDSET
13 |
14 | fieldset {
15 | border: 0;
16 | padding-left: 0;
17 | padding-right: 0;
18 | }
19 |
20 | // TEXT/NUMBER INPUTS
21 |
22 | input[type="text"], input[type="number"] {
23 | border: 0;
24 | outline: 0;
25 | padding: 0 .5em;
26 | @include interactive("pushInAndCrush");
27 | @include fontweight(bold);
28 | line-height: 2.5em;
29 | height: 2.5em;
30 | }
31 |
32 | input[type="text"].number-input, input[type="number"].number-input {
33 | float: left;
34 | text-align: right;
35 | border-radius: 2px 0px 0px 2px;
36 | position: relative;
37 | z-index: 1;
38 | & + .unit {
39 | color: lighten($black, 5%);
40 | position: relative;
41 | z-index: 0;
42 | display: inline-block;
43 | float: left;
44 | height: 2.5em;
45 | line-height: 2.5em;
46 | vertical-align: baseline;
47 | padding: 0 1em;
48 | background-color: $white-two;
49 | min-width: 4em;
50 | text-align: center;
51 | border-radius: 0 2px 2px 0;
52 | }
53 | }
54 |
55 |
56 | // CHECKBOXES
57 |
58 | input[type='checkbox']:checked,
59 | input[type='checkbox']:not(:checked),
60 | input[type='radio']:checked,
61 | input[type='radio']:not(:checked) {
62 | background: transparent;
63 | position: relative;
64 | visibility: hidden;
65 | margin: 0;
66 | padding: 0;
67 | }
68 |
69 | input[type='checkbox']+label,
70 | input[type='radio']+label {
71 | cursor: pointer;
72 | }
73 |
74 | input[type="radio"] {
75 | // Remove standard styles
76 | -webkit-appearance: none;
77 | -moz-appearance: none;
78 | appearance: none;
79 | border: none;
80 | border-radius: 0;
81 | font-size: 1em;
82 |
83 | // Graceful degradation for IE8
84 | width: auto;
85 | float: left;
86 | margin-right: .75em;
87 |
88 | // Hide native radio button
89 | background: transparent;
90 | border: none;
91 | display: inline-block;
92 | line-height: inherit;
93 | vertical-align: baseline;
94 |
95 | // Add custom styles
96 | &:checked + label::before,
97 | &:not(:checked) + label::before {
98 | content: ' ';
99 | display: inline-block;
100 | position: relative;
101 | top: 5px;
102 | width: 15px;
103 | height: 15px;
104 | @include respond-to(xl) {
105 | width: 16px;
106 | height: 16px;
107 | margin-right: 7px;
108 | }
109 | border: 2px solid rgba(49, 61, 71, 0.8);
110 | margin-right: 6px;
111 | border-radius: 50%;
112 | transition-property: border-color, background;
113 | transition-duration: 0.2s;
114 | transition-timing-function: ease-in;
115 | }
116 | & + label:hover::before {
117 | border-color: rgba(49, 61, 71, .8);
118 | background: rgba(18, 187, 155, 0.3);
119 | box-shadow: inset 0px 0px 0px 2px #ced0d2;
120 | }
121 | &:checked + label::before {
122 | border-color: rgba(49, 61, 71, .8);
123 | background: #12BB9B;
124 | box-shadow: inset 0px 0px 0px 2px #ced0d2;
125 | }
126 |
127 | // Layout for labels
128 | & + label {
129 | display: inline-block;
130 | margin:0;
131 | user-select: none;
132 | }
133 | & + label + & + label {
134 | margin-left: 3em;
135 | }
136 | }
137 |
138 | // Custom checkbox
139 | label.checkbox-container {
140 | // Customize the label container
141 | display: block;
142 | position: relative;
143 | padding-left: 26px;
144 | cursor: pointer;
145 | font-size: 1.1rem;
146 | line-height: 1.3;
147 | -webkit-user-select: none;
148 | -moz-user-select: none;
149 | -ms-user-select: none;
150 | user-select: none;
151 | // Hide the browser's default checkbox
152 | input {
153 | position: absolute;
154 | opacity: 0;
155 | cursor: pointer;
156 | }
157 | // Create a custom checkbox
158 | .checkmark {
159 | position: absolute;
160 | top: 0;
161 | left: 0;
162 | height: 18px;
163 | width: 18px;
164 | border-radius: 2px;
165 | background-color: #eee;
166 | }
167 | // On mouse-over, darken bg
168 | &:hover input ~ .checkmark {
169 | background-color: darken(#eee, 3%);
170 | }
171 | // When the checkbox is checked
172 | input:checked ~ .checkmark {
173 | background-color: #1BC4A6;
174 | }
175 | // On mouse-over, lighten bg
176 | &:hover input:checked ~ .checkmark {
177 | background-color: lighten(#1BC4A6, 3%);
178 | }
179 | // Create the checkmark/indicator (hidden when not checked)
180 | .checkmark:after {
181 | content: "";
182 | position: absolute;
183 | display: none;
184 | }
185 | // Show the checkmark when checked
186 | input:checked ~ .checkmark:after {
187 | display: block;
188 | }
189 | // Style the checkmark/indicator
190 | .checkmark:after {
191 | left: 6px;
192 | top: 2px;
193 | width: 3px;
194 | height: 9px;
195 | border: solid #0b5447;
196 | border-width: 0 3px 3px 0;
197 | -webkit-transform: rotate(45deg);
198 | -ms-transform: rotate(45deg);
199 | transform: rotate(45deg);
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/scss/_general.scss:
--------------------------------------------------------------------------------
1 | .printedNumber {
2 | cursor: pointer;
3 | }
4 |
--------------------------------------------------------------------------------
/src/scss/_helpers.scss:
--------------------------------------------------------------------------------
1 | // Helper classes
2 |
3 | .align-right {
4 | text-align: right !important;
5 | }
6 |
7 | .align-center {
8 | text-align: center !important;
9 | }
10 |
11 | .no-select {
12 | user-select: none !important;
13 | }
14 |
15 | .no-margin {
16 | margin: 0 !important;
17 | }
18 |
19 | .clear-left {
20 | clear: left !important;
21 | }
22 |
23 | .clearfix {
24 | clear: both !important;
25 | }
26 |
27 | .no-wrap {
28 | white-space: nowrap !important;
29 | }
30 |
--------------------------------------------------------------------------------
/src/scss/_interactive.scss:
--------------------------------------------------------------------------------
1 | // Interation Styles
2 |
3 | @mixin interactive($style) {
4 |
5 | @if $style == "liftAndPushIn" {
6 | box-shadow: 0px 0px 0px 0px transparent;
7 | transition-duration: .18s;
8 | transition-property: box-shadow, background-color, opacity, border, color, margin-left, margin-right, width, min-width, max-width;
9 | transition-timing-function: ease-out;
10 | z-index: 0;
11 |
12 | &:hover {
13 | z-index: 1;
14 | box-shadow: 0px 1px 6px 0px rgba(0, 0, 0, 0.9);
15 | }
16 | &:active, &:focus {
17 | transition-duration: 0.18s;
18 | box-shadow: 0 1px 2px 0px rgba(0, 0, 0, 0.9);
19 | }
20 | &:focus, &:hover, &:active {
21 | outline: 0;
22 | }
23 |
24 | .bright-style &, &.bright-style {
25 | &:enabled:hover {
26 | box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
27 | }
28 | &:active, &:focus {
29 | box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
30 | }
31 | }
32 | }
33 | @if $style == "pushInAndCrush" {
34 | box-shadow: 0px 0px 0px 0px transparent, inset 0px 0px 0px 0px transparent;
35 | transition-duration: .18s;
36 | transition-property: box-shadow, text-shadow, transform, border;
37 | transition-timing-function: ease-out;
38 | border: 0;
39 | outline: 0;
40 |
41 | &:hover {
42 | box-shadow: inset 0px 0px 0px 1px #B3B3B3, inset 0px 2px 2px 0px rgba(0, 0, 0, 0.2);
43 | }
44 | &:active, &:focus {
45 | transition-duration: 0.18s;
46 | box-shadow: inset 0 0 0 1px $maker-green, inset 0 2px 2px 0 rgba(0, 0, 0, 0.4)
47 | }
48 | &:focus, &:hover, &:active {
49 | outline: 0;
50 | }
51 |
52 | .bright-style &, &.bright-style {
53 | box-shadow: 0px 0px 0px 0px transparent, inset 0px 0px 0px 0px transparent;
54 | &:hover {
55 | box-shadow: 0px 0px 0px 1px #B3B3B3, inset 0px 2px 2px 0px rgba(0, 0, 0, 0.2);
56 | }
57 | &:active, &:focus {
58 | box-shadow: 0px 0px 0px 1px $maker-green, inset 0px 2px 2px 0px rgba(0, 0, 0, 0.2);
59 | }
60 | }
61 | }
62 | @if $style == "enlightAndSrink" {
63 | background-color: rgba(255, 255, 255, 0);
64 | transition-duration: .18s;
65 | transition-property: background-color, transform, box-shadow;
66 | transition-timing-function: ease-out;
67 |
68 | &:hover {
69 | box-shadow: none;
70 | background-color: rgba(255, 255, 255, 0.15);
71 | }
72 | &:active {
73 | background-color: rgba(255, 255, 255, 0.25);
74 | }
75 | &:focus, &:hover, &:active {
76 | outline: 0;
77 | }
78 |
79 |
80 | .bright-style &, &.bright-style {
81 | background-color: rgba(0, 0, 0, 0);
82 | &:hover {
83 | background-color: rgba(0, 0, 0, 0.10);
84 | box-shadow: none;
85 | }
86 | &:active {
87 | background-color: rgba(0, 0, 0, 0.2);
88 | }
89 | &::after {
90 | transition-duration: .18s;
91 | transition-property: transform;
92 | transition-timing-function: ease-out;
93 | }
94 | &:active::after {
95 | transform: scale(0.7);
96 | }
97 | }
98 |
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/scss/_layout.scss:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | html {
6 | background-color: $bg-grey;
7 | }
8 |
9 | body {
10 | // min-width: 768px;
11 | margin: 0;
12 | overflow: auto;
13 | overflow-x: hidden;
14 |
15 | @media only screen and (max-width: 767px) {
16 | overflow-x: auto;
17 | }
18 | }
19 |
20 | #root {
21 | padding: 0;
22 | margin: 0;
23 | display: inline;
24 | }
25 |
26 | .wrapper {
27 | width: 100%;
28 | min-height: 100vh;
29 | position: relative;
30 | padding-left: 65px;
31 | padding-right: 340px;
32 | background-color: $bg-grey;
33 | transition: padding-right .3s ease-in;
34 |
35 | @include respond-to(m) {
36 | padding-left: 0;
37 | padding-right: 0;
38 | }
39 | @include respond-to(xl) {
40 | padding-left: 80px;
41 | padding-right: 0;
42 | }
43 |
44 | .full-width-page &, &.full-width-page {
45 | padding-right: 0;
46 | .right-column {
47 | right: -50%;
48 | @include respond-to(m) {
49 | right: 0px;
50 | bottom: -100%;
51 | }
52 | border-left: none;
53 | }
54 | .main-column {
55 | padding-right: 0;
56 | margin-right: 0;
57 | width: 100%;
58 | }
59 | }
60 | }
61 |
62 |
63 |
64 | .main-column {
65 | z-index: 1;
66 | background-color: $bg-grey;
67 | min-height: 100%;
68 | width: 100%;
69 | display: block;
70 | overflow: hidden;
71 |
72 | & > div {
73 | width: 100%;
74 | padding: 23px 44px 38px;
75 | padding: 1.7em 3.3846153em 3em;
76 | }
77 |
78 | // large Screen layout
79 | @include respond-to(xl) {
80 | width: calc(75% - 20px);
81 | .is-not-connected & {
82 | width: 75%;
83 | }
84 | }
85 | // medium Screen layout
86 | @include respond-to(m) {
87 | min-height: 0;
88 | }
89 | }
90 |
91 | // ALIGNMENT
92 |
93 | .right {
94 | float: right;
95 | }
96 |
97 |
98 | // GRID
99 |
100 | .col,
101 | .row {
102 | border-color: $line-grey;
103 | border-style: solid;
104 | border-width: 0 0 1px 0;
105 | display: inline-block;
106 | width: 100%;
107 | float: left;
108 |
109 | &.row-no-border {
110 | border: 0;
111 | }
112 | }
113 |
114 | .row .col {
115 | border-width: 0;
116 | }
117 |
118 | .col {
119 | padding: 1em 0;
120 |
121 | @include respond-to(xl) {
122 | padding: 1.5em 0;
123 | }
124 |
125 | &.col-extra-padding {
126 | padding-top: 4em;
127 | padding-bottom: 4em;
128 |
129 | @include respond-to(xl) {
130 | padding-top: 5em;
131 | padding-bottom: 5em;
132 | }
133 | }
134 | &.col-no-border {
135 | border: 0;
136 | }
137 | }
138 |
139 | .col-2 {
140 | width: 50%;
141 | float: left;
142 | padding-left: 1em;
143 |
144 | &:first-child {
145 | border-right-width: 1px;
146 | padding-left: 0px;
147 | padding-right: 1em;
148 | }
149 |
150 | @include respond-to(xl) {
151 | padding-left: 1.5em;
152 | &:first-child {;
153 | padding-left: 0px;
154 | padding-right: 1.5em;
155 | }
156 | }
157 | }
158 |
159 | // responsive columns
160 |
161 | @include respond-to(m) {
162 | [foo], .row-2col-m {
163 | display: flex;
164 | flex-direction: row;
165 |
166 | & > * {
167 | padding-left: 1em;
168 | border-bottom-width: 0px;
169 | }
170 |
171 | & > *:first-child {
172 | border-right-width: 1px;
173 | padding-left: 0px;
174 | padding-right: 0;
175 | }
176 | }
177 | }
178 |
179 | .inner-row {
180 | clear: both;
181 | display: block;
182 | margin-top: 1em;
183 | line-height: 3em;
184 | vertical-align: baseline;
185 | }
186 |
--------------------------------------------------------------------------------
/src/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin flexbox {
2 | display: -webkit-box;
3 | display: -moz-box;
4 | display: -webkit-flex;
5 | display: -ms-flexbox;
6 | display: flex;
7 | }
8 |
9 | @mixin inline-flex {
10 | display: -webkit-inline-box;
11 | display: -moz-inline-box;
12 | display: -webkit-inline-flex;
13 | display: -ms-inline-flexbox;
14 | display: inline-flex;
15 | }
16 |
17 | @mixin transition($transition...) {
18 | -moz-transition: $transition;
19 | -o-transition: $transition;
20 | -webkit-transition: $transition;
21 | transition: $transition;
22 | }
23 |
24 | @mixin filter($filter-type, $filter-amount) {
25 | -webkit-filter: $filter-type+unquote('(#{$filter-amount})');
26 | -moz-filter: $filter-type+unquote('(#{$filter-amount})');
27 | -ms-filter: $filter-type+unquote('(#{$filter-amount})');
28 | -o-filter: $filter-type+unquote('(#{$filter-amount})');
29 | filter: $filter-type+unquote('(#{$filter-amount})');
30 | }
31 |
--------------------------------------------------------------------------------
/src/scss/_text-styles.scss:
--------------------------------------------------------------------------------
1 | p.error {
2 | clear: left;
3 | color: $error-red;
4 | display: block;
5 | margin-top: 5px;
6 | margin-bottom: 0px;
7 | }
8 |
9 | .value {
10 | display: inline-block;
11 | color: $white;
12 | user-select: text;
13 | position: relative;
14 |
15 | &.block {
16 | display: block;
17 | }
18 |
19 | .unit {
20 | margin-left: 0.4em;
21 | font-weight: 300;
22 | color: $text-grey;
23 | user-select: none;
24 | }
25 | }
26 |
27 |
28 | ul {
29 | margin: 1em 0;
30 | padding: 0;
31 | list-style-type: none;
32 | line-height: inherit;
33 |
34 | &.expandable {
35 | line-height: 2;
36 | li {
37 | display: block;
38 | a {
39 | margin-left: 0.5em;
40 | }
41 | &:before {
42 | content: '+';
43 | display: inline-block;
44 | font-weight: 600;
45 | }
46 | }
47 | }
48 |
49 | &.bullets {
50 | line-height: 2;
51 | li {
52 | display: block;
53 | a {
54 | margin-left: 0.5em;
55 | }
56 | &:before {
57 | content: '\2219';
58 | display: inline-block;
59 | font-weight: 600;
60 | }
61 | }
62 | }
63 |
64 |
65 | }
66 |
67 | .separator {
68 | font-weight: 300;
69 | color: $text-grey;
70 | }
71 |
--------------------------------------------------------------------------------
/src/scss/styles.scss:
--------------------------------------------------------------------------------
1 | // Load CSS presets
2 | @import '_normalize';
3 |
4 | // Libraries
5 | @import '_colors';
6 | @import '_interactive';
7 | @import '_breakpoints';
8 | @import '_typography';
9 | @import '_text-styles';
10 | @import '_buttons';
11 | @import '_forms';
12 | @import '_layout';
13 | @import '_mixins';
14 | @import '_helpers';
15 | @import '_general';
16 |
17 | // Components
18 | @import '_cp-menu-bar';
19 | @import '_cp-right-column';
20 | @import '_cp-dialog';
21 | @import '_cp-charts';
22 | @import '_cp-notify';
23 | @import '_cp-cup-history';
24 | @import '_cp-steps';
25 | @import '_cp-wizard';
26 | @import '_cp-tooltip';
27 | @import '_cp-inline-notification';
28 | @import '_cp-slider';
29 | @import '_cp-landing';
30 | @import '_cp-dropdown-menu';
31 | @import '_cp-loading-spinner';
32 | @import '_cp-range-slider';
33 | @import '_cp-modal';
34 | @import '_cp-toggle-switch';
35 | @import '_cp-react-select';
36 | @import '_cp-markdown';
37 | @import '_cp-cup';
38 | @import '_cp-migrate-legacy-cups';
39 | @import '_cp-not-found';
40 | @import '_cp-help';
41 |
42 | // States
43 | @import '_forecast-mode';
44 |
--------------------------------------------------------------------------------
/src/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "contentUrl": "https://content.makerfoundation.com/content/dai-dashboard",
3 | "chain": {
4 | "kovan": {
5 | "nodeURL": "https://kovan.infura.io/v3/078596535bf243c6996d2ac196563d49",
6 | "saiValuesAggregator": "0x040abcb09a5b46f9a5ebed320abe074e6e626cc5",
7 | "otc": "0xe325acb9765b02b8b418199bf9650972299235f4",
8 | "fromBlock": 5216602,
9 | "service": "https://sai-kovan.makerfoundation.com/v1",
10 | "serviceTimeout": 5000,
11 | "chart": false,
12 | "proxyRegistry": "0x64a436ae831c1672ae81f674cab8b6775df3475c",
13 | "saiProxyCreateAndExecute": "0x96fc005a8ba82b84b11e0ff211a2a1362f107ef0",
14 | "tub": "0xa71937147b55deb8a530c7229c442fd3f31b7db2"
15 | },
16 | "main": {
17 | "nodeURL": "https://mainnet.infura.io/v3/078596535bf243c6996d2ac196563d49",
18 | "saiValuesAggregator": "0x83f6ed3d377674186d8898a89d9032216e07e659",
19 | "otc": "0x794e6e91555438afc3ccf1c5076a74f42133d08d",
20 | "fromBlock": 4752013,
21 | "service": "https://sai-mainnet.makerfoundation.com/v1",
22 | "serviceTimeout": 5000,
23 | "chart": false,
24 | "proxyRegistry": "0x4678f0a6958e4d2bc4f1baf7bc52e8f3564f3fe4",
25 | "saiProxyCreateAndExecute": "0x526af336d614ade5cc252a407062b8861af998f5",
26 | "tub": "0x448a5065aebb8e423f0896e6c5d525c040f59af3"
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/stores/Content.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import {observable} from "mobx";
3 | import axios from "axios";
4 | import ReactTooltip from "react-tooltip";
5 | import { compiler } from 'markdown-to-jsx';
6 |
7 | // Utils
8 | import {WAD, formatNumber, fromWei, toWei} from "../utils/helpers";
9 |
10 | // Settings
11 | import * as settings from "../settings";
12 |
13 | // JSON Content
14 | import contentTerms from "../assets/json/terms.json";
15 |
16 | export default class ContentStore {
17 | @observable content = { faq: {}, tooltips: {}, notifications: {} }
18 | @observable contentLoaded = false
19 | @observable showNotification = false
20 |
21 | constructor(rootStore) {
22 | this.rootStore = rootStore;
23 | axios.get(settings.contentUrl)
24 | .then(res => {
25 | this.content = res.data || null;
26 | this.contentLoaded = true;
27 | this.showNotification = false;//!localStorage.getItem(`StabilityFeeChangeAlertClosed-${this.stabilityFeeMarkdown()}`);
28 |
29 | // General notifications
30 | this.content.notifications = {};
31 | for (let key in this.content.faq) {
32 | if (key.substr(0, 13) === 'notification-' && key.substr(-3) === '-en')
33 | this.content.notifications[key] = {
34 | markdown: this.content.faq[key].markdown,
35 | content: compiler(this.content.faq[key].markdown),
36 | show: !localStorage.getItem(`NotificationClosed-${key}-${this.content.faq[key].markdown}`)
37 | };
38 | }
39 |
40 | ReactTooltip.rebuild();
41 | });
42 | }
43 |
44 | replaceVariables = text => {
45 | return text.replace(/\$\{(.+?)\}/g, (match, capture) => {
46 | switch(capture) {
47 | case "stability_fee":
48 | return formatNumber(toWei(fromWei(this.rootStore.system.tub.fee).pow(60 * 60 * 24 * 365)).times(100).minus(toWei(100)), 1) + "%";
49 | case "liquidation_penalty":
50 | return formatNumber(this.rootStore.system.tub.axe.minus(WAD).times(100)) + "%";
51 | case "min_collateralization_ratio":
52 | return formatNumber(this.rootStore.system.tub.mat.times(100)) + "%";
53 | default:
54 | return "?";
55 | }
56 | });
57 | }
58 |
59 | getTooltip = tipKey => {
60 | if (this.content.tooltips && this.content.tooltips.hasOwnProperty(tipKey)) {
61 | let tipText = this.content.tooltips[tipKey]["text"].replace(/\n|\\n/g, " ");
62 | // Does the tooltip text contain variables that need replacing?
63 | if (/\$\{.+?\}/.test(tipText)) tipText = this.replaceVariables(tipText);
64 | return tipText;
65 | }
66 | else return "";
67 | // Solution for having a More Info link rendered using JSX
68 | // Need to submit a PR to react-tooltip or create a fork to add support for this
69 | // if (contentTooltips.hasOwnProperty(tipKey)) {
70 | // const textLines = contentTooltips[tipKey]["text"].split("\n");
71 | // return (
72 | //
73 | // { textLines.map((item, i) => { return {item}{ i !== textLines.length - 1 && } })}
74 | // { " " }
75 | // { contentTooltips[tipKey]["more-info"] && More Info }
76 | //
77 | // );
78 | // }
79 | }
80 |
81 | stabilityFeeMarkdown = () => (this.getHelpItem('stability-fee-information') || {}).markdown
82 | stabilityFeeContent = () => this.stabilityFeeMarkdown() && compiler(this.stabilityFeeMarkdown());
83 | shouldShowStabilityFeeAlert = () => {
84 | return this.showNotification && !!this.stabilityFeeMarkdown
85 | }
86 | hideStabilityFeeContent = () => {
87 | localStorage.setItem(`StabilityFeeChangeAlertClosed-${this.stabilityFeeMarkdown()}`, true);
88 | this.showNotification = false;
89 | }
90 |
91 | getGeneralNotifications = () => this.content.notifications;
92 | hideGeneralNotification = key => {
93 | localStorage.setItem(`NotificationClosed-${key}-${this.content.notifications[key].markdown}`, true);
94 | this.content.notifications[key].show = false;
95 | }
96 | shouldShowGeneralNotifications = () => {
97 | for(let key in this.content.notifications) {
98 | if (this.content.notifications[key].show) return true;
99 | }
100 | return false;
101 | }
102 |
103 | getHelpItem = helpId => {
104 | return this.content.faq[helpId] || null;
105 | }
106 |
107 | getTerms = () => {
108 | return contentTerms.markdown || null;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/stores/Dialog.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import {observable} from "mobx";
3 |
4 | export default class DialogStore {
5 | @observable show = false;
6 | @observable method = null;
7 | @observable cupId = false;
8 | @observable error = "";
9 | @observable warning = "";
10 |
11 | constructor(rootStore) {
12 | this.rootStore = rootStore;
13 | }
14 |
15 | reset = () => {
16 | this.show = false;
17 | this.method = null;
18 | this.cupId = false;
19 | this.error = "";
20 | this.warning = "";
21 | }
22 |
23 | handleOpenDialog = e => {
24 | e.preventDefault();
25 | this.method = e.currentTarget.getAttribute("data-method");
26 | this.cupId = e.currentTarget.getAttribute("data-cup") ? e.currentTarget.getAttribute("data-cup") : false;
27 | this.show = true;
28 | }
29 |
30 | handleCloseDialog = e => {
31 | e.preventDefault();
32 | this.reset();
33 | }
34 |
35 | setError = e => {
36 | this.error = e;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/stores/Profile.jsx:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import {observable} from "mobx";
3 |
4 | // Utils
5 | import * as blockchain from "../utils/blockchain";
6 | import * as daisystem from "../utils/dai-system";
7 |
8 | // Settings
9 | import * as settings from "../settings";
10 |
11 | export default class ProfileStore {
12 | @observable proxy = -1;
13 |
14 | constructor(rootStore) {
15 | this.rootStore = rootStore;
16 | }
17 |
18 | setProxyFromChain = (callbacks = null) => {
19 | return new Promise((resolve, reject) => {
20 | console.debug("Checking proxy...")
21 | daisystem.getContracts(settings.chain[this.rootStore.network.network].proxyRegistry, this.rootStore.network.defaultAccount).then(r => {
22 | if (r && r[2] && this.rootStore.transactions.setLatestBlock(r[0].toNumber())) {
23 | this.setProxy(r[2]);
24 | callbacks && this.rootStore.transactions.executeCallbacks(callbacks);
25 | resolve(r[2]);
26 | } else {
27 | // We force to check again until we get the result
28 | console.debug("Proxy still not found, trying again in 3 seconds...");
29 | setTimeout(() => this.setProxyFromChain(callbacks), 3000);
30 | reject(false);
31 | }
32 | }, () => {
33 | console.debug("Error occurred, trying again in 3 seconds...");
34 | setTimeout(() => this.setProxyFromChain(callbacks), 3000);
35 | reject(false);
36 | });
37 | });
38 | }
39 |
40 | setProxy = proxy => {
41 | this.proxy = proxy !== "0x0000000000000000000000000000000000000000" ? proxy : null;
42 | blockchain.loadObject("dsproxy", this.proxy, "proxy");
43 | console.debug("Found proxy:", this.proxy);
44 | }
45 |
46 | checkProxy = callbacks => {
47 | if (this.proxy) {
48 | this.rootStore.transactions.executeCallbacks(callbacks);
49 | } else {
50 | const title = "Create Proxy";
51 | const params = {value: 0};
52 | if (this.rootStore.network.hw.active) {
53 | params.gas = 1000000;
54 | }
55 | this.rootStore.transactions.askPriceAndSend(title, blockchain.objects.proxyRegistry.build, [], params, [["profile/setProxyFromChain", callbacks]]);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/stores/Root.jsx:
--------------------------------------------------------------------------------
1 | // Stores
2 | import DialogStore from "./Dialog";
3 | import NetworkStore from "./Network";
4 | import ProfileStore from "./Profile";
5 | import SystemStore from "./System";
6 | import TransactionsStore from "./Transactions";
7 | import ContentStore from "./Content";
8 |
9 | // Utils
10 | import * as blockchain from "../utils/blockchain";
11 | import * as daisystem from "../utils/dai-system";
12 | import {isAddress} from "../utils/helpers";
13 |
14 | // Settings
15 | import * as settings from "../settings";
16 |
17 | class RootStore {
18 | constructor() {
19 | this.dialog = new DialogStore(this);
20 | this.network = new NetworkStore(this);
21 | this.profile = new ProfileStore(this);
22 | this.system = new SystemStore(this);
23 | this.transactions = new TransactionsStore(this);
24 | this.content = new ContentStore(this);
25 |
26 | this.interval = null;
27 | this.intervalAggregatedValues = null;
28 | }
29 |
30 | setVariablesInterval = () => {
31 | if (!this.interval) {
32 | this.interval = setInterval(() => {
33 | console.debug("Running variables interval");
34 | this.transactions.setStandardGasPrice();
35 | this.transactions.checkPendingTransactions();
36 | }, 10000);
37 | }
38 |
39 | if (!this.intervalAggregatedValues) {
40 | this.intervalAggregatedValues = setInterval(() => {
41 | console.debug("Running setAggregatedValues interval");
42 | this.system.setAggregatedValues();
43 | }, 5000);
44 | }
45 | }
46 |
47 | _loadContracts = () => {
48 | daisystem.getContracts(settings.chain[this.network.network].proxyRegistry, this.network.defaultAccount).then(r => {
49 | if (r && r[0] && r[1] && isAddress(r[1][0]) && isAddress(r[1][1])) {
50 | const block = r[0].toNumber();
51 | // Make the contracts addresses load a bit more flexible, just checking the node request is bringing data no older than 5 blocks
52 | if (block > this.transactions.latestBlock - 5) {
53 | this.transactions.setLatestBlock(block);
54 | // Set profile proxy and system contracts
55 | this.profile.setProxy(r[2]);
56 | this.system.init(r[1][0], r[1][1], r[1][2], r[1][3], r[1][4], r[1][5], r[1][6], r[1][7], r[1][8], r[1][9], r[1][10], r[1][11]);
57 | this.network.stopLoadingAddress();
58 | this.transactions.setStandardGasPrice();
59 |
60 | this.setVariablesInterval();
61 | } else {
62 | console.debug(`Error loading contracts (latest block ${this.transactions.latestBlock}, request one: ${block}, trying again...`);
63 | this.transactions.addAmountCheck();
64 | setTimeout(this._loadContracts, 2000);
65 | }
66 | } else {
67 | console.debug("Error loading contracts, trying again...");
68 | this.transactions.addAmountCheck();
69 | setTimeout(this._loadContracts, 2000);
70 | }
71 | }, () => {
72 | console.debug("Error loading contracts, trying again...");
73 | setTimeout(this._loadContracts, 2000);
74 | });
75 | }
76 |
77 | loadContracts = () => {
78 | if (this.network.network && !this.network.stopIntervals) {
79 | blockchain.resetFilters(true);
80 | if (typeof this.interval !== "undefined") clearInterval(this.interval);
81 | this.dialog.reset();
82 | this.system.reset();
83 | this.transactions.reset();
84 |
85 | // Check actual block number from 3 different requests (workaround to try to avoid outdated nodes behind load balancer)
86 | const blockPromises = [];
87 | for (let i = 0; i < 3; i++) {
88 | blockPromises.push(blockchain.getBlockNumber());
89 | }
90 |
91 | Promise.all(blockPromises).then(r => {
92 | r.forEach(block => this.transactions.setLatestBlock(block)); // Will set the maximum value
93 |
94 | blockchain.loadObject("proxyregistry", settings.chain[this.network.network].proxyRegistry, "proxyRegistry");
95 | blockchain.loadObject("saivaluesaggregator", settings.chain[this.network.network].saiValuesAggregator, "saiValuesAggregator");
96 |
97 | this._loadContracts();
98 | })
99 | }
100 | }
101 | }
102 |
103 | const store = new RootStore();
104 | export default store;
105 |
--------------------------------------------------------------------------------
/src/utils/address-generator.js:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import ethUtil from "ethereumjs-util";
3 | import HDKey from "hdkey";
4 |
5 | export default class AddressGenerator {
6 | constructor(data) {
7 | this.hdk = new HDKey();
8 | this.hdk.publicKey = new Buffer(data.publicKey, "hex");
9 | this.hdk.chainCode = new Buffer(data.chainCode, "hex");
10 | }
11 |
12 | getAddressString = index => {
13 | let derivedKey = this.hdk.derive(`m/${index}`);
14 | let address = ethUtil.publicToAddress(derivedKey.publicKey, true);
15 | let addressString = "0x" + address.toString("hex");
16 | return addressString;
17 | }
18 | }
--------------------------------------------------------------------------------
/src/utils/analytics.js:
--------------------------------------------------------------------------------
1 | import mixpanel from 'mixpanel-browser';
2 | import ReactGA from 'react-ga';
3 |
4 | const env = process.env.NODE_ENV === 'production' ? 'prod' : 'test';
5 | const config = {
6 | test: {
7 | userSnap: {
8 | token: 'def2ae23-a9a8-4f11-85e6-5346cb86d4f2',
9 | config: {
10 | fields: {
11 | email: null
12 | }
13 | }
14 | },
15 | mixpanel: {
16 | token: '4ff3f85397ffc3c6b6f0d4120a4ea40a',
17 | config: { debug: true, ip: false }
18 | },
19 | gaTrackingId: 'UA-128164213-2'
20 | },
21 | prod: {
22 | mixpanel: {
23 | token: 'a030d8845e34bfdc11be3d9f3054ad67',
24 | config: { ip: false }
25 | },
26 | gaTrackingId: 'UA-128164213-1',
27 | userSnap: {
28 | token: 'def2ae23-a9a8-4f11-85e6-5346cb86d4f2',
29 | config: {
30 | fields: {
31 | email: null
32 | }
33 | }
34 | }
35 | }
36 | }[env];
37 |
38 | export const mixpanelInit = () => {
39 | console.debug(
40 | `[Mixpanel] Tracking initialized for ${env} env using ${
41 | config.mixpanel.token
42 | }`
43 | );
44 | mixpanel.init(config.mixpanel.token, config.mixpanel.config);
45 | mixpanel.track('Pageview', { product: 'scd-cdp-portal' });
46 | };
47 |
48 | export const mixpanelIdentify = (id, props = null) => {
49 | if (typeof mixpanel.config === 'undefined') return;
50 | console.debug(
51 | `[Mixpanel] Identifying as ${id} ${props && props.wallet ? `using wallet ${props.wallet}` : ''}`
52 | );
53 | mixpanel.identify(id);
54 | if (props) mixpanel.people.set(props);
55 | };
56 |
57 | export const userSnapInit = () => {
58 | // already injected
59 | if (document.getElementById('usersnap-script')) return;
60 |
61 | window.onUsersnapLoad = function(api) {
62 | api.init(config.userSnap.config);
63 | window.Usersnap = api;
64 | };
65 |
66 | const scriptUrl = `//api.usersnap.com/load/${
67 | config.userSnap.token
68 | }.js?onload=onUsersnapLoad`;
69 | const script = document.createElement('script');
70 | script.id = 'usersnap-script';
71 | script.src = scriptUrl;
72 | script.async = true;
73 |
74 | document.getElementsByTagName('head')[0].appendChild(script);
75 | };
76 |
77 | export const gaInit = () => {
78 | console.debug(
79 | `[GA] Tracking initialized for ${env} env using ${config.gaTrackingId}`
80 | );
81 | ReactGA.initialize(config.gaTrackingId);
82 | };
83 |
--------------------------------------------------------------------------------
/src/utils/web3.js:
--------------------------------------------------------------------------------
1 | // Libraries
2 | import Web3 from "web3";
3 | import * as Web3ProviderEngine from "web3-provider-engine/dist/es5";
4 | import * as RpcSource from "web3-provider-engine/dist/es5/subproviders/rpc";
5 | import Transport from "@ledgerhq/hw-transport-u2f";
6 | import checkIsMobile from "ismobilejs";
7 |
8 | // Utils
9 | import LedgerSubProvider from "./ledger-subprovider";
10 | import TrezorSubProvider from "./trezor-subprovider";
11 |
12 | // Settings
13 | import * as settings from "../settings";
14 |
15 | export const getWebClientProviderName = () => {
16 | if (window.imToken)
17 | return "imtoken";
18 |
19 | if (window.ethereum && window.ethereum.isStatus)
20 | return "status";
21 |
22 | if (!window.web3 || typeof window.web3.currentProvider === "undefined")
23 | return "";
24 |
25 | if (window.web3.currentProvider.isAlphaWallet)
26 | return "alphawallet";
27 |
28 | if (window.activeProvider && window.activeProvider.isWalletLink)
29 | return "walletlink";
30 |
31 | if (window.web3.currentProvider.isMetaMask && checkIsMobile.any)
32 | return "metamask-mobile";
33 |
34 | if (window.web3.currentProvider.isMetaMask)
35 | return "metamask";
36 |
37 | if (window.web3.currentProvider.isTrust)
38 | return "trust";
39 |
40 | if (window.web3.currentProvider.isQbao)
41 | return "qbao";
42 |
43 | if (window.web3.currentProvider.isBitpie)
44 | return "bitpie";
45 |
46 | if (typeof window.SOFA !== "undefined")
47 | return "coinbase";
48 |
49 | if (typeof window.__CIPHER__ !== "undefined")
50 | return "cipher";
51 |
52 | if (window.web3.currentProvider.constructor.name === "EthereumProvider")
53 | return "mist";
54 |
55 | if (window.web3.currentProvider.constructor.name === "Web3FrameProvider")
56 | return "parity";
57 |
58 | if (window.web3.currentProvider.host && window.web3.currentProvider.host.indexOf("infura") !== -1)
59 | return "infura";
60 |
61 | if (window.web3.currentProvider.host && window.web3.currentProvider.host.indexOf("localhost") !== -1)
62 | return "localhost";
63 |
64 | return "other";
65 | };
66 |
67 | class Web3Extended extends Web3 {
68 | stop = () => {
69 | this.reset();
70 | if (this.currentProvider && typeof this.currentProvider.stop === "function") {
71 | this.currentProvider.stop();
72 | }
73 | }
74 |
75 | setHWProvider = (device, network, path, accountsOffset = 0, accountsLength = 1) => {
76 | this.stop();
77 | return new Promise(async (resolve, reject) => {
78 | try {
79 | const networkId = network === "main" ? 1 : (network === "kovan" ? 42 : "");
80 | this.setProvider(new Web3ProviderEngine());
81 | const hwWalletSubProvider = device === "ledger"
82 | ? LedgerSubProvider(async () => await Transport.create(), {networkId, path, accountsOffset, accountsLength})
83 | : TrezorSubProvider({networkId, path, accountsOffset, accountsLength});
84 | this.currentProvider.name = device;
85 | this.currentProvider.addProvider(hwWalletSubProvider);
86 | this.currentProvider.addProvider(new RpcSource({rpcUrl: settings.chain[network].nodeURL}));
87 | this.currentProvider.start();
88 | this.useLogs = false;
89 | resolve(true);
90 | } catch(e) {
91 | reject(e);
92 | }
93 | });
94 | }
95 |
96 | setWebClientWeb3 = (specificProvider = null) => {
97 | this.stop();
98 | return new Promise(async (resolve, reject) => {
99 | try {
100 | if (specificProvider) {
101 | try {
102 | if (typeof specificProvider.enable === 'function') {
103 | await specificProvider.enable();
104 | }
105 | resolve(specificProvider);
106 | } catch (error) {
107 | reject(new Error("User denied account access"));
108 | }
109 | } else if (window.web3 || window.ethereum) {
110 | try {
111 | let provider;
112 | if (window.ethereum) {
113 | await window.ethereum.enable();
114 | provider = window.ethereum;
115 | } else {
116 | provider = window.web3.currentProvider;
117 | }
118 | resolve(provider);
119 | } catch (error) {
120 | reject(new Error("User denied account access"));
121 | }
122 | } else {
123 | reject(new Error("No client"));
124 | }
125 | } catch(e) {
126 | reject(e);
127 | }
128 | });
129 | }
130 |
131 | setWebClientProvider = provider => {
132 | return new Promise(async (resolve, reject) => {
133 | try {
134 | this.setProvider(provider);
135 | this.useLogs = false;
136 | window.activeProvider = provider;
137 | this.currentProvider.name = getWebClientProviderName();
138 | resolve(true);
139 | } catch (error) {
140 | reject(new Error("Error setting provider"));
141 | }
142 | });
143 | }
144 | }
145 |
146 | const web3 = new Web3Extended();
147 | window.web3Provider = web3;
148 |
149 | export default web3;
150 |
--------------------------------------------------------------------------------