commons/client/src/context/UserProvider.tsx

287 lines
8.7 KiB
TypeScript

import React, { PureComponent } from 'react'
import Web3 from 'web3'
import { Ocean, Account, Config } from '@oceanprotocol/squid'
import { User } from '.'
import { provideOcean, requestFromFaucet, FaucetResponse } from '../ocean'
import MarketProvider from './MarketProvider'
import { MetamaskProvider } from './MetamaskProvider'
import { BurnerWalletProvider } from './BurnerWalletProvider'
import { urlq, getObjByKey } from '../utils/utils'
import {
oceanConfig,
getCurrentNetConfigFromMetamask
} from '../components/molecules/NetworkSwitcher'
import { CONNECTIONS } from '../config'
//const nodeUri = oceanConfig.then((c: any) => c.nodeUri)
const { nodeUri } = oceanConfig
const POLL_ACCOUNTS = 1000 // every 1s
const POLL_NETWORK = POLL_ACCOUNTS * 60 // every 1 min
const DEFAULT_WEB3 = new Web3(new Web3.providers.HttpProvider(nodeUri)) // default web3
const networkUrlParam = urlq.get('network') || ''
interface UserProviderState {
isLogged: boolean
isBurner: boolean
isWeb3Capable: boolean
isLoading: boolean
account: string
balance: {
eth: number
ocn: number
}
network: string
web3: Web3
ocean: Ocean
switchNetwork(network: string, config: Config): any
requestFromFaucet(account: string): Promise<FaucetResponse>
loginMetamask(): Promise<any>
loginBurnerWallet(): Promise<any>
logoutBurnerWallet(): Promise<any>
loadOcean: (config: Config) => Promise<Ocean | void>
message: string
}
export default class UserProvider extends PureComponent<{}, UserProviderState> {
public state = {
isLogged: false,
isBurner: false,
isWeb3Capable: Boolean(window.web3 || window.ethereum),
isLoading: true,
balance: {
eth: 0,
ocn: 0
},
network: '',
web3: DEFAULT_WEB3,
account: '',
ocean: {} as any,
requestFromFaucet: () => requestFromFaucet(''),
loginMetamask: () => this.loginMetamask(),
switchNetwork: (network: string, config: Config) =>
this.switchNetwork(network, config),
loginBurnerWallet: () => this.loginBurnerWallet(),
logoutBurnerWallet: () => this.logoutBurnerWallet(),
loadOcean: (config: Config) => this.loadOcean(config),
message: 'Connecting to Ocean...'
}
public async componentDidMount() {
await this.bootstrap()
}
private switchNetwork = async (network: string, config: Config) => {
console.log('TEST')
this.setState({ network }, async () => {
this.loadOcean({
web3Provider: this.state.web3,
...config
})
})
}
private loginMetamask = async () => {
console.log('loginMetamask')
const metamaskProvider = new MetamaskProvider()
await metamaskProvider.startLogin()
const web3 = metamaskProvider.getProvider()
console.log(web3.currentProvider)
console.log(web3)
this.setState(
{
isLogged: true,
isBurner: false,
web3
},
() => {
this.loadOcean({
web3Provider: this.state.web3,
...oceanConfig
})
}
)
}
private loginBurnerWallet = async () => {
const burnerwalletProvider = new BurnerWalletProvider()
await burnerwalletProvider.startLogin()
const web3 = burnerwalletProvider.getProvider()
this.setState(
{
isLogged: true,
isBurner: true,
web3
},
async () => {
await this.switchNetwork(networkUrlParam, oceanConfig)
this.loadOcean({
web3Provider: this.state.web3,
...oceanConfig
})
}
)
}
private logoutBurnerWallet = async () => {
const burnerwalletProvider = new BurnerWalletProvider()
await burnerwalletProvider.logout()
}
private accountsInterval: any = null
private networkInterval: any = null
private initAccountsPoll() {
if (!this.accountsInterval) {
this.accountsInterval = setInterval(
this.fetchAccounts,
POLL_ACCOUNTS
)
}
}
private initNetworkPoll() {
if (!this.networkInterval) {
this.networkInterval = setInterval(this.fetchNetwork, POLL_NETWORK)
}
}
private loadDefaultWeb3 = async () => {
this.setState(
{
isLogged: false,
isBurner: false,
web3: DEFAULT_WEB3
},
() => {
this.loadOcean({
web3Provider: this.state.web3,
...oceanConfig
})
}
)
}
private loadOcean = async (config: Config) => {
const { ocean } = await provideOcean({
web3Provider: this.state.web3,
...config
})
this.setState({ ocean, isLoading: false }, () => {
this.initNetworkPoll()
this.initAccountsPoll()
this.fetchNetwork()
this.fetchAccounts()
})
}
private bootstrap = async () => {
const logType = localStorage.getItem('logType')
switch (logType) {
case 'Metamask':
await getCurrentNetConfigFromMetamask()
.then((obj: any) => {
console.log(obj)
const { netConfig, web3, netName } = obj
this.setState(
{
isLogged: true,
web3,
network: netName
},
() => {
this.loadOcean({
web3Provider: web3,
...netConfig
})
}
)
})
.catch(() => this.loadDefaultWeb3())
break
case 'BurnerWallet':
this.loginBurnerWallet()
break
default:
this.loginBurnerWallet()
break
}
}
private fetchAccounts = async () => {
const { ocean, isLogged } = this.state
if (isLogged) {
let accounts
// Modern dapp browsers
if (window.ethereum && !isLogged) {
// simply set to empty, and have user click a button somewhere
// to initiate account unlocking
accounts = []
// alternatively, automatically prompt for account unlocking
// await this.unlockAccounts()
}
accounts = await ocean.accounts.list()
//console.log('fetch', accounts)
if (accounts.length > 0) {
const account = await accounts[0].getId()
if (account !== this.state.account) {
this.setState({
account,
isLogged: true,
requestFromFaucet: () => requestFromFaucet(account)
})
await this.fetchBalance(accounts[0])
}
} else {
!isLogged &&
this.setState({
isLogged: false,
account: ''
})
}
}
}
private fetchBalance = async (account: Account) => {
const balance = await account.getBalance()
const { eth, ocn } = balance
if (eth !== this.state.balance.eth || ocn !== this.state.balance.ocn) {
this.setState({ balance: { eth, ocn } })
}
}
private fetchNetwork = async () => {
const { ocean } = this.state
let network = 'Unknown'
if (ocean.keeper) {
network = await ocean.keeper.getNetworkName()
const networkId = await ocean.keeper.getNetworkId()
const netId = await this.state.web3.eth.net.getId()
console.log('Network Name:', network, networkId, netId)
}
if (network !== this.state.network) {
this.setState({ network }, () => {})
}
}
public render() {
// console.log(this.state.network)
return (
<User.Provider value={this.state}>
<MarketProvider ocean={this.state.ocean}>
{this.props.children}
</MarketProvider>
</User.Provider>
)
}
}