diff --git a/__mocks__/react-web3-settings.js b/__mocks__/react-web3-settings.js new file mode 100644 index 00000000..67dfe550 --- /dev/null +++ b/__mocks__/react-web3-settings.js @@ -0,0 +1,16 @@ +export const getWeb3Settings = () => ({ + eth: 'https://cloudflare-eth.com/', + eos: 'https://corsproxy.ptokens.io/v1/?apiurl=https://eos.greymass.com', + telos: 'https://telos.eosphere.io', + libre: 'https://libre-node-2.ptokens.io:8889', + bsc: 'https://bsc-dataseed1.binance.org/', + xdai: 'https://rpc.xdaichain.com/', + polygon: 'https://polygon-rpc.com/', + ultra: 'https://corsproxy.ptokens.io/v1/?apiurl=http://ultra-mainnet-1.ptokens.io:8888', + arbitrum: 'https://arb1.arbitrum.io/rpc', + luxochain: 'https://corsproxy.ptokens.io/v1/?apiurl=https://lugano.nodes.luxochain.io', + algorand: 'https://algorand-node-1.ptokens.io', + ftm: 'https://rpc.ftm.tools/', + ore: 'https://ore-node-1.ptokens.io', + btc: 'https://blockstream.info/api/', +}) diff --git a/package.json b/package.json index 388759a1..8380690b 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "react-step-progress-bar": "^1.0.3", "react-switch": "^7.0.0", "react-tooltip": "^4.4.2", + "react-web3-settings": "github:pnetwork-association/react-web3-settings#feat/sections", "reactstrap": "^9.1.6", "redux": "^4.2.1", "redux-thunk": "^2.4.2", diff --git a/src/components/molecules/version/Version.jsx b/src/components/molecules/version/Version.jsx index 364542a6..ae3ab3db 100644 --- a/src/components/molecules/version/Version.jsx +++ b/src/components/molecules/version/Version.jsx @@ -1,4 +1,5 @@ import React from 'react' +import { Web3SettingsButton } from 'react-web3-settings' import styled from 'styled-components' const VersionDiv = styled.div` @@ -6,23 +7,52 @@ const VersionDiv = styled.div` position: fixed; bottom: 0; right: 0; - padding-right: 30px; - padding-bottom: 10px; + padding-right: 1rem; + padding-bottom: 1rem; ` -const VersionContainer = styled.p` +const ContainerOptions = styled.div` justify-content: right !important; display: flex; - color: ${({ theme }) => theme.text2}; - font-size: 13px; + @media (max-width: 767.98px) { + display: none; + } +` + +const VersionButton = styled.button` + width: auto; + color: white; + border-radius: 3px; + font-size: 15px; + font-weight: 300; + height: 40px; + border: 0; + padding-left: 10px; + padding-right: 10px; + font-weight: 400; + border-radius: 10px; + outline: none !important; + background: ${({ theme }) => theme.secondary4}; + &:hover { + background: ${({ theme }) => theme.secondary4Hovered}; + } + color: ${({ theme }) => theme.text1}; + @media (max-width: 767.98px) { + height: 35px; + } ` export default function Version() { + const githubLink = + 'https://github.com/pnetwork-association/ptokens-dapp/tree/' + import.meta.env.VITE_REACT_APP_GIT_SHA return ( - - - Version: {import.meta.env.VITE_REACT_APP_GIT_SHA} - + + + window.open(githubLink, '_blank', 'noopener,noreferrer')}> + Version: {import.meta.env.VITE_REACT_APP_GIT_SHA} + + + ) } diff --git a/src/components/organisms/header/Header.jsx b/src/components/organisms/header/Header.jsx index 8a853b53..2c4a1c24 100644 --- a/src/components/organisms/header/Header.jsx +++ b/src/components/organisms/header/Header.jsx @@ -6,6 +6,7 @@ import Walletinfo from '../walletInfoModal/WalletInfoModal' import { useWallets } from '../../../hooks/use-wallets' import Icon from '../../atoms/icon/Icon' import settings from '../../../settings' +import { Web3SettingsButton } from 'react-web3-settings' const HeaderWrapper = styled.div` border-bottom: 1px solid rgba(0, 0, 0, 0.1); @@ -294,6 +295,7 @@ const Header = (_props) => { icon={theme === 'light' ? 'sun' : 'moon'} onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')} > + diff --git a/src/components/organisms/settings/Settings.jsx b/src/components/organisms/settings/Settings.jsx new file mode 100644 index 00000000..a32cbe26 --- /dev/null +++ b/src/components/organisms/settings/Settings.jsx @@ -0,0 +1,117 @@ +import React, { useContext } from 'react' +import { Web3SettingsProvider } from 'react-web3-settings' +import { ThemeContext } from 'styled-components' + +import settings from '../../../settings' +import generateSettings from '../../../settings/utils' + +const SettingsDrawer = ({ children }) => { + const theme = useContext(ThemeContext) + + const buttonSaveStyle = { + color: 'white', + background: `${theme.primary1}`, + fontSize: '16px', + borderRadius: '10px', + border: '0', + padding: '5px 10px 5px 10px', + } + + const buttonResetStyle = { + color: 'white', + background: `${theme.secondary2}`, + fontSize: '16px', + borderRadius: '10px', + border: '0', + padding: '5px 10px 5px 10px', + marginLeft: '10px', + } + + const titleStyle = { + color: `${theme.text1}`, + fontSize: '1.5rem', + fontWeight: '500', + } + + const drawerStyle = { + background: `${theme.bg1}`, + display: 'flex', + flexDirection: 'column', + } + + const bodyStyle = { + overflowY: 'auto', + marginBottom: '4.3rem', + } + + const headerStyle = { + paddingBottom: '0px', + } + + const inputStyle = { + border: '0', + outline: '0px !important', + WebkitAppearance: 'none', + boxShadow: 'none !important', + textAlign: 'left', + fontSize: '16px', + color: `${theme.secondary1}`, + width: '75%', + marginLeft: '1rem', + background: `${theme.secondary4}`, + borderRadius: '5px', + } + + const sectionLabelStyle = { + color: `${theme.text1}`, + fontSize: '1.25rem', + fontWeight: '350', + marginBottom: '0px', + } + + const sectionRowStyle = { + marginTop: '2.5rem', + } + + const settingRowStyle = { + color: `${theme.text2}`, + marginTop: '1rem', + display: 'flex', + justifyContent: 'space-between', + } + + const buttonAreaStyle = { + position: 'absolute', + bottom: '0px', + right: '1rem', + marginBottom: '1rem', + } + + const labelStyle = { + marginTop: '0.25rem', + marginBottom: '0.25rem', + } + + return ( + + {children} + + ) +} + +export default SettingsDrawer diff --git a/src/main.jsx b/src/main.jsx index cd4cf66f..0718258d 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -13,6 +13,7 @@ import 'react-responsive-carousel/lib/styles/carousel.min.css' import './theme/font.css' import './theme/bootstrap.css' import { initialize } from './ga4' +import SettingsDrawer from './components/organisms/settings/Settings' initialize() @@ -28,7 +29,9 @@ root.render( - + + + diff --git a/src/settings/__tests__/utils.test.js b/src/settings/__tests__/utils.test.js new file mode 100644 index 00000000..7613f4d6 --- /dev/null +++ b/src/settings/__tests__/utils.test.js @@ -0,0 +1,34 @@ +import { test, describe, expect } from 'vitest' +import generateRpcSettings from '../utils' + +describe('generateRpcSettings', () => { + test('Should generate a setting object for https://www.npmjs.com/package/react-web3-settings', () => { + const settings = { + eos: { + chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', + host: 'https://eos.greymass.com', + port: 443, + protocol: 'https', + endpoint: 'https://corsproxy.ptokens.io/v1/?apiurl=https://eos.greymass.com', + label: 'Eos', + }, + ftm: { + endpoint: 'https://rpc.ftm.tools/', + chainId: 250, + label: 'Ftm', + }, + } + const expected = { + eos: { + label: 'Eos', + value: 'https://corsproxy.ptokens.io/v1/?apiurl=https://eos.greymass.com', + }, + ftm: { + label: 'Ftm', + value: 'https://rpc.ftm.tools/', + }, + } + const res = generateRpcSettings(settings) + expect(res).toStrictEqual(expected) + }) +}) diff --git a/src/settings/index.js b/src/settings/index.js index 6468c3cc..a9f5d299 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -71,6 +71,7 @@ const settings = { eth: { endpoint: 'https://cloudflare-eth.com/', chainId: 1, + label: 'Ethereum', }, eos: { chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', @@ -78,6 +79,7 @@ const settings = { port: 443, protocol: 'https', endpoint: 'https://corsproxy.ptokens.io/v1/?apiurl=https://eos.greymass.com', + label: 'EOS', }, telos: { chainId: '4667b205c6838ef70ff7988f6e8257e8be0e1284a2f59699054a018f743b1d11', @@ -85,6 +87,7 @@ const settings = { port: 443, protocol: 'https', endpoint: 'https://telos.eosphere.io', + label: 'Telos', }, libre: { chainId: '38b1d7815474d0c60683ecbea321d723e83f5da6ae5f1c1f9fecc69d9ba96465', @@ -92,18 +95,22 @@ const settings = { port: 443, protocol: 'https', endpoint: 'https://libre-node-2.ptokens.io:8889', + label: 'Libre', }, bsc: { endpoint: 'https://bsc-dataseed1.binance.org/', chainId: 56, + label: 'BSC', }, xdai: { endpoint: 'https://rpc.xdaichain.com/', chainId: 100, + label: 'xDAI', }, polygon: { endpoint: 'https://polygon-rpc.com/', chainId: 137, + label: 'Polygon', }, ultra: { chainId: 'a9c481dfbc7d9506dc7e87e9a137c931b0a9303f64fd7a1d08b8230133920097', @@ -111,23 +118,28 @@ const settings = { port: 443, protocol: 'https', endpoint: 'https://corsproxy.ptokens.io/v1/?apiurl=http://ultra-mainnet-1.ptokens.io:8888', + label: 'Ultra', }, arbitrum: { endpoint: 'https://arb1.arbitrum.io/rpc', chainId: 42161, + label: 'Arbitrum', }, luxochain: { endpoint: 'https://corsproxy.ptokens.io/v1/?apiurl=https://lugano.nodes.luxochain.io', chainId: 110, + label: 'Luxochain', }, algorand: { token: '4950dcab89ddc2e7f4dd8e51deb2f0c44aa37aab18cbfd8242ac5fb697222342', port: 443, endpoint: 'https://algorand-node-1.ptokens.io', + label: 'Algorand', }, ftm: { endpoint: 'https://rpc.ftm.tools/', chainId: 250, + label: 'Fantom', }, ore: { chainId: '7900eaca71d5b213d3e1e15d54d98ad235a7a5b8166361be78e672edeeb2b47a', @@ -135,9 +147,11 @@ const settings = { port: 443, protocol: 'https', endpoint: 'https://ore-node-1.ptokens.io', + label: 'ORE', }, btc: { endpoint: 'https://blockstream.info/api/', + label: 'Bitcoin', }, }, }, diff --git a/src/settings/utils.js b/src/settings/utils.js new file mode 100644 index 00000000..39319b9d --- /dev/null +++ b/src/settings/utils.js @@ -0,0 +1,11 @@ +const generateRpcSettings = (settings) => + Object.assign( + {}, + Object.fromEntries( + Object.entries(settings).map(([key, val]) => { + return [key, { label: val.label, value: val.endpoint }] + }) + ) + ) + +export default generateRpcSettings diff --git a/src/store/swap/__tests__/swap.actions.test.js b/src/store/swap/__tests__/swap.actions.test.js index 1f4e33cf..a0ffa8c4 100644 --- a/src/store/swap/__tests__/swap.actions.test.js +++ b/src/store/swap/__tests__/swap.actions.test.js @@ -13,6 +13,7 @@ import algosdk from 'algosdk' describe('swap', () => { beforeAll(() => { vi.mock('ptokens-node') + vi.mock('react-web3-settings') }) beforeEach(() => { diff --git a/src/theme/ThemeProvider.jsx b/src/theme/ThemeProvider.jsx index 17214728..42b1500d 100644 --- a/src/theme/ThemeProvider.jsx +++ b/src/theme/ThemeProvider.jsx @@ -95,6 +95,63 @@ input[type=number] { line-height: 0.9; } +.api-icon { + stroke-width: 1; + height: 28px; + width: 28px; +} + +.api-icon-mobile { + stroke-width: 1; + height: 23px; + width: 23px; +} + +.api-button { + width: 40px; + color: white; + border-radius: 3px; + font-size: 15px; + font-weight: 300; + height: 40px; + border: 0; + margin-left: 10px; + font-weight: 500; + border-radius: 10px; + outline: none !important; + background: ${({ theme }) => theme.secondary4}; + &:hover { + background: ${({ theme }) => theme.secondary4Hovered}; + } + color: ${({ theme }) => theme.text1}; + @media (max-width: 767.98px) { + height: 35px; + } +} + +.api-button-mobile { + width: 35px; + color: white; + border-radius: 3px; + font-size: 15px; + font-weight: 300; + height: 35px; + border: 0; + padding: 0; + margin-left: 10px; + font-weight: 500; + border-radius: 10px; + outline: none !important; + background: ${({ theme }) => theme.secondary4}; + &:hover { + background: ${({ theme }) => theme.secondary4Hovered}; + } + color: ${({ theme }) => theme.text1}; + @media (max-width: 767.98px) { + height: 35px; + } +} + .navbar-nav .dropdown-menu { position: absolute; float: none; diff --git a/src/utils/read-only-providers.js b/src/utils/read-only-providers.js index 395bbe74..2297993b 100644 --- a/src/utils/read-only-providers.js +++ b/src/utils/read-only-providers.js @@ -1,56 +1,56 @@ -import settings from '../settings' import Web3 from 'web3' import { JsonRpc } from 'eosjs' import fetch from 'cross-fetch' import { Algodv2 } from 'algosdk' +import { getWeb3Settings } from 'react-web3-settings' + +import settings from '../settings' const getReadOnlyProviderByBlockchain = (_blockchain) => { // TODO: only mainnet at the moment + const configs = getWeb3Settings() + if (_blockchain === 'ETH') { - return new Web3.providers.HttpProvider(settings.rpc.mainnet.eth.endpoint) + return new Web3.providers.HttpProvider(configs.eth) } if (_blockchain === 'BSC') { - return new Web3.providers.HttpProvider(settings.rpc.mainnet.bsc.endpoint) + return new Web3.providers.HttpProvider(configs.bsc) } if (_blockchain === 'POLYGON') { - return new Web3.providers.HttpProvider(settings.rpc.mainnet.polygon.endpoint) + return new Web3.providers.HttpProvider(configs.polygon) } if (_blockchain === 'XDAI') { - return new Web3.providers.HttpProvider(settings.rpc.mainnet.xdai.endpoint) + return new Web3.providers.HttpProvider(configs.xdai) } if (_blockchain === 'EOS') { - return new JsonRpc(settings.rpc.mainnet.eos.endpoint, { fetch }) + return new JsonRpc(configs.eos, { fetch }) } if (_blockchain === 'TELOS') { - return new JsonRpc(settings.rpc.mainnet.telos.endpoint, { fetch }) + return new JsonRpc(configs.telos, { fetch }) } if (_blockchain === 'LIBRE') { - return new JsonRpc(settings.rpc.mainnet.libre.endpoint, { fetch }) + return new JsonRpc(configs.libre, { fetch }) } if (_blockchain === 'ULTRA') { - return new JsonRpc(settings.rpc.mainnet.ultra.endpoint, { fetch }) + return new JsonRpc(configs.ultra, { fetch }) } if (_blockchain === 'ORE') { - return new JsonRpc(settings.rpc.mainnet.ore.endpoint, { fetch }) + return new JsonRpc(configs.ore, { fetch }) } if (_blockchain === 'ARBITRUM') { - return new Web3.providers.HttpProvider(settings.rpc.mainnet.arbitrum.endpoint) + return new Web3.providers.HttpProvider(configs.arbitrum) } if (_blockchain === 'LUXOCHAIN') { - return new Web3.providers.HttpProvider(settings.rpc.mainnet.luxochain.endpoint) + return new Web3.providers.HttpProvider(configs.luxochain) } if (_blockchain === 'ALGORAND') { - return new Algodv2( - settings.rpc.mainnet.algorand.token, - settings.rpc.mainnet.algorand.endpoint, - settings.rpc.mainnet.algorand.port - ) + return new Algodv2(settings.rpc.mainnet.algorand.token, configs.algorand, settings.rpc.mainnet.algorand.port) } if (_blockchain === 'FTM') { - return new Web3.providers.HttpProvider(settings.rpc.mainnet.ftm.endpoint) + return new Web3.providers.HttpProvider(configs.ftm) } if (_blockchain === 'BTC') { - return settings.rpc.mainnet.btc.endpoint + return configs.btc } return null }