Skip to content

Commit 133f4d5

Browse files
Multichain (#9)
* Multichain config added --------- Co-authored-by: Amir Habibzadeh <[email protected]>
1 parent 8c4d5d8 commit 133f4d5

File tree

16 files changed

+230
-48
lines changed

16 files changed

+230
-48
lines changed

.env.example

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
PORT=3000
22
CHOKIDAR_USEPOLLING=true
3-
REACT_APP_BASE_URL=""
43
REACT_APP_WALLET_CONNECT_PROJECT_ID=""
5-
REACT_APP_ALCHEMY_ID=""
4+
REACT_APP_ALCHEMY_ID=""
5+
6+
#DEFAULT
7+
REACT_APP_DEFAULT_CHAIN_ID=
8+
REACT_APP_DEFAULT_BASE_URL=
9+
10+
#MATIC_MAIN
11+
REACT_APP_MAIN_MATIC_BASE_URL=
12+
13+
#MATIC_TEST
14+
REACT_APP_TEST_MATIC_BASE_URL=
15+
16+
#ETHERIUM
17+
REACT_APP_MAIN_ETHERIUM_BASE_URL=
18+

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ module.exports = {
2323
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
2424
// e.g. "@typescript-eslint/explicit-function-return-type": "off",
2525
},
26-
}
26+
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ We have extended the functionality of the original CoreUI template by adding web
88
- Axios - Axios is a simple promise based HTTP client for the browser and node.js. Axios provides a simple to use library in a small package with a very extensible interface.
99
- Redux - For state management.
1010
- Redux Saga - For managing side effects, such as fetching blockchain data.
11+
- Multichain config - configs are set by chain.
1112

1213
The CoreUI template already utilizes React and Bootstrap to provide a robust admin template with a wide range of UI components.
1314

src/components/AppHeader.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react'
1+
import React, { useEffect } from 'react'
22
import { NavLink } from 'react-router-dom'
33
import {
44
CContainer,
@@ -12,14 +12,19 @@ import {
1212
} from '@coreui/react'
1313
import CIcon from '@coreui/icons-react'
1414
import { cilBell, cilEnvelopeOpen, cilList, cilMenu } from '@coreui/icons'
15-
import { useToggleSidebar } from '../redux/modules/init'
15+
import { useToggleSidebar, useInit } from '../redux/modules/init/slice'
1616
import { AppBreadcrumb } from './index'
1717
import { AppHeaderDropdown } from './header/index'
1818
import { logo } from 'src/assets/brand/logo'
1919
import { WalletButton } from './rainbow/index'
2020

2121
const AppHeader = () => {
2222
const { toggleSidebar } = useToggleSidebar()
23+
const { dispatchInit } = useInit()
24+
25+
useEffect(() => {
26+
dispatchInit()
27+
}, [])
2328

2429
return (
2530
<CHeader position="sticky" className="mb-4">

src/components/AppSidebar.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { sygnet } from 'src/assets/brand/sygnet'
88
import SimpleBar from 'simplebar-react'
99
import 'simplebar/dist/simplebar.min.css'
1010
import navigation from '../_nav'
11-
import { useToggleSidebar } from '../redux/modules/init'
11+
import { useToggleSidebar } from '../redux/modules/init/slice'
1212

1313
const AppSidebar = () => {
1414
const unfoldable = useSelector((state) => state.sidebarUnfoldable)

src/components/rainbow/button.js

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,50 @@
11
import React, { useEffect } from 'react'
22
import { CButton } from '@coreui/react'
3-
import { useSelector } from 'react-redux'
43
import { RainbowKitProvider, ConnectButton } from '@rainbow-me/rainbowkit'
54
import { configureChains, useAccount, useNetwork } from 'wagmi'
6-
import { mainnet, polygon, optimism, arbitrum, zora } from 'wagmi/chains'
5+
import { mainnet, polygon, polygonMumbai } from 'wagmi/chains'
76
import { alchemyProvider } from 'wagmi/providers/alchemy'
87
import { useGetNonce } from '../../redux/modules/userNonce'
9-
import { useRemoveToken } from '../../redux/modules/userSign'
8+
import { useUserSign } from '../../redux/modules/userSign'
109
import { publicProvider } from 'wagmi/providers/public'
1110
import '@rainbow-me/rainbowkit/styles.css'
1211

1312
const apiKey = process.env.REACT_APP_ALCHEMY_ID
14-
15-
const supportedChains = [mainnet, polygon, optimism, arbitrum, zora]
13+
const supportedChains = [mainnet, polygon, polygonMumbai]
1614
const providers = [alchemyProvider({ apiKey }), publicProvider()]
1715
const { chains } = configureChains(supportedChains, providers)
1816

1917
const RainbowButton = () => {
2018
const { address } = useAccount()
2119
const { chain } = useNetwork()
22-
const { dispatchGetNonce } = useGetNonce()
23-
const { dispatchRemoveToken } = useRemoveToken()
24-
const userToken = useSelector((state) => state.userSign?.data?.access_token)
20+
const { dispatchGetNonce, loading: userNonceLoading } = useGetNonce()
21+
const { dispatchRemoveToken, userSign, loading: userSignLoading } = useUserSign()
22+
const userToken = userSign?.access_token
23+
const isLoading = userNonceLoading || userSignLoading
2524

2625
useEffect(() => {
27-
handleEffectLogic(address, chain, dispatchGetNonce, dispatchRemoveToken)
28-
}, [address, chain, dispatchGetNonce, dispatchRemoveToken])
29-
30-
const handleEffectLogic = (address, chain, dispatchGetNonce, dispatchRemoveToken) => {
31-
if (address) {
32-
dispatchGetNonce(address)
33-
} else {
34-
dispatchRemoveToken()
35-
}
3626
if (chain) {
3727
dispatchRemoveToken()
3828
}
39-
}
29+
}, [chain, dispatchRemoveToken])
4030

41-
const handleSignInWallet = () => {
42-
handleEffectLogic(address, chain, dispatchGetNonce, dispatchRemoveToken)
31+
const handleSignInWallet = async () => {
32+
try {
33+
await dispatchGetNonce(address)
34+
} catch (error) {
35+
console.error('Error signing in:', error)
36+
}
4337
}
4438

45-
const showSignInWalletButton = !userToken && address
39+
const showSignInWalletButton = !userToken && address && !chain.unsupported
4640
return (
4741
<>
4842
{showSignInWalletButton && (
49-
<CButton color="light" className="mx-2" onClick={handleSignInWallet}>
50-
Sign In Wallet
43+
<CButton color="light" className="mx-2" onClick={handleSignInWallet} disabled={isLoading}>
44+
{isLoading ? 'Signing In...' : 'Sign In Wallet'}
5145
</CButton>
5246
)}
53-
<RainbowKitProvider chains={chains}>
47+
<RainbowKitProvider chains={chains} initialChain={process.env.REACT_APP_DEFAULT_CHAIN_ID}>
5448
<ConnectButton label="Connect Wallet" />
5549
</RainbowKitProvider>
5650
</>

src/components/rainbow/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
import React from 'react'
44
import { getDefaultWallets } from '@rainbow-me/rainbowkit'
55
import { configureChains, createConfig, WagmiConfig } from 'wagmi'
6-
import { mainnet, polygon, optimism, arbitrum, zora } from 'wagmi/chains'
6+
import { mainnet, polygon, polygonMumbai } from 'wagmi/chains'
77
import { alchemyProvider } from 'wagmi/providers/alchemy'
88
import { publicProvider } from 'wagmi/providers/public'
99
import RainBowButton from './button'
1010

1111
const { chains, publicClient } = configureChains(
12-
[mainnet, polygon, optimism, arbitrum, zora],
12+
[mainnet, polygon, polygonMumbai],
1313
[alchemyProvider({ apiKey: process.env.REACT_APP_ALCHEMY_ID }), publicProvider()],
1414
)
1515

src/redux/modules/init/saga.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { put, take, takeEvery } from 'redux-saga/effects'
2+
import { watchAppNetwrok } from '../web3/slice'
3+
import { initApp, initAppCompleted } from './slice'
4+
export function* watchInitApp() {
5+
try {
6+
yield put(watchAppNetwrok())
7+
yield take(watchAppNetwrok)
8+
yield put(initAppCompleted())
9+
} catch (e) {
10+
console.log(e, 'error in init app')
11+
}
12+
}
13+
14+
export function* initSagas() {
15+
yield takeEvery(initApp, watchInitApp)
16+
}

src/redux/modules/init/index.js renamed to src/redux/modules/init/slice.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ const initSlice = createSlice({
1313
setSidebarShow: (state) => {
1414
state.sidebarShow = !state.sidebarShow
1515
},
16+
initApp: (state) => {
17+
state.loading = true
18+
},
19+
initAppCompleted: (state) => {
20+
state.loading = false
21+
},
1622
},
1723
})
1824

@@ -27,5 +33,24 @@ export function useToggleSidebar() {
2733
return { sidebarShow, toggleSidebar }
2834
}
2935

30-
export const { setSidebarShow } = initSlice.actions
36+
export function useInit() {
37+
const initState = useSelector((state) => state.init)
38+
const dispatch = useDispatch()
39+
40+
const dispatchInit = useCallback(() => {
41+
dispatch(initApp())
42+
}, [dispatch])
43+
44+
const dispatchInitCompleted = useCallback(() => {
45+
dispatch(initAppCompleted())
46+
}, [dispatch])
47+
48+
return {
49+
initState,
50+
dispatchInit,
51+
dispatchInitCompleted,
52+
}
53+
}
54+
55+
export const { setSidebarShow, initApp, initAppCompleted } = initSlice.actions
3156
export default initSlice.reducer

src/redux/modules/userNonce/index.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { useCallback } from 'react'
2-
import { put, takeEvery } from 'redux-saga/effects'
2+
import { put, takeEvery, select } from 'redux-saga/effects'
33
import ReduxFetchState from 'redux-fetch-state'
44
import { getAccount, signMessage } from '@wagmi/core'
5-
import { useDispatch } from 'react-redux'
5+
import { useDispatch, useSelector } from 'react-redux'
66
import apiPlugin from '../../../services/api'
77
import { userSignActions } from '../userSign'
8-
const API_URL = process.env.REACT_APP_BASE_URL
98

109
const { actions, actionTypes, reducer } = new ReduxFetchState('userNonce')
1110

1211
export function* watchUserNonce(action) {
12+
const { base_url } = yield select((state) => state.web3?.config || {})
1313
const { address } = action.payload
1414
try {
15-
const response = yield apiPlugin.getData(`${API_URL}/nonce/${address}`)
15+
const response = yield apiPlugin.getData(`${base_url}/nonce/${address}`)
1616
const { message } = response
1717
const signature = yield signMessage({ message: message })
1818
yield put(actions.loadSuccess(response))
@@ -28,13 +28,13 @@ export function* userNonceSagas() {
2828

2929
export function useGetNonce() {
3030
const dispatch = useDispatch()
31+
const { data: userNonce, ...userNonceState } = useSelector((state) => state.userSign)
3132

3233
const dispatchGetNonce = useCallback(() => {
3334
const { address } = getAccount()
3435
dispatch(actions.load({ address }))
3536
}, [dispatch])
36-
37-
return { dispatchGetNonce }
37+
return { userNonce, ...userNonceState, dispatchGetNonce }
3838
}
3939

4040
export {

0 commit comments

Comments
 (0)