Skip to content
This repository has been archived by the owner on Feb 21, 2024. It is now read-only.

Xdefi Wallet Context Provider #1

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/context/XDEFIProvider/XDEFIContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createContext } from 'react'

import { ActionTypes } from './actions'
import { InitialState } from './types'

export interface IXDEFIProviderContext {
state: InitialState
dispatch: React.Dispatch<ActionTypes>
}

export const XDEFIProviderContext = createContext<IXDEFIProviderContext | null>(null)
138 changes: 138 additions & 0 deletions src/context/XDEFIProvider/XDEFIWalletProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/* eslint-disable no-console */
import React, { useCallback, useEffect, useMemo, useReducer } from 'react'

import { useWallet } from '../../hooks/useWallet/useWallet'
import { KeyManager } from '../WalletProvider/KeyManager'
import { getLocalWalletDeviceId, getLocalWalletType } from '../WalletProvider/local-wallet'
import { ActionTypes, XDEFIProviderActions } from './actions'
import { InitialState, IXfiBitcoinProvider, IXfiLitecoinProvider } from './types'
import { IXDEFIProviderContext, XDEFIProviderContext } from './XDEFIContext'

const initialState: InitialState = {
ethereumWallet: null,
xfiBitcoinProvider: null,
xfiLitecoinProvider: null,
isWalletLoading: false,
}

export const reducer = (state: InitialState, action: ActionTypes) => {
switch (action.type) {
case XDEFIProviderActions.XDEFI_CONNECTED: {
return {
...state,
...action.payload,
isWalletLoading: false,
}
}
case XDEFIProviderActions.XDEFI_NOT_CONNECTED: {
return {
...initialState,
...action.payload,
isWalletLoading: false,
}
}
case XDEFIProviderActions.RESET_STATE: {
return {
...initialState,
isWalletLoading: false,
}
}
default:
return state
}
}

const getInitialState = () => {
const localWalletType = getLocalWalletType()
const localWalletDeviceId = getLocalWalletDeviceId()
if (localWalletType && localWalletDeviceId) {
return {
...initialState,
isWalletLoading: true,
}
}
return initialState
}

const injectedAccount = async (
xfiProvider: IXfiBitcoinProvider | IXfiLitecoinProvider,
): Promise<string[]> => {
return new Promise(resolve => {
xfiProvider.request(
{ method: 'request_accounts', params: [] },
(error: any, accounts: string[]) => {
if (!error && accounts.length) {
resolve(accounts)
}
if (error) {
resolve([])
}
},
)
})
}

export const XDEFIWalletProvider = ({ children }: { children: React.ReactNode }): JSX.Element => {
const [state, dispatch] = useReducer(reducer, getInitialState())
const {
state: { wallet },
} = useWallet()
const localWalletType = getLocalWalletType()
const localWalletDeviceId = getLocalWalletDeviceId()

const load = useCallback(() => {
if (localWalletType && localWalletDeviceId) {
switch (localWalletType) {
case KeyManager.XDefi: {
;(async () => {
const xfi = (window as any).xfi
const xfiBitcoinProvider: IXfiBitcoinProvider = xfi['bitcoin']
const xfiLitecoinProvider: IXfiLitecoinProvider = xfi['litecoin']
const xfiBitcoinAccounts = await injectedAccount(xfiBitcoinProvider)
const xfiLItecoinAccounts = await injectedAccount(xfiLitecoinProvider)

dispatch({
type: XDEFIProviderActions.XDEFI_CONNECTED,
payload: {
ethereumWallet: wallet!,
xfiBitcoinProvider: {
...xfiBitcoinProvider,
accounts: xfiBitcoinAccounts,
},
xfiLitecoinProvider: {
...xfiLitecoinProvider,
accounts: xfiLItecoinAccounts,
},
},
})
})()
break
}
default: {
dispatch({
type: XDEFIProviderActions.XDEFI_NOT_CONNECTED,
payload: {
ethereumWallet: wallet!,
},
})
}
}
} else {
dispatch({
type: XDEFIProviderActions.RESET_STATE,
})
}
}, [localWalletType, localWalletDeviceId, wallet])

useEffect(() => load(), [load])

const value: IXDEFIProviderContext = useMemo(
() => ({
state,
dispatch,
}),
[state],
)

return <XDEFIProviderContext.Provider value={value}>{children}</XDEFIProviderContext.Provider>
}
28 changes: 28 additions & 0 deletions src/context/XDEFIProvider/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { HDWallet } from '@shapeshiftoss/hdwallet-core'

import { IXfiBitcoinProvider, IXfiLitecoinProvider } from './types'

export enum XDEFIProviderActions {
XDEFI_CONNECTED = 'XDEFI_CONNECTED',
XDEFI_NOT_CONNECTED = 'XDEFI_NOT_CONNECTED',
RESET_STATE = 'RESET_STATE',
}

export type ActionTypes =
| {
type: XDEFIProviderActions.XDEFI_CONNECTED
payload: {
ethereumWallet: HDWallet
xfiBitcoinProvider: IXfiBitcoinProvider
xfiLitecoinProvider: IXfiLitecoinProvider
}
}
| {
type: XDEFIProviderActions.XDEFI_NOT_CONNECTED
payload: {
ethereumWallet: HDWallet
}
}
| {
type: XDEFIProviderActions.RESET_STATE
}
6 changes: 6 additions & 0 deletions src/context/XDEFIProvider/hooks/useXDEFIProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useContext } from 'react'

import { IXDEFIProviderContext, XDEFIProviderContext } from '../XDEFIContext'

export const useXDEFIProvider = (): IXDEFIProviderContext =>
useContext(XDEFIProviderContext as React.Context<IXDEFIProviderContext>)
27 changes: 27 additions & 0 deletions src/context/XDEFIProvider/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { HDWallet } from '@shapeshiftoss/hdwallet-core'

import { AnyFunction } from '../../types/common'

export interface InitialState {
ethereumWallet: HDWallet | null
xfiBitcoinProvider: IXfiBitcoinProvider | null
xfiLitecoinProvider: IXfiLitecoinProvider | null
isWalletLoading: boolean
}
Comment on lines +5 to +10
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The state interface that is provided by the useXDEFIProvider hook.

The etereumWallet is the Wallet created when connecting via Shapeshift's interface. this is for easy access to the other wallets when connected to any other ethereum wallet.


export interface IXfiBitcoinProvider {
accounts: string[]
chainId: string
network: string
request: (e: { method: string; params: any[] }, cb: AnyFunction) => Promise<any>
signTransaction: (e: any) => Promise<void>
transfer: (e: any) => Promise<void>
}

export interface IXfiLitecoinProvider {
accounts: string[]
chainId: string
network: string
request: (e: { method: string; params: any[] }, cb: AnyFunction) => void
transfer: (e: any) => void
}
Comment on lines +12 to +27
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is set up so that when a XDEFI wallet is connected then it will grab the accounts of the needed wallets, in this case litecoin and bitcoin and gather some general information about the connection in a 'provider' object.

For bitcoin it exposes the request, signTransaction, and transfer methods.
https://sdk.xdefi.io/docs/HEAD/bitcoin.html

For litecoin it exposes the request and transfer methods.
https://sdk.xdefi.io/docs/HEAD/litecoin.html

These will allow you to interact with these chains