1
0
mirror of https://github.com/oceanprotocol/react.git synced 2025-02-14 21:10:38 +01:00

decoupling web3 - wip

This commit is contained in:
Dimo Dzhurenov 2021-03-03 15:43:22 +02:00
parent e99dfaf256
commit 93177c08cb
25 changed files with 49 additions and 26501 deletions

15
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}"
}
]
}

View File

@ -1,8 +0,0 @@
# Example
Simple example app based on Create React App.
```bash
npm install
npm start
```

View File

@ -1,15 +0,0 @@
module.exports = function override(config, env) {
const path = require('path')
return {
...config,
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
react: path.resolve('../node_modules/react'),
'@oceanprotocol/lib': path.resolve('../node_modules/@oceanprotocol/lib')
}
}
}
}

25860
example/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +0,0 @@
{
"name": "example",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "SKIP_PREFLIGHT_CHECK=true react-app-rewired start",
"build": "SKIP_PREFLIGHT_CHECK=true react-app-rewired build",
"eject": "react-app-rewired eject"
},
"dependencies": {
"@oceanprotocol/react": "file:../",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.3",
"shortid": "^2.2.15",
"typescript": "^4.0.2"
},
"devDependencies": {
"@types/node": "^12.12.67",
"@types/react": "^16.9.51",
"@types/react-dom": "^16.9.8",
"@types/shortid": "0.0.29",
"react-app-rewired": "^2.1.6"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -1,38 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -1,46 +0,0 @@
import React from 'react'
import { useOcean } from '@oceanprotocol/react'
import { DDO } from '@oceanprotocol/lib'
import { useState } from 'react'
import { useEffect } from 'react'
import shortid from 'shortid'
import { MetadataExample } from './MetadataExample'
export function AllDdos() {
const { networkId, account, accountId, ocean } = useOcean()
const [ddos, setDdos] = useState<DDO[]>()
useEffect(() => {
async function init() {
if (!ocean || !accountId || !accountId) return
//const assets = await ocean.assets.ownerAssets(accountId)
const assets = await ocean.assets.query({
page: 1,
offset: 10,
query: {},
sort: { created: -1 }
})
console.log('assets', assets.results)
setDdos(assets.results.slice(0, 4))
}
init()
}, [ocean, account, networkId, accountId])
return (
<>
<div>Assets</div> <br />
<div style={{ flexDirection: 'column' }}>
{ddos?.map((ddo) => {
return (
<div key={shortid.generate()}>
<MetadataExample ddo={ddo} />
<br />
</div>
)
})}
</div>
</>
)
}

View File

@ -1,16 +0,0 @@
.app {
width: 100%;
}
.container {
display: flex;
flex-direction: column;
margin-left: auto;
margin-right: auto;
max-width: 860px;
}
.container div {
display: flex;
padding: 10px;
margin-bottom: 10px;
}

View File

@ -1,52 +0,0 @@
import React, { useEffect, useState } from 'react'
import './App.css'
import { OceanProvider } from '@oceanprotocol/react'
import { Wallet } from './Wallet'
import { Publish } from './Publish'
import { ConfigHelper, Logger } from '@oceanprotocol/lib'
import { AllDdos } from './AllDdos'
import { ConsumeDdo } from './ConsumeDdo'
import { NetworkMonitor } from './NetworkMonitor'
import { LogLevel } from '@oceanprotocol/lib/dist/node/utils'
const configRinkeby = new ConfigHelper().getConfig('rinkeby')
const providerOptions = {}
export const web3ModalOpts = {
cacheProvider: true,
providerOptions
}
function App() {
console.log(configRinkeby)
Logger.setLevel(LogLevel.Verbose)
const init = async () => {}
useEffect(() => {
init()
}, [])
const [did, setDid] = useState<string | undefined>()
return (
<OceanProvider initialConfig={configRinkeby} web3ModalOpts={web3ModalOpts}>
<div className="container">
<NetworkMonitor />
<div>
<Wallet />
</div>
<div>
<AllDdos />
</div>
<div>
<Publish />
</div>
<div>
<ConsumeDdo />
</div>
</div>
</OceanProvider>
)
}
export default App

View File

@ -1,68 +0,0 @@
import React from 'react'
import {
useOcean,
useConsume,
useCompute,
computeOptions
} from '@oceanprotocol/react'
import { useState } from 'react'
import { useEffect } from 'react'
export function ConsumeDdo() {
const { ocean, accountId } = useOcean()
const { consumeStepText, consume, consumeError } = useConsume()
const { compute, computeStepText } = useCompute()
const [did, setDid] = useState<string | undefined>()
useEffect(() => {
async function init() {}
init()
}, [ocean])
const consumeDid = async () => {
if (!did) return
const ddo = await ocean.assets.resolve(did)
// use own accountId for marketFeeAddress for testing purposes
await consume(did, ddo.dataToken, 'access', accountId)
}
const computeDid = async () => {
if (!did) return
const ddo = await ocean.assets.resolve(did)
console.log(ddo)
console.log('ocean dt', ocean.datatokens)
const computeService = ddo.findServiceByType('compute')
console.log('ddo compute service', computeService)
const serv = ddo.findServiceById(computeService.index)
console.log('ddo compute service resolved', serv)
await compute(
did,
computeService,
ddo.dataToken,
"console.log('test')",
computeOptions[0].value
)
}
const handleChange = (e: any) => {
setDid(e.target.value)
}
return (
<>
<div>Consume</div>
<div>
DID <input onChange={handleChange}></input>
</div>
<div>
<button onClick={consumeDid}>Consume did</button>
<button onClick={computeDid}>Compute</button>
</div>
<div>
{consumeStepText}
{computeStepText}
</div>
<div>{consumeError}</div>
</>
)
}

View File

@ -1,22 +0,0 @@
import React from 'react'
import { useMetadata } from '@oceanprotocol/react'
import { DDO } from '@oceanprotocol/lib'
export function MetadataExample({ ddo }: { ddo: DDO }) {
const { title, price, did } = useMetadata(ddo)
return (
<>
<div>
{title} - did= {did}
</div>
<div>
{price && (
<span>
price = {price.value} // {price.type} = {price.address}
</span>
)}
</div>
</>
)
}

View File

@ -1,28 +0,0 @@
import React, { useCallback } from 'react'
import { useOcean } from '@oceanprotocol/react'
import { ConfigHelper } from '@oceanprotocol/lib'
import { useEffect } from 'react'
export const NetworkMonitor = () => {
const { connect, web3Provider } = useOcean()
const handleNetworkChanged = useCallback(
(chainId: number) => {
const config = new ConfigHelper().getConfig(chainId)
connect(config)
},
[connect]
)
useEffect(() => {
if (!web3Provider) return
web3Provider.on('chainChanged', handleNetworkChanged)
return () => {
web3Provider.removeListener('chainChanged', handleNetworkChanged)
}
}, [web3Provider, handleNetworkChanged])
return <></>
}

View File

@ -1,51 +0,0 @@
import React from 'react'
import { usePublish } from '@oceanprotocol/react'
import { DDO } from '@oceanprotocol/lib'
import { useState } from 'react'
import { Metadata } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Metadata'
export function Publish() {
const { publish, publishStepText, isLoading } = usePublish()
const [ddo, setDdo] = useState<DDO | undefined | null>()
const asset = {
main: {
type: 'dataset',
name: 'test-dataset - ' + new Date().toISOString(),
dateCreated: new Date(Date.now()).toISOString().split('.')[0] + 'Z', // remove milliseconds
author: 'oceanprotocol-team',
license: 'MIT',
files: [
{
url:
'https://raw.githubusercontent.com/tbertinmahieux/MSongsDB/master/Tasks_Demos/CoverSongs/shs_dataset_test.txt',
checksum: 'efb2c764274b745f5fc37f97c6b0e761',
contentLength: '4535431',
contentType: 'text/csv',
encoding: 'UTF-8',
compression: 'zip'
}
]
}
}
const publishAsset = async () => {
const datatokenOptions = {}
const ddo = await publish(asset as Metadata, 'access', datatokenOptions)
console.log(ddo)
setDdo(ddo)
}
return (
<>
<div>Publish</div>
<div>
<button onClick={publishAsset}>Publish</button>
</div>
<div>
IsLoading: {isLoading.toString()} || Status: {publishStepText}
</div>
<div>DID: {ddo && ddo.id} </div>
</>
)
}

View File

@ -1,66 +0,0 @@
import React from 'react'
import { PriceOptions, useOcean, usePricing } from '@oceanprotocol/react'
// import { useOcean, usePublish } from '@oceanprotocol/react'
import { DDO } from '@oceanprotocol/lib'
import { useState } from 'react'
import { Metadata } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Metadata'
export function Trade() {
const { ocean, accountId } = useOcean()
const {
createPricing,
buyDT,
sellDT,
mint,
pricingStep,
pricingStepText,
pricingIsLoading,
pricingError
} = usePricing(new DDO())
const [datatoken, setDatatoken] = useState<string | undefined>()
const handleBuy = async () => {
const tx = await buyDT('1')
console.log(tx)
}
const handleSell = async () => {
const tx = await buyDT('1')
console.log(tx)
}
const handleChange = (e: any) => {
setDatatoken(e.target.value)
}
const handlePostForSale = async () => {
if (datatoken) {
const priceOptions = {
price: 7,
dtAmount: 10,
type: 'fixed',
weightOnDataToken: '',
swapFee: ''
} as PriceOptions
const tx = await createPricing(priceOptions)
console.log(tx)
}
}
return (
<>
<div>Trade Datatoken</div>
<div>
Datatoken <input onChange={handleChange}></input>
</div>
<div>
<button onClick={handlePostForSale}>Post for sale</button>
</div>
<div>
<button onClick={handleBuy}>Buy 1 DT</button>
</div>
<div>
<button onClick={handleSell}>Sell 1 DT</button>
</div>
<div>
IsLoading: {pricingIsLoading.toString()} || Status: {pricingStepText}
</div>
</>
)
}

View File

@ -1,38 +0,0 @@
import React, { useCallback } from 'react'
import { useOcean } from '@oceanprotocol/react'
import { useEffect } from 'react'
export function Wallet() {
const { ocean, connect, logout, accountId } = useOcean()
const conn = async () => {
await connect()
}
const init = useCallback(async () => {
if (ocean === undefined || accountId === undefined) return
await ocean.assets.ownerAssets(accountId)
}, [accountId, ocean])
useEffect(() => {
init()
}, [ocean, accountId, init])
const disc = async () => {
await logout()
await conn()
}
return (
<>
<div>wallet</div>
<div>
<button onClick={conn}>Connect</button>
</div>
<div>
<button onClick={disc}>Disconnect</button>
</div>
<div>{accountId}</div>
</>
)
}

View File

@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@ -1,11 +0,0 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)

View File

@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@ -1,19 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
},
"include": ["src"]
}

View File

@ -10,8 +10,6 @@ import React, {
import Web3 from 'web3'
import ProviderStatus from './ProviderStatus'
import { Ocean, Logger, Account, Config } from '@oceanprotocol/lib'
import Web3Modal, { ICoreOptions } from 'web3modal'
import { getDefaultProviders } from './getDefaultProviders'
import { getAccountId, getBalance } from 'utils'
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
import {
@ -26,8 +24,6 @@ interface Balance {
interface OceanProviderValue {
web3: Web3 | undefined
web3Provider: any
web3Modal: Web3Modal
ocean: Ocean
config: Config | ConfigHelperConfig
account: Account
@ -38,43 +34,29 @@ interface OceanProviderValue {
networkId: number | undefined
status: ProviderStatus
connect: (config?: Config) => Promise<void>
logout: () => Promise<void>
refreshBalance: () => Promise<void>
}
const OceanContext = createContext({} as OceanProviderValue)
function OceanProvider({
initialConfig,
web3ModalOpts,
children
}: {
function OceanProvider({ initialConfig, children }: {
initialConfig: Config | ConfigHelperConfig
web3ModalOpts?: Partial<ICoreOptions>
children: ReactNode
}): ReactElement {
const [web3, setWeb3] = useState<Web3 | undefined>()
const [web3Provider, setWeb3Provider] = useState<any | undefined>()
const [ocean, setOcean] = useState<Ocean | undefined>()
const [web3Modal, setWeb3Modal] = useState<Web3Modal>()
const [networkId, setNetworkId] = useState<number | undefined>()
const [account, setAccount] = useState<Account | undefined>()
const [accountId, setAccountId] = useState<string | undefined>()
const [networkId, setNetworkId] = useState<number | undefined>()
const [balance, setBalance] = useState<Balance | undefined>({ eth: undefined, ocean: undefined });
const [isInPurgatory, setIsInPurgatory] = useState(false)
const [purgatoryData, setPurgatoryData] = useState<AccountPurgatoryData>()
const [config, setConfig] = useState<Config | ConfigHelperConfig>(
initialConfig
)
const [balance, setBalance] = useState<Balance | undefined>({
eth: undefined,
ocean: undefined
})
const [status, setStatus] = useState<ProviderStatus>(
ProviderStatus.NOT_AVAILABLE
)
const [config, setConfig] = useState<Config | ConfigHelperConfig>(initialConfig)
const [status, setStatus] = useState<ProviderStatus>(ProviderStatus.NOT_AVAILABLE)
const setPurgatory = useCallback(async (address: string): Promise<void> => {
if (!address) return
try {
const result = await getAccountPurgatoryData(address)
@ -84,27 +66,13 @@ function OceanProvider({
} else {
setIsInPurgatory(false)
}
setPurgatoryData(result)
} catch (error) {
Logger.error(error)
}
}, [])
const init = useCallback(async () => {
Logger.log('Ocean Provider init')
window &&
window.ethereum &&
(window.ethereum.autoRefreshOnNetworkChange = false)
Logger.log('Web3Modal init.')
const web3ModalInstance = new Web3Modal(
web3ModalOpts || (await getDefaultProviders())
)
setWeb3Modal(web3ModalInstance)
Logger.log('Web3Modal instance created.', web3ModalInstance)
}, [web3ModalOpts])
const connect = useCallback(
async (newConfig?: Config | ConfigHelperConfig) => {
try {
@ -112,63 +80,47 @@ function OceanProvider({
newConfig && setConfig(newConfig)
const provider = await web3Modal?.connect()
setWeb3Provider(provider)
const web3 = new Web3(provider)
setWeb3(web3)
Logger.log('Web3 created.', web3)
const networkId = web3 && (await web3.eth.net.getId())
setNetworkId(networkId)
Logger.log('network id ', networkId)
config.web3Provider = web3
// ========
// config.web3Provider = web3
const ocean = await Ocean.getInstance(config)
setOcean(ocean)
Logger.log('Ocean instance created.', ocean)
// ========
setStatus(ProviderStatus.CONNECTED)
// NETWORK ID
const account = (await ocean.accounts.list())[0]
setAccount(account)
Logger.log('Account ', account)
// const networkId = web3 && (await web3.eth.net.getId())
// setNetworkId(networkId)
// Logger.log('network id ', networkId)
const accountId = await getAccountId(web3)
setAccountId(accountId)
Logger.log('account id', accountId)
// ACCOUNT
const balance = await getBalance(account)
setBalance(balance)
Logger.log('balance', JSON.stringify(balance))
// const account = (await ocean.accounts.list())[0]
// setAccount(account)
// Logger.log('Account ', account)
// ACCOUNT ID
// const accountId = await getAccountId(web3)
// setAccountId(accountId)
// Logger.log('account id', accountId)
// BALANCE
// const balance = await getBalance(account)
// setBalance(balance)
// Logger.log('balance', JSON.stringify(balance))
} catch (error) {
Logger.error(error)
}
},
[config, web3Modal]
[config]
)
// On mount setup Web3Modal instance
useEffect(() => {
init()
}, [init])
// Connect automatically to cached provider if present
useEffect(() => {
if (!web3Modal) return
web3Modal.cachedProvider && connect()
}, [web3Modal, connect])
async function refreshBalance() {
const balance = account && (await getBalance(account))
setBalance(balance)
}
async function logout() {
// TODO: #67 check how is the proper way to logout
web3Modal?.clearCachedProvider()
}
// TODO: #68 Refetch balance periodically, or figure out some event to subscribe to
useEffect(() => {
if (!accountId) return
@ -176,42 +128,20 @@ function OceanProvider({
setPurgatory(accountId)
}, [accountId])
useEffect(() => {
const handleAccountsChanged = async (accounts: string[]) => {
Logger.debug("Handling 'accountsChanged' event with payload", accounts)
connect()
}
// web3Modal && web3Modal.on('connect', handleConnect)
if (web3Provider !== undefined && web3Provider !== null) {
web3Provider.on('accountsChanged', handleAccountsChanged)
// web3Provider.on('chainChanged', handleNetworkChanged)
return () => {
web3Provider.removeListener('accountsChanged', handleAccountsChanged)
// web3Provider.removeListener('chainChanged', handleNetworkChanged)
}
}
}, [web3Modal, web3Provider, connect])
return (
<OceanContext.Provider
value={
{
web3,
web3Provider,
web3Modal,
ocean,
account,
accountId,
networkId,
balance,
isInPurgatory,
purgatoryData,
balance,
networkId,
status,
config,
connect,
logout,
refreshBalance
} as OceanProviderValue
}

View File

@ -1,5 +0,0 @@
import { ICoreOptions } from 'web3modal/dist/helpers/types'
export async function getDefaultProviders(): Promise<Partial<ICoreOptions>> {
return { cacheProvider: true }
}