├── .firebaserc
├── packages
└── react-app
│ ├── .eslintignore
│ ├── public
│ ├── robots.txt
│ ├── favicon.ico
│ ├── manifest.json
│ ├── index.html
│ └── 404.html
│ ├── jsconfig.json
│ ├── .prettierrc
│ ├── src
│ ├── index.jsx
│ ├── Routes.jsx
│ ├── components
│ │ ├── index.js
│ │ ├── ConnectWeb3.jsx
│ │ ├── Container.jsx
│ │ ├── Header.jsx
│ │ ├── AvailableLiquidity.jsx
│ │ └── Modal.jsx
│ ├── styles
│ │ ├── globals.css
│ │ └── Home.module.css
│ ├── lib
│ │ ├── network.js
│ │ └── rpc.js
│ ├── pages
│ │ ├── Home.jsx
│ │ └── Layout.jsx
│ ├── App.jsx
│ ├── theme.js
│ ├── utils
│ │ └── index.js
│ ├── assets
│ │ ├── logo.svg
│ │ ├── bg-pattern.svg
│ │ ├── 1hive.svg
│ │ ├── poweredby.svg
│ │ ├── logo-text.svg
│ │ ├── connext.svg
│ │ └── powered-by.svg
│ └── contexts
│ │ └── Web3Context.jsx
│ ├── .eslintrc.js
│ ├── package.json
│ └── README.md
├── firebase.json
├── .github
└── workflows
│ ├── firebase-hosting-pull-request.yml
│ └── firebase-hosting-merge.yml
├── package.json
├── LICENSE
├── .gitignore
└── README.md
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "hive-flora"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/react-app/.eslintignore:
--------------------------------------------------------------------------------
1 | serviceWorker.js
2 | build/
3 | node_modules/
4 | public/
--------------------------------------------------------------------------------
/packages/react-app/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/packages/react-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1Hive/xpollinate/HEAD/packages/react-app/public/favicon.ico
--------------------------------------------------------------------------------
/packages/react-app/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./src"
4 | },
5 | "exclude": ["node_modules"]
6 | }
--------------------------------------------------------------------------------
/packages/react-app/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true,
6 | "bracketSpacing": true
7 | }
--------------------------------------------------------------------------------
/packages/react-app/src/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import { App } from './App';
5 |
6 | ReactDOM.render(, document.getElementById('root'));
7 |
--------------------------------------------------------------------------------
/packages/react-app/src/Routes.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Redirect, Route, Switch } from 'react-router-dom';
3 |
4 | import { Home } from 'pages/Home';
5 |
6 | export const Routes = () => (
7 |
8 |
9 |
10 |
11 | );
12 |
--------------------------------------------------------------------------------
/packages/react-app/src/components/index.js:
--------------------------------------------------------------------------------
1 | export { default as Header } from './Header.jsx';
2 | export { default as Modal } from './Modal.jsx';
3 | export { default as Container } from './Container.jsx';
4 | export { default as ConnectWeb3 } from './ConnectWeb3.jsx';
5 | export { default as AvailableLiquidity } from './AvailableLiquidity.jsx';
6 |
--------------------------------------------------------------------------------
/packages/react-app/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/react-app/src/lib/network.js:
--------------------------------------------------------------------------------
1 | export default function networkName(id) {
2 | switch (Number(id)) {
3 | case 56:
4 | return 'Binance Smart Chain';
5 | case 100:
6 | return 'xDai Network';
7 | case 137:
8 | return 'Matic Network';
9 | case 250:
10 | return 'Fantom Opera';
11 | default:
12 | return 'Unsupported Network';
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "packages/react-app/build",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ],
9 | "rewrites": [
10 | {
11 | "source": "**",
12 | "destination": "/index.html"
13 | }
14 | ]
15 | }
16 | }
--------------------------------------------------------------------------------
/packages/react-app/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Eth App",
3 | "name": "Create Eth App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
--------------------------------------------------------------------------------
/packages/react-app/src/pages/Home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Text } from '@chakra-ui/react';
3 | import { Container } from 'components/index';
4 |
5 | export const Home = (props) => (
6 |
7 |
14 | Cross-Chain Bridge
15 |
16 |
17 |
18 | );
19 |
--------------------------------------------------------------------------------
/packages/react-app/src/lib/rpc.js:
--------------------------------------------------------------------------------
1 | export default function getRpcUrl(networkId) {
2 | switch (networkId) {
3 | case 56:
4 | return 'https://bsc-dataseed1.ninicoin.io/';
5 | case 100:
6 | return 'https://xdai.poanetwork.dev/';
7 | case 128:
8 | return 'https://http-mainnet.hecochain.com/';
9 | case 137:
10 | return 'https://polygon-mainnet.infura.io/v3/e02a34c8aa5d4156aeed1142ea2173c8';
11 | case 250:
12 | return 'https://rpc.ftm.tools/';
13 | default:
14 | throw new Error('No RPC configured for network: ', networkId);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/react-app/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { ChakraProvider, CSSReset } from '@chakra-ui/react';
2 | import React from 'react';
3 | import { BrowserRouter as Router } from 'react-router-dom';
4 |
5 | import { Web3Provider } from 'contexts/Web3Context';
6 | import { Routes } from './Routes';
7 | import { Layout } from './pages/Layout';
8 | import { theme } from './theme';
9 |
10 | export const App = () => {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/.github/workflows/firebase-hosting-pull-request.yml:
--------------------------------------------------------------------------------
1 | # This file was auto-generated by the Firebase CLI
2 | # https://github.com/firebase/firebase-tools
3 |
4 | name: Deploy to Firebase Hosting on PR
5 | 'on': pull_request
6 | jobs:
7 | build_and_preview:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - run: yarn install --frozen-lockfile && yarn react-app:build
12 | - uses: FirebaseExtended/action-hosting-deploy@v0
13 | with:
14 | repoToken: '${{ secrets.GITHUB_TOKEN }}'
15 | firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_HIVE_FLORA }}'
16 | projectId: hive-flora
17 | env:
18 | FIREBASE_CLI_PREVIEWS: hostingchannels
19 |
--------------------------------------------------------------------------------
/packages/react-app/src/pages/Layout.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import styles from 'styles/Home.module.css';
3 | import { Web3Context } from 'contexts/Web3Context';
4 | import { Container } from '@chakra-ui/react';
5 | import { Header, ConnectWeb3 } from 'components/index';
6 |
7 | export const Layout = ({ children }) => {
8 | const { account } = useContext(Web3Context);
9 | const valid = !!account;
10 |
11 | // eslint-disable-next-line no-console
12 | // console.log(valid, account, providerChainId);
13 |
14 | return (
15 |
16 |
17 |
18 | {valid ? children : }
19 |
20 |
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/.github/workflows/firebase-hosting-merge.yml:
--------------------------------------------------------------------------------
1 | # This file was auto-generated by the Firebase CLI
2 | # https://github.com/firebase/firebase-tools
3 |
4 | name: Deploy to Firebase Hosting on merge
5 | 'on':
6 | push:
7 | branches:
8 | - main
9 | jobs:
10 | build_and_deploy:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 | - run: yarn install --frozen-lockfile && yarn react-app:build
15 | - uses: FirebaseExtended/action-hosting-deploy@v0
16 | with:
17 | repoToken: '${{ secrets.GITHUB_TOKEN }}'
18 | firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_HIVE_FLORA }}'
19 | channelId: live
20 | projectId: hive-flora
21 | env:
22 | FIREBASE_CLI_PREVIEWS: hostingchannels
23 |
--------------------------------------------------------------------------------
/packages/react-app/src/theme.js:
--------------------------------------------------------------------------------
1 | import chakraTheme from '@chakra-ui/theme';
2 |
3 | export const theme = {
4 | ...chakraTheme,
5 | styles: {
6 | ...chakraTheme.styles,
7 | global: {
8 | body: {
9 | bg: 'linear-gradient(118.5deg, #F2F3FB 13.9%, #F2F3FB 94.36%)',
10 | bgImage:
11 | // eslint-disable-next-line quotes
12 | "url('https://storage.googleapis.com/1hive/xpollinate/bg-pattern.svg')",
13 | backgroundRepeat: 'no-repeat',
14 | backgroundAttachment: 'fixed',
15 | backgroundPosition: 'center',
16 | backgroundSize: 'cover',
17 | },
18 | },
19 | },
20 | colors: {
21 | ...chakraTheme.colors,
22 | },
23 | fonts: {
24 | ...chakraTheme.fonts,
25 | body: 'Manrope, sans-serif',
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@1hive-connext/monorepo",
3 | "version": "1.0.0",
4 | "keywords": [
5 | "ethereum",
6 | "react",
7 | "workspaces",
8 | "yarn"
9 | ],
10 | "private": true,
11 | "scripts": {
12 | "react-app:build": "yarn workspace @1hive-connext/react-app build",
13 | "react-app:eject": "yarn workspace @1hive-connext/react-app eject",
14 | "react-app:ipfs": "yarn workspace @1hive-connext/react-app ipfs",
15 | "react-app:lint": "yarn workspace @1hive-connext/react-app lint",
16 | "react-app:start": "yarn workspace @1hive-connext/react-app start",
17 | "react-app:test": "yarn workspace @1hive-connext/react-app test",
18 | "react-app:deploy": "yarn workspace @1hive-connext/react-app build && firebase deploy"
19 | },
20 | "workspaces": {
21 | "nohoist": [
22 | "**/@graphprotocol/graph-ts",
23 | "**/@graphprotocol/graph-ts/**"
24 | ],
25 | "packages": [
26 | "packages/*"
27 | ]
28 | }
29 | }
--------------------------------------------------------------------------------
/packages/react-app/src/utils/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Shorten an Ethereum address. `charsLength` allows to change the number of
3 | * characters on both sides of the ellipsis.
4 | *
5 | * Examples:
6 | * shortenAddress('0x19731977931271') // 0x1973…1271
7 | * shortenAddress('0x19731977931271', 2) // 0x19…71
8 | * shortenAddress('0x197319') // 0x197319 (already short enough)
9 | *
10 | * @param {string} address The address to shorten
11 | * @param {number} [charsLength=4] The number of characters to change on both sides of the ellipsis
12 | * @returns {string} The shortened address
13 | */
14 | export function shortenAddress(address, charsLength = 4) {
15 | const prefixLength = 2; // "0x"
16 |
17 | if (!address) {
18 | return '';
19 | }
20 | if (address.length < charsLength * 2 + prefixLength) {
21 | return address;
22 | }
23 | return (
24 | address.slice(0, charsLength + prefixLength) +
25 | '…' +
26 | address.slice(-charsLength)
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/packages/react-app/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | es6: true,
4 | node: true,
5 | jest: true,
6 | },
7 | rules: {
8 | 'prettier/prettier': 'warn',
9 | 'no-console': 'warn',
10 | 'comma-spacing': 'error',
11 | semi: ['error', 'always'],
12 | quotes: ['error', 'single'],
13 | eqeqeq: 'error',
14 | 'no-alert': 'error',
15 | curly: 'error',
16 | 'brace-style': ['error', '1tbs'],
17 | 'object-curly-spacing': ['error', 'always'],
18 | 'function-call-argument-newline': ['error', 'consistent'],
19 | 'one-var-declaration-per-line': ['error', 'always'],
20 | 'padding-line-between-statements': [
21 | 'error',
22 | {
23 | blankLine: 'always',
24 | prev: ['const', 'let', 'var'],
25 | next: '*',
26 | },
27 | {
28 | blankLine: 'any',
29 | prev: ['const', 'let', 'var'],
30 | next: ['const', 'let', 'var'],
31 | },
32 | ],
33 | },
34 | plugins: ['prettier'],
35 | extends: ['react-app', 'plugin:prettier/recommended', 'prettier/react'],
36 | };
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 1Hive
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | firebase-debug.log*
8 | firebase-debug.*.log*
9 |
10 | # Firebase cache
11 | .firebase/
12 |
13 | # Firebase config
14 |
15 | # Uncomment this if you'd like others to create their own Firebase project.
16 | # For a team working on the same Firebase project(s), it is recommended to leave
17 | # it commented so all members can deploy to the same project(s) in .firebaserc.
18 | # .firebaserc
19 |
20 | # Runtime data
21 | pids
22 | *.pid
23 | *.seed
24 | *.pid.lock
25 |
26 | # Directory for instrumented libs generated by jscoverage/JSCover
27 | lib-cov
28 |
29 | # Coverage directory used by tools like istanbul
30 | coverage
31 |
32 | # nyc test coverage
33 | .nyc_output
34 |
35 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
36 | .grunt
37 |
38 | # Bower dependency directory (https://bower.io/)
39 | bower_components
40 |
41 | # node-waf configuration
42 | .lock-wscript
43 |
44 | # Compiled binary addons (http://nodejs.org/api/addons.html)
45 | build/Release
46 |
47 | # Dependency directories
48 | node_modules/
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Optional REPL history
57 | .node_repl_history
58 |
59 | # Output of 'npm pack'
60 | *.tgz
61 |
62 | # Yarn Integrity file
63 | .yarn-integrity
64 |
65 | # dotenv environment variables file
66 | .env
67 |
68 | # production
69 | build
70 |
--------------------------------------------------------------------------------
/packages/react-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
24 | xPollinate
25 |
26 |
27 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## XPollinate
3 |
4 | XPollinate is a cross-chain bridge that allows users to connect their Web3 wallets and swap assets between different networks, such as xDai Chain, Matic Mainnet, Fantom Mainnet and Binance Smart Chain Mainnet.
5 |
6 | ## Project Structure
7 |
8 | The default template is a monorepo created with [Yarn Workspaces](https://classic.yarnpkg.com/en/docs/workspaces/).
9 |
10 | Workspaces makes it possible to setup multiple packages in such a way that we only need to run `yarn install` once to install all of them in
11 | a single pass. Dependencies are hoisted at the root.
12 |
13 | Owing to this dependency on Yarn Workspaces, this repository can't be used with npm.
14 |
15 | ## Available Scripts
16 |
17 | In the project directory, you can run:
18 |
19 | #### `yarn`
20 |
21 | Installs dependencies
22 |
23 | #### `yarn react-app:start`
24 |
25 | Runs the React app in development mode.
26 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
27 |
28 | The page will automatically reload if you make changes to the code.
29 | You will see the build errors and lint warnings in the console.
30 |
31 | #### `yarn react-app:test`
32 |
33 | Runs the React test watcher in an interactive mode.
34 | By default, runs tests related to files changed since the last commit.
35 |
36 | [Read more about testing React.](https://facebook.github.io/create-react-app/docs/running-tests)
37 |
38 | #### `yarn react-app:build`
39 |
40 | Builds the React app for production to the `build` folder.
41 | It correctly bundles React in production mode and optimizes the build for the best performance.
42 |
43 | The build is minified and the filenames include the hashes.
44 | Your app is ready to be deployed!
45 |
46 | See the React documentation on [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
47 |
--------------------------------------------------------------------------------
/packages/react-app/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Page Not Found
7 |
8 |
23 |
24 |
25 |
26 |
404
27 |
Page Not Found
28 |
The specified file was not found on this website. Please check the URL for mistakes and try again.
29 |
Why am I seeing this?
30 |
This page was generated by the Firebase Command-Line Interface. To modify it, edit the 404.html file in your project's configured public directory.
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/packages/react-app/src/components/ConnectWeb3.jsx:
--------------------------------------------------------------------------------
1 | import { Button, Flex, Text, Image, Center } from '@chakra-ui/react';
2 | import React, { useContext } from 'react';
3 |
4 | import { Web3Context } from 'contexts/Web3Context';
5 |
6 | const styles = {
7 | 'bold-gradient':
8 | 'linear-gradient(257.5deg, #EB0055 -39.73%, #FFFA80 107.97%)',
9 | 'light-gradient':
10 | 'linear-gradient(257.5deg, rgba(235, 0, 85, 0.3) -39.73%, rgba(255, 250, 128, 0.3) 107.97%)',
11 | };
12 |
13 | const ConnectWeb3 = () => {
14 | const { connectWeb3, loading, account, disconnect } = useContext(Web3Context);
15 |
16 | return (
17 |
18 |
29 |
33 |
34 | Please, connect your wallet.
35 |
36 | {account && !loading ? (
37 |
40 | ) : (
41 |
54 | )}
55 |
56 |
57 | );
58 | };
59 |
60 | export default ConnectWeb3;
61 |
--------------------------------------------------------------------------------
/packages/react-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@1hive-connext/react-app",
3 | "version": "1.0.0",
4 | "homepage": "./",
5 | "browserslist": {
6 | "production": [
7 | ">0.2%",
8 | "not dead",
9 | "not op_mini all"
10 | ],
11 | "development": [
12 | "last 1 chrome version",
13 | "last 1 firefox version",
14 | "last 1 safari version"
15 | ]
16 | },
17 | "dependencies": {
18 | "@apollo/react-hooks": "^3.1.5",
19 | "@chakra-ui/icons": "^1.0.12",
20 | "@chakra-ui/react": "^1.3.3",
21 | "@connext/vector-modal": "^1.0.6-beta.6",
22 | "@connext/vector-types": "^0.2.5-beta.18",
23 | "@connext/vector-utils": "^0.2.5-beta.18",
24 | "@emotion/react": "^11.1.5",
25 | "@emotion/styled": "^11.1.5",
26 | "@ethersproject/contracts": "^5.2.0",
27 | "@ethersproject/providers": "^5.2.0",
28 | "@material-ui/core": "^4.11.3",
29 | "@testing-library/dom": "^6.16.0",
30 | "@testing-library/jest-dom": "^4.2.4",
31 | "@testing-library/react": "^9.5.0",
32 | "@testing-library/user-event": "^7.2.1",
33 | "@types/react": "^16.9.53",
34 | "@walletconnect/web3-provider": "^1.3.1",
35 | "apollo-boost": "^0.4.9",
36 | "apollo-client": "^2.6.10",
37 | "apollo-utilities": "^1.3.3",
38 | "babel-eslint": "^10.1.0",
39 | "chalk": "^4.1.0",
40 | "emotion-theming": "^11.0.0",
41 | "eslint": "^6.8.0",
42 | "eslint-plugin-flowtype": "^4.6.0",
43 | "ethers": "^5.0.29",
44 | "framer-motion": "^3.5.2",
45 | "graphql": "^14.7.0",
46 | "ipfs-http-client": "^45.0.0",
47 | "react": "16.14.0",
48 | "react-dom": "16.14.0",
49 | "react-router-dom": "^5.2.0",
50 | "react-scripts": "3.4.3",
51 | "styled-components": "^5.2.0",
52 | "web3modal": "^1.9.1"
53 | },
54 | "devDependencies": {
55 | "eslint": "^6.8.0",
56 | "eslint-config-prettier": "^7.2.0",
57 | "eslint-config-react-app": "^5.2.0",
58 | "eslint-import-resolver-alias": "^1.1.2",
59 | "eslint-plugin-import": "^2.20.1",
60 | "eslint-plugin-prettier": "^3.3.1",
61 | "eslint-plugin-react": "^7.22.0",
62 | "prettier": "^2.2.1"
63 | },
64 | "eslintConfig": {
65 | "extends": "react-app"
66 | },
67 | "scripts": {
68 | "build": "react-scripts build",
69 | "eject": "react-scripts eject",
70 | "ipfs": "yarn build && node scripts/ipfs.js",
71 | "start": "react-scripts start",
72 | "test": "react-scripts test",
73 | "lint": "eslint --fix --ext .js,.jsx ."
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/packages/react-app/src/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | min-height: 10vh;
3 | padding: 0 0.5rem;
4 | margin: 5rem;
5 | display: flex;
6 | flex-direction: column;
7 | justify-content: center;
8 | align-items: center;
9 | }
10 |
11 | .header {
12 | width: 80%;
13 | margin: 20px auto;
14 | }
15 |
16 | .main {
17 | padding: 5rem 0;
18 | flex: 1;
19 | display: flex;
20 | flex-direction: column;
21 | justify-content: center;
22 | align-items: center;
23 | }
24 |
25 | .footer {
26 | width: 100%;
27 | height: 100px;
28 | border-top: 1px solid #eaeaea;
29 | display: flex;
30 | justify-content: center;
31 | align-items: center;
32 | }
33 |
34 | .footer img {
35 | margin-left: 0.5rem;
36 | }
37 |
38 | .footer a {
39 | display: flex;
40 | justify-content: center;
41 | align-items: center;
42 | }
43 |
44 | .title a {
45 | color: #0070f3;
46 | text-decoration: none;
47 | }
48 |
49 | .title a:hover,
50 | .title a:focus,
51 | .title a:active {
52 | text-decoration: underline;
53 | }
54 |
55 | .title {
56 | margin: 0;
57 | line-height: 1.15;
58 | font-size: 4rem;
59 | }
60 |
61 | .title,
62 | .description {
63 | text-align: center;
64 | }
65 |
66 | .description {
67 | line-height: 1.5;
68 | font-size: 1.5rem;
69 | }
70 |
71 | .code {
72 | background: #fafafa;
73 | border-radius: 5px;
74 | padding: 0.75rem;
75 | font-size: 1.1rem;
76 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
77 | Bitstream Vera Sans Mono, Courier New, monospace;
78 | }
79 |
80 | .grid {
81 | display: flex;
82 | align-items: center;
83 | justify-content: center;
84 | flex-wrap: wrap;
85 | max-width: 800px;
86 | margin-top: 3rem;
87 | }
88 |
89 | .card {
90 | margin: 1rem;
91 | flex-basis: 45%;
92 | padding: 1.5rem;
93 | text-align: left;
94 | color: inherit;
95 | text-decoration: none;
96 | border: 1px solid #eaeaea;
97 | border-radius: 10px;
98 | transition: color 0.15s ease, border-color 0.15s ease;
99 | }
100 |
101 | .card:hover,
102 | .card:focus,
103 | .card:active {
104 | color: #0070f3;
105 | border-color: #0070f3;
106 | }
107 |
108 | .card h3 {
109 | margin: 0 0 1rem 0;
110 | font-size: 1.5rem;
111 | }
112 |
113 | .card p {
114 | margin: 0;
115 | font-size: 1.25rem;
116 | line-height: 1.5;
117 | }
118 |
119 | .logo {
120 | height: 1em;
121 | }
122 |
123 | @media (max-width: 600px) {
124 | .grid {
125 | width: 100%;
126 | flex-direction: column;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/packages/react-app/src/components/Container.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Modal, AvailableLiquidity } from 'components/index';
3 | import { useMediaQuery, Box, Flex, Image } from '@chakra-ui/react';
4 |
5 | const DISABLED = false;
6 |
7 | const Container = () => {
8 | const [isLargerThan1280] = useMediaQuery('(min-width: 1280px)');
9 |
10 | return (
11 |
12 |
23 |
24 |
25 |
34 | {DISABLED
35 | ? 'We are experiencing some issues with the bridge, we will be back soon.'
36 | : 'This is beta software! Use at your own risk.'}
37 |
38 |
48 |
49 |
50 |
83 |
84 | );
85 | };
86 |
87 | export default Container;
88 |
--------------------------------------------------------------------------------
/packages/react-app/src/components/Header.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { Box, Flex, Button, Image } from '@chakra-ui/react';
3 | import { Web3Context } from 'contexts/Web3Context';
4 | import networkName from 'lib/network';
5 | import { shortenAddress } from 'utils/index';
6 | import { Link } from '@chakra-ui/react';
7 | import { ExternalLinkIcon } from '@chakra-ui/icons';
8 |
9 | const styles = {
10 | gradient: 'linear-gradient(257.5deg, #EB0055 -39.73%, #FFFA80 107.97%)',
11 | };
12 |
13 | const Header = (props) => {
14 | const { account, providerChainId } = useContext(Web3Context);
15 |
16 | return (
17 |
30 |
35 |
42 |
51 | {networkName(providerChainId)}
52 |
53 |
54 | {account ? (
55 |
66 | ) : (
67 |
79 | )}
80 |
81 |
82 |
83 | }
93 | >
94 | Support
95 |
96 |
97 |
98 |
99 | );
100 | };
101 |
102 | export default Header;
103 |
--------------------------------------------------------------------------------
/packages/react-app/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
43 |
--------------------------------------------------------------------------------
/packages/react-app/README.md:
--------------------------------------------------------------------------------
1 | # @project/react-app
2 |
3 | This package is a fork of the default template provided by [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `yarn start`
10 |
11 | Runs the app in development mode.
12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
13 |
14 | The page will automatically reload if you make changes to the code.
15 | You will see the build errors and lint warnings in the console.
16 |
17 | ### `yarn test`
18 |
19 | Runs the test watcher in an interactive mode.
20 | By default, runs tests related to files changed since the last commit.
21 |
22 | [Read more about testing.](https://facebook.github.io/create-react-app/docs/running-tests)
23 |
24 | ### `yarn build`
25 |
26 | Builds the app for production to the `build` folder.
27 | It correctly bundles React in production mode and optimizes the build for the best performance.
28 |
29 | The build is minified and the filenames include the hashes.
30 | Your app is ready to be deployed!
31 |
32 | See the React documentation on [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
33 |
34 | ### `yarn react-app:eject`
35 |
36 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
37 |
38 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` the React app at any time. This command will
39 | remove the single build dependency from your React package.
40 |
41 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right
42 | into your project so you have full control over them. All of the commands except `eject` will still work, but
43 | they will point to the copied scripts so you can tweak them. At this point you’re on your own.
44 |
45 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
46 |
47 | ## Learn More
48 |
49 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
50 |
51 | To learn React, check out the [React documentation](https://reactjs.org/).
52 |
53 | ### Code Splitting
54 |
55 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
56 |
57 | ### Analyzing the Bundle Size
58 |
59 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
60 |
61 | ### Making a Progressive Web App
62 |
63 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
64 |
65 | ### Advanced Configuration
66 |
67 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
68 |
69 | ### Deployment
70 |
71 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
72 |
73 | ### `yarn build` fails to minify
74 |
75 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
76 |
--------------------------------------------------------------------------------
/packages/react-app/src/contexts/Web3Context.jsx:
--------------------------------------------------------------------------------
1 | import WalletConnectProvider from '@walletconnect/web3-provider';
2 | import { ethers } from 'ethers';
3 | import React, { useCallback, useEffect, useState } from 'react';
4 | import Web3 from 'web3';
5 | import Web3Modal from 'web3modal';
6 |
7 | import getRPCUrl from 'lib/rpc';
8 |
9 | export const Web3Context = React.createContext({});
10 |
11 | const providerOptions = {
12 | walletconnect: {
13 | package: WalletConnectProvider,
14 | options: {
15 | rpc: {
16 | 100: getRPCUrl(100),
17 | 137: getRPCUrl(137),
18 | },
19 | },
20 | },
21 | };
22 |
23 | const web3Modal = new Web3Modal({
24 | cacheProvider: true,
25 | providerOptions,
26 | });
27 |
28 | export const Web3Provider = ({ children }) => {
29 | const [web3State, setWeb3State] = useState({});
30 | const { providerChainId, ethersProvider, web3Provider } = web3State;
31 | const [account, setAccount] = useState();
32 | const [balance, setBalance] = useState();
33 | const [loading, setLoading] = useState(true);
34 |
35 | const setWeb3Provider = useCallback(async (prov, updateAccount = false) => {
36 | try {
37 | if (prov) {
38 | const web3Provider = new Web3(prov);
39 | const provider = new ethers.providers.Web3Provider(
40 | web3Provider.currentProvider
41 | );
42 |
43 | const providerNetwork = await provider.getNetwork();
44 |
45 | setWeb3State({
46 | ethersProvider: provider,
47 | web3Provider: prov,
48 | providerChainId: providerNetwork.chainId,
49 | });
50 | if (updateAccount) {
51 | const signer = provider.getSigner();
52 | const gotAccount = await signer.getAddress();
53 | const gotBalance = await signer.getBalance();
54 |
55 | setAccount(gotAccount);
56 | setBalance(gotBalance);
57 | }
58 | }
59 | } catch (error) {
60 | // eslint-disable-next-line no-console
61 | console.log({ web3ModalError: error });
62 | }
63 | }, []);
64 |
65 | const connectWeb3 = useCallback(async () => {
66 | try {
67 | setLoading(true);
68 | const modalProvider = await web3Modal.connect();
69 |
70 | await setWeb3Provider(modalProvider, true);
71 |
72 | // Subscribe to accounts change
73 | modalProvider.on('accountsChanged', (accounts) => {
74 | setAccount(accounts[0]);
75 | });
76 |
77 | // Subscribe to chainId change
78 | modalProvider.on('chainChanged', (_chainId) => {
79 | setWeb3Provider(modalProvider);
80 | });
81 | } catch (error) {
82 | // eslint-disable-next-line no-console
83 | console.log({ web3ModalError: error });
84 | }
85 | setLoading(false);
86 | }, [setWeb3Provider]);
87 |
88 | const disconnect = useCallback(async () => {
89 | web3Modal.clearCachedProvider();
90 | setAccount();
91 | setWeb3State({});
92 | }, []);
93 |
94 | useEffect(() => {
95 | if (window.ethereum) {
96 | window.ethereum.autoRefreshOnNetworkChange = false;
97 | }
98 | if (web3Modal.cachedProvider) {
99 | connectWeb3();
100 | } else {
101 | setLoading(false);
102 | }
103 | }, [connectWeb3]);
104 |
105 | return (
106 |
118 | {children}
119 |
120 | );
121 | };
122 |
--------------------------------------------------------------------------------
/packages/react-app/src/components/AvailableLiquidity.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import Table from '@material-ui/core/Table';
3 | import TableBody from '@material-ui/core/TableBody';
4 | import TableCell from '@material-ui/core/TableCell';
5 | import TableContainer from '@material-ui/core/TableContainer';
6 | import TableHead from '@material-ui/core/TableHead';
7 | import TableRow from '@material-ui/core/TableRow';
8 | import { providers, constants, Contract, utils } from 'ethers';
9 | import { getSignerAddressFromPublicIdentifier } from '@connext/vector-utils';
10 | import { ERC20Abi } from '@connext/vector-types';
11 |
12 | import getRpcUrl from '../lib/rpc';
13 | import networkName from '../lib/network';
14 | import { NETWORKS, CONNEXT_ROUTER } from './Modal';
15 |
16 | const AvailableLiquidity = () => {
17 | const [tableData, setTableData] = useState([]);
18 | const [loadingData, setLoadingData] = useState(true);
19 |
20 | useEffect(() => {
21 | const effect = async () => {
22 | const signerAddress =
23 | getSignerAddressFromPublicIdentifier(CONNEXT_ROUTER);
24 | const _tableData = [];
25 |
26 | for (const network of NETWORKS) {
27 | // eslint-disable-next-line no-console
28 | console.log('network: ', network);
29 | const chainProvider = new providers.JsonRpcProvider(
30 | getRpcUrl(network.chainId)
31 | );
32 |
33 | for (const [assetName, assetId] of Object.entries(network.assets)) {
34 | let onchainBalance;
35 | let decimals = 18;
36 |
37 | try {
38 | if (assetId === constants.AddressZero) {
39 | onchainBalance = await chainProvider.getBalance(signerAddress);
40 | } else {
41 | const tokenContract = new Contract(
42 | assetId,
43 | ERC20Abi,
44 | chainProvider
45 | );
46 |
47 | onchainBalance = await tokenContract.balanceOf(signerAddress);
48 | decimals = await tokenContract.decimals();
49 | }
50 | } catch (e) {
51 | // eslint-disable-next-line no-console
52 | console.error(
53 | `Couldn't get balance or decimals for asset ${assetName}:${assetId} on chain ${network.chainId}`,
54 | e
55 | );
56 | }
57 |
58 | const row = {
59 | chain: networkName(network.chainId),
60 | assetName,
61 | balance: onchainBalance
62 | ? utils.formatUnits(onchainBalance, decimals)
63 | : '-',
64 | };
65 |
66 | // eslint-disable-next-line no-console
67 | console.log('table row: ', row);
68 | _tableData.push(row);
69 | }
70 | }
71 |
72 | setTableData(_tableData);
73 | setLoadingData(false);
74 | };
75 |
76 | effect();
77 | }, []);
78 | return (
79 |
80 |
81 |
82 |
83 | Destination Chain
84 | Asset
85 | Exit Liquidity
86 |
87 |
88 |
89 | {loadingData ? (
90 | {'Loading...'}
91 | ) : (
92 | tableData.map((row, index) => (
93 |
94 |
95 | {row.chain}
96 |
97 | {row.assetName}
98 |
99 | {parseFloat(row.balance).toFixed(2).toString()}
100 |
101 |
102 | ))
103 | )}
104 |
105 |
106 |
107 | );
108 | };
109 |
110 | export default AvailableLiquidity;
111 |
--------------------------------------------------------------------------------
/packages/react-app/src/assets/bg-pattern.svg:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/packages/react-app/src/assets/1hive.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/packages/react-app/src/assets/poweredby.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/packages/react-app/src/assets/logo-text.svg:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/packages/react-app/src/components/Modal.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import React, { useState, useContext, useEffect } from 'react';
3 | import { Web3Context } from 'contexts/Web3Context';
4 | import { ConnextModal } from '@connext/vector-modal';
5 | import { ArrowUpDownIcon } from '@chakra-ui/icons';
6 | import {
7 | Button,
8 | Grid,
9 | Select,
10 | GridItem,
11 | Input,
12 | Text,
13 | IconButton,
14 | Center,
15 | Circle,
16 | } from '@chakra-ui/react';
17 | import { useHistory, useLocation } from 'react-router-dom';
18 | import getRpcUrl from 'lib/rpc';
19 |
20 | export const CONNEXT_ROUTER =
21 | 'vector5AGCU8oedG9HDmrC7mU9fDyQkpVRovFtEauVq3fHGcmRdbg7iu';
22 |
23 | export const NETWORKS = [
24 | {
25 | assetId: '0x0000000000000000000000000000000000000000',
26 | chainName: 'xDai Chain',
27 | chainId: 100,
28 | assets: {
29 | DAI: '0x0000000000000000000000000000000000000000',
30 | USDC: '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83',
31 | USDT: '0x4ECaBa5870353805a9F068101A40E0f32ed605C6',
32 | },
33 | },
34 | {
35 | assetId: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
36 | chainName: 'Matic Mainnet',
37 | chainId: 137,
38 | assets: {
39 | DAI: '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063',
40 | USDC: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174',
41 | USDT: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
42 | },
43 | },
44 | {
45 | assetId: '0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3',
46 | chainName: 'Fantom Mainnet',
47 | chainId: 250,
48 | assets: {
49 | DAI: '0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e',
50 | USDC: '0x04068da6c83afcfa0e13ba15a6696662335d5b75',
51 | USDT: '0x049d68029688eabf473097a2fc38ef61633a3c7a',
52 | },
53 | },
54 | {
55 | assetId: '0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3',
56 | chainName: 'Binance Smart Chain Mainnet',
57 | chainId: 56,
58 | assets: {
59 | DAI: '0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3',
60 | USDC: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
61 | USDT: '0x55d398326f99059fF775485246999027B3197955',
62 | },
63 | },
64 | ];
65 |
66 | export const ASSETS = ['DAI', 'USDC', 'USDT'];
67 |
68 | function useQuery() {
69 | return new URLSearchParams(useLocation().search);
70 | }
71 |
72 | function getQueryParams(query) {
73 | return {
74 | senderChainId: Number(query.get('senderChainId')),
75 | receiverChainId: Number(query.get('receiverChainId')),
76 | _asset: query.get('asset'),
77 | };
78 | }
79 |
80 | const Modal = ({ disabled }) => {
81 | const history = useHistory();
82 | const { senderChainId, receiverChainId, _asset } = getQueryParams(useQuery());
83 | const { web3Provider, account } = useContext(Web3Context);
84 | const [showModal, setShowModal] = useState(false);
85 | const [withdrawalAddress, setWithdrawalAddress] = useState(account);
86 | const [helperText, setHelperText] = useState(undefined);
87 | const [senderOpen, setSenderOpen] = useState(false);
88 | const [receiverOpen, setReceiverOpen] = useState(false);
89 | const [assetOpen, setAssetOpen] = useState(false);
90 | const [asset, setAsset] = useState(
91 | _asset && ASSETS.indexOf(_asset.toUpperCase()) >= 0
92 | ? _asset.toUpperCase()
93 | : ASSETS[0]
94 | );
95 | const [senderChain, setSenderChain] = useState(
96 | (senderChainId && NETWORKS.find((n) => n.chainId === senderChainId)) ||
97 | NETWORKS[0]
98 | );
99 | const [receiverChain, setReceiverChain] = useState(
100 | (receiverChainId && NETWORKS.find((n) => n.chainId === receiverChainId)) ||
101 | NETWORKS[1]
102 | );
103 | const [showButton, setShowButton] = useState(!disabled);
104 |
105 | useEffect(() => {
106 | history.push({
107 | search: `?asset=${asset}&senderChainId=${senderChain.chainId}&receiverChainId=${receiverChain.chainId}`,
108 | });
109 | }, [asset, senderChain, receiverChain, history]);
110 |
111 | const isValidAddress = (input) => {
112 | const valid = input.match(/0x[0-9a-fA-F]{40}/);
113 |
114 | return !!valid;
115 | };
116 |
117 | const handleChange = (event) => {
118 | const [addr, shouldShowButton] = event.target.value.split('-secret');
119 |
120 | if (!isValidAddress(addr.trim())) {
121 | setHelperText('Must be an Ethereum address');
122 | setShowButton(false);
123 | return;
124 | } else {
125 | setHelperText(undefined);
126 | }
127 |
128 | setShowButton(disabled ? shouldShowButton !== undefined : true);
129 | setWithdrawalAddress(addr.trim());
130 | };
131 |
132 | const handleSubmit = (values) => {
133 | const errors = { receiverAddress: '' };
134 |
135 | if (!values.receiverAddress) {
136 | errors.receiverAddress = 'Required';
137 | }
138 | return errors;
139 | };
140 |
141 | const swapChains = () => {
142 | const s = senderChain;
143 | const r = receiverChain;
144 |
145 | setSenderChain(r);
146 | setReceiverChain(s);
147 | };
148 |
149 | return (
150 | <>
151 |
257 |
258 | {helperText && (
259 |
260 |
261 |
262 | {helperText}
263 |
264 |
265 |
266 | )}
267 |
268 |
269 |
270 |
306 |
307 |
308 |
309 | {web3Provider !== 'undefined' ? (
310 | setShowModal(false)}
319 | depositChainProvider={getRpcUrl(senderChain.chainId)}
320 | withdrawChainProvider={getRpcUrl(receiverChain.chainId)}
321 | injectedProvider={web3Provider}
322 | loginProvider={window.ethereum}
323 | />
324 | ) : (
325 | Loading...
326 | )}
327 | >
328 | );
329 | };
330 |
331 | export default Modal;
332 |
--------------------------------------------------------------------------------
/packages/react-app/src/assets/connext.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/packages/react-app/src/assets/powered-by.svg:
--------------------------------------------------------------------------------
1 |
26 |
--------------------------------------------------------------------------------