Skip to content

Instantly share code, notes, and snippets.

@jeffywu
Last active August 9, 2020 00:59
Show Gist options
  • Save jeffywu/6a7cf84addccdadf1b495d71160dc7a0 to your computer and use it in GitHub Desktop.
Save jeffywu/6a7cf84addccdadf1b495d71160dc7a0 to your computer and use it in GitHub Desktop.
OnboardJS + Redux
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>
)
}
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 })
}
}
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 }});
}
}
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;
}
}
@thegostep
Copy link

What does selectOnboard do?

@thegostep
Copy link

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