Last active
August 9, 2020 00:59
-
-
Save jeffywu/6a7cf84addccdadf1b495d71160dc7a0 to your computer and use it in GitHub Desktop.
OnboardJS + Redux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react'; | |
import { useSelector } from 'react-redux'; | |
import { selectOnboard, selectAccount } from '../redux/Store'; | |
export default function ConnectWallet() { | |
const networkId = Number(process.env.NETWORK_ID); | |
const swapnet = useSelector(selectSwapnet); | |
const onboard = useSelector(selectOnboard); | |
const account = useSelector(selectAccount); | |
const dispatch = useDispatch(); | |
if (swapnet == null || onboard == null) { | |
dispatch({type: START_SWAPNET_INIT, payload: { networkId } }) | |
} | |
if (onboard == null) return <div></div> | |
if (account != null) { | |
return ( | |
<div> | |
<button onClick={() => { | |
if (onboard != null) { | |
onboard.resetWallet(); | |
} | |
}}>Reset Wallet</button> | |
</div> | |
) | |
} | |
return ( | |
<div> | |
<button onClick={() => { | |
if (onboard != null) { | |
onboard.connectWallet(); | |
} | |
}}>Connect Wallet</button> | |
</div> | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Onboard from 'bnc-onboard'; | |
import {Wallet as BNCWallet, API as BNCAPI} from 'bnc-onboard/dist/src/interfaces'; | |
import { Web3Provider } from 'ethers/providers' | |
import { Signer } from 'ethers'; | |
import { Swapnet, Account } from '@swapnet-protocol/sdk'; | |
import {WALLET_CONNECT, WALLET_RESET, StoreType } from "../redux/Store"; | |
// TODO: move these to the environment | |
const DAPP_ID = 'xxx' | |
const INFURA_KEY = 'xxx' | |
const APP_URL = 'xxx' | |
const CONTACT_EMAIL = 'xxx' | |
// const FORTMATIC_KEY = 'Your Fortmatic key here' | |
// const PORTIS_KEY = 'Your Portis key here' | |
// const SQUARELINK_KEY = 'Your Squarelink key here' | |
const supportedWallets = (rpcUrl: string) => { | |
return([ | |
{ walletName: "coinbase", preferred: true }, | |
{ walletName: "trust", preferred: true, rpcUrl: rpcUrl }, | |
{ walletName: "metamask", preferred: true }, | |
{ | |
walletName: 'trezor', | |
appUrl: APP_URL, | |
email: CONTACT_EMAIL, | |
rpcUrl: rpcUrl | |
}, | |
{ | |
walletName: 'ledger', | |
rpcUrl: rpcUrl | |
}, | |
{ walletName: "authereum" }, | |
{ | |
walletName: "walletConnect", | |
infuraKey: INFURA_KEY | |
} | |
]) | |
} | |
export class OnboardWrapper { | |
public wallet: BNCWallet | undefined; | |
public signer: Signer | undefined; | |
public onboard: BNCAPI; | |
constructor( | |
networkId: number, | |
rpcUrl: string, | |
private swapnet: Swapnet, | |
private store: StoreType | |
) { | |
const wallets = supportedWallets(rpcUrl); | |
const initWallet = (newWallet: BNCWallet) => { | |
if (newWallet != null) { | |
this.wallet = newWallet | |
window.localStorage.setItem('selectedWallet', newWallet.name as string) | |
if (newWallet.provider != null) this._updateWallet(newWallet); | |
} else { | |
this._walletReset() | |
} | |
} | |
const setAddress = (newAddress: string) => { | |
if (newAddress != null && this.wallet != null && this.wallet.provider != null) { | |
this._updateWallet(this.wallet); | |
} | |
} | |
const setNetworkId = (newNetworkId: number) => { | |
if (newNetworkId != null && this.wallet != null && this.wallet.provider != null) { | |
this._updateWallet(this.wallet); | |
} | |
} | |
this.onboard = Onboard({ | |
dappId: DAPP_ID, | |
networkId: networkId, | |
hideBranding: true, | |
// These calls are fired on change | |
subscriptions: { | |
address: setAddress.bind(this), | |
network: setNetworkId.bind(this), | |
wallet: initWallet.bind(this) | |
}, | |
walletSelect: { | |
wallets: wallets | |
} | |
}); | |
const previouslySelectedWallet = window.localStorage.getItem('selectedWallet'); | |
if (previouslySelectedWallet) { | |
this.onboard.walletSelect(previouslySelectedWallet).then((selected) => { | |
if (selected) this.onboard.walletCheck(); | |
}) | |
} | |
this.connectWallet = this.connectWallet.bind(this); | |
this.resetWallet = this.resetWallet.bind(this); | |
this.fetchAccount = this.fetchAccount.bind(this); | |
} | |
public async connectWallet() { | |
if (!this.signer) { | |
let walletSelected = await this.onboard.walletSelect() | |
if (!walletSelected) return false | |
} | |
const ready = await this.onboard.walletCheck() | |
return ready | |
} | |
public async resetWallet() { | |
this.onboard.walletReset(); | |
this._walletReset(); | |
} | |
public async fetchAccount(account: Account | undefined) { | |
if (account == null) { | |
const ready = await this.connectWallet(); | |
if (!ready) throw new Error("Wallet not connected"); | |
account = await this.swapnet.getAccount(this.signer as Signer); | |
} | |
return account; | |
} | |
private async _updateWallet(wallet: BNCWallet) { | |
const provider = new Web3Provider(wallet.provider) | |
this.signer = provider.getSigner(); | |
this.swapnet.getAccount(this.signer).then((a) => { | |
this.store.dispatch({ | |
type: WALLET_CONNECT, | |
payload: { | |
signer: this.signer as Signer, | |
account: a | |
} | |
}) | |
}); | |
} | |
private async _walletReset() { | |
this.wallet = undefined; | |
this.signer = undefined; | |
this.store.dispatch({ type: WALLET_RESET, payload: undefined }) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { put, call, takeLatest, takeEvery, select, all } from 'redux-saga/effects' | |
function* watchSwapnetInit() { | |
yield takeLatest(START_SWAPNET_INIT, initSwapnet); | |
} | |
function* initSwapnet(action: StartSwapnetInitAction) { | |
const rpc = getRpcUrl(action.payload.networkId); | |
const provider = new JsonRpcProvider(rpc); | |
const voidSigner = new VoidSigner(AddressZero, provider); | |
try { | |
const swapnet = yield call(Swapnet.load, action.payload.networkId, voidSigner); | |
// NOTE: not sure if importing the store here is kosher | |
const onboard = new OnboardWrapper(action.payload.networkId, rpc, swapnet, store); | |
yield put({ type: FINISH_SWAPNET_INIT, payload: { swapnet, onboard }}); | |
} catch (error) { | |
yield put({ type: ERROR_SWAPNET_INIT, payload: { error }}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const globalStateReducer = (state = {} as GlobalState, action: GlobalActionTypes): GlobalState => { | |
switch (action.type) { | |
case START_SWAPNET_INIT: | |
return { | |
...state, | |
swapnet: { | |
...state.swapnet, | |
isUpdating: true | |
} | |
} | |
case FINISH_SWAPNET_INIT: | |
return { | |
...state, | |
onboard: action.payload.onboard, | |
swapnet: { | |
isUpdating: false, | |
lastUpdateTimestamp: (new Date()).getTime(), | |
swapnet: action.payload.swapnet | |
} | |
} | |
case ERROR_SWAPNET_INIT: | |
return { | |
...state, | |
swapnet: { | |
...state.swapnet, | |
isUpdating: false, | |
error: action.payload.error | |
} | |
} | |
default: | |
return state; | |
} | |
} |
How do you handle WALLET_RESET
in redux?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What does
selectOnboard
do?