mirror of
https://github.com/oceanprotocol/react.git
synced 2025-02-14 21:10:38 +01:00
commit
fecbf2c85c
7
.eslintignore
Normal file
7
.eslintignore
Normal file
@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
dist
|
||||
.DS_Store
|
||||
.env
|
||||
.gitignore
|
||||
coverage
|
||||
example
|
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
@ -1,8 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
time: '03:00'
|
||||
timezone: Europe/Berlin
|
||||
- package-ecosystem: npm
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: weekly
|
||||
time: '03:00'
|
||||
timezone: Europe/Berlin
|
||||
|
23
example/.gitignore
vendored
Normal file
23
example/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
0
example/README.md
Normal file
0
example/README.md
Normal file
34642
example/package-lock.json
generated
Normal file
34642
example/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
44
example/package.json
Normal file
44
example/package.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "example",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@oceanprotocol/react": "../",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.5.0",
|
||||
"@testing-library/user-event": "^7.2.1",
|
||||
"@toruslabs/torus-embed": "^1.7.3",
|
||||
"@types/jest": "^24.9.1",
|
||||
"@types/node": "^12.12.47",
|
||||
"@types/react": "^16.9.41",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@walletconnect/web3-provider": "^1.0.14",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-scripts": "3.4.1",
|
||||
"typescript": "^3.7.5",
|
||||
"web3-eth-contract": "^1.2.9",
|
||||
"web3modal": "../node_modules/web3modal"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
BIN
example/public/favicon.ico
Normal file
BIN
example/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
43
example/public/index.html
Normal file
43
example/public/index.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!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" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
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>
|
BIN
example/public/logo192.png
Normal file
BIN
example/public/logo192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
example/public/logo512.png
Normal file
BIN
example/public/logo512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
25
example/public/manifest.json
Normal file
25
example/public/manifest.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
3
example/public/robots.txt
Normal file
3
example/public/robots.txt
Normal file
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
16
example/src/App.css
Normal file
16
example/src/App.css
Normal file
@ -0,0 +1,16 @@
|
||||
.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-top: 40px;
|
||||
}
|
39
example/src/App.tsx
Normal file
39
example/src/App.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import './App.css'
|
||||
import { OceanProvider } from '@oceanprotocol/react'
|
||||
import { LogLevel } from '@oceanprotocol/lib/dist/node/utils/Logger'
|
||||
import { Wallet } from './Wallet'
|
||||
import { Publish } from './Publish'
|
||||
import { Config } from '@oceanprotocol/lib'
|
||||
|
||||
function App() {
|
||||
// factory Address needs to be updated each time you deploy the contract on local network
|
||||
const config = {
|
||||
metadataStoreUri: 'http://aquarius:5000',
|
||||
providerUri: 'http://localhost:8030',
|
||||
nodeUri: `http://localhost:8545`,
|
||||
factoryAddress: '0x2fC1fd21cb222Dc180Ef817dE4c426fd9230b5A5'
|
||||
} as Config
|
||||
const init = async () => {}
|
||||
useEffect(() => {
|
||||
init()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<OceanProvider config={config}>
|
||||
<div className="container">
|
||||
<div>
|
||||
<Wallet />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Publish />
|
||||
</div>
|
||||
</div>
|
||||
</OceanProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
46
example/src/Publish.tsx
Normal file
46
example/src/Publish.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React from 'react'
|
||||
import { useOcean, usePublish } from '@oceanprotocol/react'
|
||||
import { Metadata, DDO } from '@oceanprotocol/lib'
|
||||
import { useState } from 'react'
|
||||
|
||||
export function Publish() {
|
||||
const { accountId } = useOcean()
|
||||
const { publish } = usePublish()
|
||||
const [ddo, setDdo] = useState<DDO | undefined>()
|
||||
|
||||
const asset = {
|
||||
main: {
|
||||
type: 'dataset',
|
||||
name: 'test-dataset',
|
||||
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 ddo = await publish(asset as Metadata, 4)
|
||||
console.log(ddo)
|
||||
setDdo(ddo)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div>Publish</div>
|
||||
<div>
|
||||
<button onClick={publishAsset}>Publish</button>
|
||||
</div>
|
||||
<div>DID: {ddo && ddo.id} </div>
|
||||
</>
|
||||
)
|
||||
}
|
57
example/src/Wallet.tsx
Normal file
57
example/src/Wallet.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import React from 'react'
|
||||
import { useOcean } from '@oceanprotocol/react'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export function Wallet() {
|
||||
const { ocean, connect, logout, accountId } = useOcean()
|
||||
const conn = async () => {
|
||||
const { default: WalletConnectProvider } = await import(
|
||||
'@walletconnect/web3-provider'
|
||||
)
|
||||
const { default: Torus } = await import('@toruslabs/torus-embed')
|
||||
|
||||
const providerOptions = {
|
||||
/* See Provider Options Section */
|
||||
walletconnect: {
|
||||
package: WalletConnectProvider, // required
|
||||
options: {
|
||||
infuraId: 'INFURA_ID' // required
|
||||
}
|
||||
},
|
||||
torus: {
|
||||
package: Torus // required
|
||||
}
|
||||
}
|
||||
|
||||
await connect({ providerOptions })
|
||||
}
|
||||
const init = async () => {
|
||||
if (ocean === undefined) return
|
||||
console.log(ocean.datatokens.factoryAddress)
|
||||
|
||||
const accs = await ocean.accounts.list()
|
||||
console.log(accs)
|
||||
}
|
||||
useEffect(() => {
|
||||
init()
|
||||
}, [ocean])
|
||||
|
||||
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>
|
||||
</>
|
||||
)
|
||||
}
|
13
example/src/index.css
Normal file
13
example/src/index.css
Normal file
@ -0,0 +1,13 @@
|
||||
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;
|
||||
}
|
12
example/src/index.tsx
Normal file
12
example/src/index.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
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')
|
||||
)
|
||||
|
1
example/src/react-app-env.d.ts
vendored
Normal file
1
example/src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
19
example/tsconfig.json
Normal file
19
example/tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react",
|
||||
"strict": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
2607
package-lock.json
generated
2607
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -6,9 +6,10 @@
|
||||
"module": "dist/esm/index.js",
|
||||
"scripts": {
|
||||
"start": "tsc --watch",
|
||||
"start-example": "cd example && npm start",
|
||||
"build": "tsc",
|
||||
"test": "npm run lint",
|
||||
"lint": "eslint --ignore-path .gitignore --ext .js --ext .ts --ext .tsx .",
|
||||
"lint": "eslint --ignore-path .eslintignore --ext .js --ext .ts --ext .tsx .",
|
||||
"format": "prettier --ignore-path .gitignore './**/*.{css,yml,js,ts,tsx,json}' --write",
|
||||
"release": "release-it --non-interactive",
|
||||
"changelog": "auto-changelog -p",
|
||||
@ -20,10 +21,12 @@
|
||||
"dist/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@oceanprotocol/squid": "^2.2.0",
|
||||
"@oceanprotocol/contracts": "^0.2.2",
|
||||
"@oceanprotocol/lib": "^0.1.2",
|
||||
"axios": "^0.19.2",
|
||||
"react": "^16.13.1",
|
||||
"web3connect": "^1.0.0-beta.33"
|
||||
"react": "^16.9.41",
|
||||
"web3": "^1.2.9",
|
||||
"web3modal": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@release-it/bumper": "^1.4.0",
|
||||
|
7
src/@types/globals.d.ts
vendored
7
src/@types/globals.d.ts
vendored
@ -4,10 +4,3 @@ import { HttpProvider } from 'web3-core'
|
||||
interface EthereumProvider extends HttpProvider {
|
||||
enable: () => Promise<void>
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
web3: Web3
|
||||
ethereum: EthereumProvider
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
export * from './useConsume'
|
||||
export * from './useMetadata'
|
||||
export * from './useCompute'
|
||||
export * from './useSearch'
|
||||
export * from './usePublish'
|
||||
|
@ -1,28 +0,0 @@
|
||||
export interface ComputeValue {
|
||||
entrypoint: string
|
||||
image: string
|
||||
tag: string
|
||||
}
|
||||
export interface ComputeOption {
|
||||
name: string
|
||||
value: ComputeValue
|
||||
}
|
||||
|
||||
export const computeOptions: ComputeOption[] = [
|
||||
{
|
||||
name: 'nodejs',
|
||||
value: {
|
||||
entrypoint: 'node $ALGO',
|
||||
image: 'node',
|
||||
tag: '10'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'python3.7',
|
||||
value: {
|
||||
entrypoint: 'python $ALGO',
|
||||
image: 'oceanprotocol/algo_dockers',
|
||||
tag: 'python-panda'
|
||||
}
|
||||
}
|
||||
]
|
@ -1,67 +0,0 @@
|
||||
# `useCompute`
|
||||
|
||||
Start a compute job on a data asset and retrieve its status.
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import React from 'react'
|
||||
import {
|
||||
useWeb3,
|
||||
useMetadata,
|
||||
useCompute,
|
||||
computeOptions,
|
||||
ComputeValue,
|
||||
readFileContent
|
||||
} from '@oceanprotocol/react'
|
||||
|
||||
const did = 'did:op:0x000000000'
|
||||
|
||||
export default function MyComponent() {
|
||||
// Get web3 from Web3Provider context
|
||||
const { web3, account } = useWeb3()
|
||||
|
||||
// Get metadata for this asset
|
||||
const { title, metadata } = useMetadata(did)
|
||||
|
||||
// compute asset
|
||||
const { compute, computeStep } = useCompute()
|
||||
|
||||
// raw code text
|
||||
const [algorithmRawCode, setAlgorithmRawCode] = useState('')
|
||||
const [computeContainer, setComputeContainer] = useState<ComputeValue>()
|
||||
async function handleCompute() {
|
||||
await consume(did,algorithmRawCode,computeContainer)
|
||||
}
|
||||
|
||||
async function onChangeHandler(event){
|
||||
const fileText = await readFileContent(files[0])
|
||||
setAlgorithmRawCode(fileText)
|
||||
}
|
||||
|
||||
async function handleSelectChange(event: any) {
|
||||
const comType = event.target.value
|
||||
setComputeContainer(comType)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{title}</h1>
|
||||
<p>Price: {web3.utils.fromWei(metadata.main.price)}</p>
|
||||
|
||||
<p>Your account: {account}</p>
|
||||
<label for="computeOptions">Select image to run the algorithm</label>
|
||||
<select id="computeOptions" onChange={handleSelectChange}>
|
||||
{computeOptions.map((x) => (
|
||||
<option value={x.value}>{x.name}</option>
|
||||
)
|
||||
}
|
||||
</select>
|
||||
<input type="file" name="file" onChange={onChangeHandler}/>
|
||||
<button onClick={handleCompute}>
|
||||
{computeStep || 'Start compute job'}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
@ -1,2 +0,0 @@
|
||||
export * from './useCompute'
|
||||
export * from './ComputeOptions'
|
@ -1,94 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
import { DID, MetaDataAlgorithm, Logger } from '@oceanprotocol/squid'
|
||||
import { useOcean } from '../../providers'
|
||||
import { ComputeValue } from './ComputeOptions'
|
||||
import { feedback } from './../../utils'
|
||||
|
||||
interface UseCompute {
|
||||
compute: (
|
||||
did: DID | string,
|
||||
algorithmRawCode: string,
|
||||
computeContainer: ComputeValue
|
||||
) => Promise<void>
|
||||
computeStep?: number
|
||||
computeStepText?: string
|
||||
computeError?: string
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
// TODO: customize for compute
|
||||
export const computeFeedback: { [key in number]: string } = {
|
||||
...feedback,
|
||||
4: '3/3 Access granted. Starting job...'
|
||||
}
|
||||
const rawAlgorithmMeta: MetaDataAlgorithm = {
|
||||
rawcode: `console.log('Hello world'!)`,
|
||||
format: 'docker-image',
|
||||
version: '0.1',
|
||||
container: {
|
||||
entrypoint: '',
|
||||
image: '',
|
||||
tag: ''
|
||||
}
|
||||
}
|
||||
|
||||
function useCompute(): UseCompute {
|
||||
const { ocean, account, accountId, config } = useOcean()
|
||||
const [computeStep, setComputeStep] = useState<number | undefined>()
|
||||
const [computeStepText, setComputeStepText] = useState<string | undefined>()
|
||||
const [computeError, setComputeError] = useState<string | undefined>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
async function compute(
|
||||
did: DID | string,
|
||||
algorithmRawCode: string,
|
||||
computeContainer: ComputeValue
|
||||
): Promise<void> {
|
||||
if (!ocean || !account) return
|
||||
|
||||
setComputeError(undefined)
|
||||
|
||||
try {
|
||||
setIsLoading(true)
|
||||
const computeOutput = {
|
||||
publishAlgorithmLog: false,
|
||||
publishOutput: false,
|
||||
brizoAddress: config.brizoAddress,
|
||||
brizoUri: config.brizoUri,
|
||||
metadataUri: config.aquariusUri,
|
||||
nodeUri: config.nodeUri,
|
||||
owner: accountId,
|
||||
secretStoreUri: config.secretStoreUri
|
||||
}
|
||||
const agreement = await ocean.compute
|
||||
.order(account, did as string)
|
||||
.next((step: number) => {
|
||||
setComputeStep(step)
|
||||
setComputeStepText(computeFeedback[step])
|
||||
})
|
||||
|
||||
rawAlgorithmMeta.container = computeContainer
|
||||
rawAlgorithmMeta.rawcode = algorithmRawCode
|
||||
setComputeStep(4)
|
||||
setComputeStepText(computeFeedback[4])
|
||||
await ocean.compute.start(
|
||||
account,
|
||||
agreement,
|
||||
undefined,
|
||||
rawAlgorithmMeta,
|
||||
computeOutput
|
||||
)
|
||||
} catch (error) {
|
||||
Logger.error(error)
|
||||
setComputeError(error.message)
|
||||
} finally {
|
||||
setComputeStep(undefined)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return { compute, computeStep, computeStepText, computeError, isLoading }
|
||||
}
|
||||
|
||||
export { useCompute, UseCompute }
|
||||
export default UseCompute
|
@ -1,10 +1,11 @@
|
||||
import { useState } from 'react'
|
||||
import { DID } from '@oceanprotocol/squid'
|
||||
import { useOcean } from '../../providers'
|
||||
import { feedback } from '../../utils'
|
||||
import { DID } from '@oceanprotocol/lib'
|
||||
import { ServiceType } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Service'
|
||||
|
||||
interface UseConsume {
|
||||
consume: (did: DID | string) => Promise<void>
|
||||
consume: (did: DID | string, serviceType: ServiceType) => Promise<void>
|
||||
consumeStep?: number
|
||||
consumeStepText?: string
|
||||
consumeError?: string
|
||||
@ -16,7 +17,7 @@ interface UseConsume {
|
||||
// instead of just a number
|
||||
export const consumeFeedback: { [key in number]: string } = {
|
||||
...feedback,
|
||||
4: '3/3 Access granted. Consuming file...'
|
||||
3: '3/3 Access granted. Consuming file...'
|
||||
}
|
||||
|
||||
function useConsume(): UseConsume {
|
||||
@ -26,30 +27,40 @@ function useConsume(): UseConsume {
|
||||
const [consumeStepText, setConsumeStepText] = useState<string | undefined>()
|
||||
const [consumeError, setConsumeError] = useState<string | undefined>()
|
||||
|
||||
async function consume(did: DID | string): Promise<void> {
|
||||
async function consume(did: string, serviceType: ServiceType): Promise<void> {
|
||||
if (!ocean || !account) return
|
||||
setIsLoading(true)
|
||||
setConsumeError(undefined)
|
||||
|
||||
try {
|
||||
const agreements = await ocean.keeper.conditions.accessSecretStoreCondition.getGrantedDidByConsumer(
|
||||
accountId
|
||||
)
|
||||
const agreement = agreements.find((el: { did: string }) => el.did === did)
|
||||
console.log('existing agre', agreements)
|
||||
const agreementId = agreement
|
||||
? agreement.agreementId
|
||||
: await ocean.assets
|
||||
.order(did as string, account)
|
||||
.next((step: number) => {
|
||||
setConsumeStep(step)
|
||||
setConsumeStepText(consumeFeedback[step])
|
||||
})
|
||||
setConsumeStep(0)
|
||||
setConsumeStepText(consumeFeedback[0])
|
||||
const ddo = await ocean.metadatastore.retrieveDDO(did)
|
||||
|
||||
setConsumeStep(1)
|
||||
setConsumeStepText(consumeFeedback[1])
|
||||
const order = await ocean.assets.order(did, serviceType, accountId)
|
||||
setConsumeStep(2)
|
||||
setConsumeStepText(consumeFeedback[2])
|
||||
const res = JSON.parse(order)
|
||||
const tokenTransfer = await ocean.datatokens.transfer(
|
||||
res.dataToken,
|
||||
res.to,
|
||||
res.numTokens,
|
||||
res.from
|
||||
)
|
||||
setConsumeStep(3)
|
||||
setConsumeStepText(consumeFeedback[3])
|
||||
await ocean.assets.download(
|
||||
did,
|
||||
(tokenTransfer as any).transactionHash,
|
||||
ddo.dataToken,
|
||||
account,
|
||||
''
|
||||
)
|
||||
|
||||
// manually add another step here for better UX
|
||||
setConsumeStep(4)
|
||||
setConsumeStepText(consumeFeedback[4])
|
||||
await ocean.assets.consume(agreementId, did as string, account, '')
|
||||
} catch (error) {
|
||||
setConsumeError(error.message)
|
||||
} finally {
|
||||
|
@ -1,54 +1,43 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import axios from 'axios'
|
||||
import { DID, DDO, MetaData, Curation } from '@oceanprotocol/squid'
|
||||
import { useOcean, OceanConnectionStatus } from '../../providers'
|
||||
import { DID, DDO, Metadata } from '@oceanprotocol/lib'
|
||||
import { useOcean } from '../../providers'
|
||||
import ProviderStatus from '../../providers/OceanProvider/ProviderStatus'
|
||||
|
||||
interface UseMetadata {
|
||||
ddo: DDO
|
||||
metadata: MetaData
|
||||
metadata: Metadata
|
||||
title: string
|
||||
getDDO: (did: DID | string) => Promise<DDO>
|
||||
getMetadata: (did: DID | string) => Promise<MetaData>
|
||||
getCuration: (did: DID | string) => Promise<Curation>
|
||||
getMetadata: (did: DID | string) => Promise<Metadata>
|
||||
getTitle: (did: DID | string) => Promise<string>
|
||||
getAllDIDs: () => Promise<DID[]>
|
||||
}
|
||||
|
||||
function useMetadata(did?: DID | string): UseMetadata {
|
||||
const { aquarius, config, status } = useOcean()
|
||||
const { ocean, status } = useOcean()
|
||||
const [ddo, setDDO] = useState<DDO | undefined>()
|
||||
const [metadata, setMetadata] = useState<MetaData | undefined>()
|
||||
const [metadata, setMetadata] = useState<Metadata | undefined>()
|
||||
const [title, setTitle] = useState<string | undefined>()
|
||||
|
||||
async function getDDO(did: DID | string): Promise<DDO> {
|
||||
if (status !== OceanConnectionStatus.CONNECTED) return
|
||||
if (status !== ProviderStatus.CONNECTED) return
|
||||
|
||||
const ddo = await aquarius.retrieveDDO(did)
|
||||
const ddo = await ocean.metadatastore.retrieveDDO(did)
|
||||
return ddo
|
||||
}
|
||||
|
||||
async function getMetadata(did: DID | string): Promise<MetaData> {
|
||||
async function getMetadata(did: DID | string): Promise<Metadata> {
|
||||
const ddo = await getDDO(did)
|
||||
if (!ddo) return
|
||||
const metadata = ddo.findServiceByType('metadata')
|
||||
return metadata.attributes
|
||||
}
|
||||
|
||||
async function getCuration(did: DID | string): Promise<Curation> {
|
||||
const metadata = await getMetadata(did)
|
||||
return metadata.curation
|
||||
}
|
||||
|
||||
async function getTitle(did: DID | string): Promise<string> {
|
||||
const metadata = await getMetadata(did)
|
||||
return metadata.main.name
|
||||
}
|
||||
|
||||
async function getAllDIDs(): Promise<DID[]> {
|
||||
const assets = await axios(`${config.aquariusUri}/api/v1/aquarius/assets`)
|
||||
return assets.data
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
async function init(): Promise<void> {
|
||||
if (!did) return
|
||||
@ -68,9 +57,7 @@ function useMetadata(did?: DID | string): UseMetadata {
|
||||
title,
|
||||
getDDO,
|
||||
getMetadata,
|
||||
getCuration,
|
||||
getTitle,
|
||||
getAllDIDs
|
||||
getTitle
|
||||
}
|
||||
}
|
||||
|
||||
|
1
src/hooks/usePublish/index.ts
Normal file
1
src/hooks/usePublish/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './usePublish'
|
125
src/hooks/usePublish/usePublish.ts
Normal file
125
src/hooks/usePublish/usePublish.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import { useEffect } from 'react'
|
||||
import { DDO, Metadata, DataTokens, Logger } from '@oceanprotocol/lib'
|
||||
import { useOcean } from '../../providers'
|
||||
import ProviderStatus from '../../providers/OceanProvider/ProviderStatus'
|
||||
import { Service } from '@oceanprotocol/lib/dist/node/ddo/interfaces/Service'
|
||||
|
||||
interface UsePublish {
|
||||
publish: (
|
||||
asset: Metadata,
|
||||
tokensToMint: number,
|
||||
price?: number
|
||||
) => Promise<DDO>
|
||||
mint: (tokenAddress: string, tokensToMint: number) => void
|
||||
}
|
||||
|
||||
function usePublish(): UsePublish {
|
||||
const { web3, ocean, status, account, accountId, config } = useOcean()
|
||||
|
||||
async function publish(
|
||||
asset: Metadata,
|
||||
tokensToMint: number,
|
||||
price = 1
|
||||
): Promise<DDO> {
|
||||
if (status !== ProviderStatus.CONNECTED) return
|
||||
|
||||
const datatoken = new DataTokens(
|
||||
ocean.datatokens.factoryAddress,
|
||||
(ocean.datatokens.factoryABI as any).abi,
|
||||
(ocean.datatokens.datatokensABI as any).abi,
|
||||
web3
|
||||
)
|
||||
|
||||
Logger.log('datatoken created', datatoken)
|
||||
const data = { t: 1, url: config.metadataStoreUri }
|
||||
const blob = JSON.stringify(data)
|
||||
const tokenAddress = await datatoken.create(blob, accountId)
|
||||
|
||||
Logger.log('tokensto mint', tokensToMint)
|
||||
|
||||
await datatoken.mint(tokenAddress, accountId, tokensToMint)
|
||||
|
||||
Logger.log('tokenAddress created', tokenAddress)
|
||||
const publishedDate = new Date(Date.now()).toISOString().split('.')[0] + 'Z'
|
||||
const timeout = 0
|
||||
let services: Service[] = []
|
||||
switch (asset.main.type) {
|
||||
case 'dataset': {
|
||||
const accessService = await ocean.assets.createAccessServiceAttributes(
|
||||
account,
|
||||
price.toString(),
|
||||
publishedDate,
|
||||
timeout
|
||||
)
|
||||
Logger.log('access service created', accessService)
|
||||
services = [accessService]
|
||||
break
|
||||
}
|
||||
case 'algorithm': {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const ddo = await ocean.assets.create(
|
||||
asset,
|
||||
account,
|
||||
services,
|
||||
tokenAddress
|
||||
)
|
||||
|
||||
return ddo
|
||||
}
|
||||
|
||||
async function mint(
|
||||
tokenAddress: string,
|
||||
tokensToMint: number,
|
||||
datatoken?: DataTokens
|
||||
) {
|
||||
if (datatoken === undefined)
|
||||
datatoken = new DataTokens(
|
||||
ocean.datatokens.factoryAddress,
|
||||
(ocean.datatokens.factoryABI as any).abi,
|
||||
(ocean.datatokens.datatokensABI as any).abi,
|
||||
web3
|
||||
)
|
||||
|
||||
await datatoken.mint(tokenAddress, accountId, tokensToMint)
|
||||
}
|
||||
|
||||
async function giveMarketAllowance(
|
||||
tokenAddress: string,
|
||||
marketAddress: string,
|
||||
tokens: number,
|
||||
datatoken?: DataTokens
|
||||
) {
|
||||
if (datatoken === undefined)
|
||||
datatoken = new DataTokens(
|
||||
ocean.datatokens.factoryAddress,
|
||||
(ocean.datatokens.factoryABI as any).abi,
|
||||
(ocean.datatokens.datatokensABI as any).abi,
|
||||
web3
|
||||
)
|
||||
|
||||
await datatoken.approve(tokenAddress, marketAddress, tokens, accountId)
|
||||
const allowance = await datatoken.allowance(
|
||||
tokenAddress,
|
||||
accountId,
|
||||
marketAddress
|
||||
)
|
||||
// allowance should be string not number, so this is a temp hack
|
||||
await datatoken.transferFrom(
|
||||
tokenAddress,
|
||||
accountId,
|
||||
(allowance as unknown) as number,
|
||||
marketAddress
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
publish,
|
||||
mint
|
||||
}
|
||||
}
|
||||
|
||||
export { usePublish, UsePublish }
|
||||
export default usePublish
|
@ -1,5 +0,0 @@
|
||||
import { DDO, ComputeJob } from '@oceanprotocol/squid'
|
||||
export interface ComputeItem {
|
||||
job: ComputeJob
|
||||
ddo: DDO
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from './useSearch'
|
||||
export * from './ComputeItem'
|
@ -1,136 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
import { Logger, DDO } from '@oceanprotocol/squid'
|
||||
import { useOcean } from '../../providers'
|
||||
import {
|
||||
SearchQuery,
|
||||
Aquarius,
|
||||
QueryResult
|
||||
} from '@oceanprotocol/squid/dist/node/aquarius/Aquarius'
|
||||
import { ComputeItem } from './ComputeItem'
|
||||
|
||||
// TODO searchText,
|
||||
interface UseSearch {
|
||||
searchWithQuery: (query: SearchQuery) => Promise<QueryResult>
|
||||
getPublishedList: (page: number, offset: number) => Promise<QueryResult>
|
||||
getConsumedList: () => Promise<DDO[] | undefined>
|
||||
getComputeItems: () => Promise<ComputeItem[] | undefined>
|
||||
searchError?: string
|
||||
}
|
||||
|
||||
function useSearch(): UseSearch {
|
||||
// should we call the useOcean hook in useSearch or in each function?
|
||||
const { ocean, account, config, accountId } = useOcean()
|
||||
const [searchError, setSearchError] = useState<string | undefined>()
|
||||
|
||||
async function searchWithQuery(query: SearchQuery): Promise<QueryResult> {
|
||||
if (!ocean || !account) return
|
||||
|
||||
setSearchError(undefined)
|
||||
|
||||
try {
|
||||
const aquarius = new Aquarius(config.aquariusUri as string, Logger)
|
||||
return await aquarius.queryMetadata(query)
|
||||
} catch (error) {
|
||||
setSearchError(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
async function getPublishedList(
|
||||
page: number,
|
||||
offset: number
|
||||
): Promise<QueryResult> {
|
||||
if (!ocean || !accountId) return
|
||||
|
||||
setSearchError(undefined)
|
||||
|
||||
try {
|
||||
const query = {
|
||||
page,
|
||||
offset,
|
||||
query: {
|
||||
'publicKey.owner': [accountId]
|
||||
},
|
||||
sort: {
|
||||
created: -1
|
||||
}
|
||||
} as SearchQuery
|
||||
|
||||
return await searchWithQuery(query)
|
||||
} catch (error) {
|
||||
setSearchError(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
async function getConsumedList(): Promise<DDO[] | undefined> {
|
||||
const consumed = await ocean.assets.consumerAssets(accountId)
|
||||
const consumedItems = await Promise.all(
|
||||
consumed.map(async (did) => {
|
||||
try {
|
||||
const ddo = await ocean.assets.resolve(did)
|
||||
if (ddo) {
|
||||
// Since we are getting assets from chain there might be
|
||||
// assets from other marketplaces. So return only those assets
|
||||
// whose serviceEndpoint contains the configured Aquarius URI.
|
||||
const { serviceEndpoint } = ddo.findServiceByType('metadata')
|
||||
if (serviceEndpoint?.includes(config.aquariusUri)) return ddo
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error(err)
|
||||
}
|
||||
})
|
||||
)
|
||||
const filteredConsumedItems = consumedItems.filter(
|
||||
(value) => typeof value !== 'undefined'
|
||||
)
|
||||
return filteredConsumedItems
|
||||
}
|
||||
|
||||
async function getComputeItems(): Promise<ComputeItem[] | undefined> {
|
||||
if (!ocean || !account) return
|
||||
const jobList = await ocean.compute.status(account)
|
||||
const computeItems = await Promise.all(
|
||||
jobList.map(async (job) => {
|
||||
if (!job) return
|
||||
try {
|
||||
const { did } = await ocean.keeper.agreementStoreManager.getAgreement(
|
||||
job.agreementId
|
||||
)
|
||||
if (
|
||||
did ===
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000'
|
||||
)
|
||||
return
|
||||
|
||||
const ddo = await ocean.assets.resolve(did)
|
||||
|
||||
if (ddo) {
|
||||
// Since we are getting assets from chain there might be
|
||||
// assets from other marketplaces. So return only those assets
|
||||
// whose serviceEndpoint contains the configured Aquarius URI.
|
||||
const { serviceEndpoint } = ddo.findServiceByType('metadata')
|
||||
if (serviceEndpoint?.includes(config.aquariusUri)) {
|
||||
return { job, ddo }
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error(err)
|
||||
}
|
||||
})
|
||||
)
|
||||
const filteredComputeItems = computeItems.filter(
|
||||
(value) => value !== undefined && typeof value.ddo !== 'undefined'
|
||||
)
|
||||
return filteredComputeItems
|
||||
}
|
||||
|
||||
return {
|
||||
searchWithQuery,
|
||||
getPublishedList,
|
||||
getConsumedList,
|
||||
getComputeItems,
|
||||
searchError
|
||||
}
|
||||
}
|
||||
|
||||
export { useSearch, UseSearch }
|
||||
export default useSearch
|
@ -2,5 +2,4 @@ export * from './providers'
|
||||
export * from './hooks'
|
||||
// export * from './components'
|
||||
|
||||
export * from './utils/curationUtils'
|
||||
export * from './utils'
|
||||
|
@ -1,8 +0,0 @@
|
||||
|
||||
enum OceanConnectionStatus {
|
||||
OCEAN_CONNECTION_ERROR = -1,
|
||||
NOT_CONNECTED = 0,
|
||||
CONNECTED = 1
|
||||
}
|
||||
|
||||
export default OceanConnectionStatus
|
@ -1,20 +1,22 @@
|
||||
import React, { useContext, useState, useEffect, createContext } from 'react'
|
||||
import { Ocean, Config, Account, Aquarius, Logger } from '@oceanprotocol/squid'
|
||||
import Balance from '@oceanprotocol/squid/dist/node/models/Balance'
|
||||
import { connectOcean } from './utils'
|
||||
import { useWeb3, InjectedProviderStatus } from '../Web3Provider'
|
||||
import OceanConnectionStatus from './OceanConnectionStatus'
|
||||
|
||||
import Web3 from 'web3'
|
||||
import ProviderStatus from './ProviderStatus'
|
||||
import { Ocean, Logger, Account, Config } from '@oceanprotocol/lib'
|
||||
import Web3Modal, { ICoreOptions } from 'web3modal'
|
||||
|
||||
interface OceanProviderValue {
|
||||
aquarius: Aquarius
|
||||
web3: Web3 | undefined
|
||||
web3Provider: any
|
||||
web3Modal: Web3Modal
|
||||
ocean: Ocean
|
||||
config: Config
|
||||
account: Account
|
||||
accountId: string
|
||||
balance: Balance
|
||||
balanceInOcean: string
|
||||
status: OceanConnectionStatus
|
||||
config: Config
|
||||
balance: string
|
||||
chainId: number | undefined
|
||||
status: ProviderStatus
|
||||
connect: (opts?: Partial<ICoreOptions>) => void
|
||||
logout: () => void
|
||||
}
|
||||
|
||||
const OceanContext = createContext(null)
|
||||
@ -25,79 +27,132 @@ function OceanProvider({
|
||||
}: {
|
||||
config: Config
|
||||
children: any
|
||||
}): any {
|
||||
}) {
|
||||
const [web3, setWeb3] = useState<Web3 | undefined>()
|
||||
const [web3Provider, setWeb3Provider] = useState<any | undefined>()
|
||||
const [ocean, setOcean] = useState<Ocean | undefined>()
|
||||
const [aquarius, setAquarius] = useState<Aquarius | undefined>()
|
||||
const [web3Modal, setWeb3Modal] = useState<Web3Modal>(null)
|
||||
const [chainId, setChainId] = useState<number | undefined>()
|
||||
const [account, setAccount] = useState<Account | undefined>()
|
||||
const [accountId, setAccountId] = useState<string | undefined>()
|
||||
const [balance, setBalance] = useState<Balance | undefined>()
|
||||
const [balanceInOcean, setBalanceInOcean] = useState<string | undefined>()
|
||||
const [status, setStatus] = useState<OceanConnectionStatus>(
|
||||
OceanConnectionStatus.NOT_CONNECTED
|
||||
)
|
||||
const { web3, ethProviderStatus } = useWeb3()
|
||||
const [balance, setBalance] = useState<string | undefined>()
|
||||
const [status, setStatus] = useState(ProviderStatus.NOT_AVAILABLE)
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// 1. On mount, connect to Aquarius instance right away
|
||||
// -------------------------------------------------------------
|
||||
function init() {
|
||||
Logger.log('Ocean Provider init')
|
||||
}
|
||||
|
||||
// On mount setup Web3Modal instance
|
||||
useEffect(() => {
|
||||
const aquarius = new Aquarius(config.aquariusUri, Logger)
|
||||
setAquarius(aquarius)
|
||||
init()
|
||||
}, [])
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// 2. Once `web3` becomes available, connect to the whole network
|
||||
// -------------------------------------------------------------
|
||||
useEffect(() => {
|
||||
if (!web3 || ethProviderStatus !== InjectedProviderStatus.CONNECTED) return
|
||||
async function init(): Promise<void> {
|
||||
const { ocean, account, accountId, balance } = await connectOcean(
|
||||
web3,
|
||||
config
|
||||
)
|
||||
setOcean(ocean)
|
||||
setStatus(OceanConnectionStatus.CONNECTED)
|
||||
setAccount(account)
|
||||
setAccountId(accountId)
|
||||
setBalance(balance)
|
||||
setBalanceInOcean(`${balance?.ocn}`)
|
||||
}
|
||||
async function connect(opts?: Partial<ICoreOptions>) {
|
||||
Logger.log('Connecting ....')
|
||||
const instance = new Web3Modal(opts)
|
||||
setWeb3Modal(instance)
|
||||
Logger.log('Web3Modal instance created', instance)
|
||||
const provider = await instance.connect()
|
||||
setWeb3Provider(provider)
|
||||
|
||||
try {
|
||||
init()
|
||||
} catch (error) {
|
||||
console.error(error.message)
|
||||
setStatus(OceanConnectionStatus.OCEAN_CONNECTION_ERROR)
|
||||
throw error.message
|
||||
}
|
||||
}, [web3])
|
||||
const web3 = new Web3(provider)
|
||||
setWeb3(web3)
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// 3. Once `ocean` becomes available, spit out some info about it
|
||||
// -------------------------------------------------------------
|
||||
useEffect(() => {
|
||||
async function debug(): Promise<void> {
|
||||
if (!ocean) return
|
||||
Logger.debug(
|
||||
`Ocean instance initiated with:\n ${JSON.stringify(config, null, 2)}`
|
||||
)
|
||||
Logger.debug(await ocean.versions.get())
|
||||
config.web3Provider = web3
|
||||
const ocean = await Ocean.getInstance(config)
|
||||
|
||||
setOcean(ocean)
|
||||
Logger.log('Ocean instance created ', ocean)
|
||||
Logger.log('Web3 created ', web3)
|
||||
setStatus(ProviderStatus.CONNECTED)
|
||||
const account = (await ocean.accounts.list())[0]
|
||||
setAccount(account)
|
||||
Logger.log('Account ', account)
|
||||
|
||||
const accountId = await getAccount(web3)
|
||||
setAccountId(accountId)
|
||||
Logger.log('account id', accountId)
|
||||
const balance = await getBalance(web3, accountId)
|
||||
setBalance(balance)
|
||||
Logger.log('balance', accountId)
|
||||
const chainId = web3 && (await web3.eth.getChainId())
|
||||
setChainId(chainId)
|
||||
Logger.log('chain id ', chainId)
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
// ToDo check how is the proper way to logout
|
||||
web3Modal.clearCachedProvider()
|
||||
}
|
||||
|
||||
async function getAccount(web3: Web3) {
|
||||
const accounts = await web3.eth.getAccounts()
|
||||
return accounts[0]
|
||||
}
|
||||
|
||||
async function getBalance(web3: Web3, address: string) {
|
||||
const balance = await web3.eth.getBalance(address)
|
||||
return Web3.utils.fromWei(balance)
|
||||
}
|
||||
|
||||
//
|
||||
// Listen for provider, account & network changes
|
||||
// and react to it
|
||||
//
|
||||
const handleConnect = async (provider: any) => {
|
||||
Logger.debug("Handling 'connect' event with payload", provider)
|
||||
}
|
||||
|
||||
const handleAccountsChanged = async (accounts: string[]) => {
|
||||
console.debug("Handling 'accountsChanged' event with payload", accounts)
|
||||
if (accounts.length > 0) {
|
||||
setAccountId(accounts[0])
|
||||
|
||||
if (web3) {
|
||||
const balance = await getBalance(web3, accounts[0])
|
||||
setBalance(balance)
|
||||
}
|
||||
}
|
||||
debug()
|
||||
}, [ocean])
|
||||
}
|
||||
|
||||
// ToDo need to handle this, it's not implemented
|
||||
const handleNetworkChanged = async (networkId: string | number) => {
|
||||
console.debug("Handling 'networkChanged' event with payload", networkId)
|
||||
web3Provider.autoRefreshOnNetworkChange = false
|
||||
// init(networkId)
|
||||
// handleConnect(ethProvider)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
web3Modal && web3Modal.on('connect', handleConnect)
|
||||
|
||||
if (web3Provider !== undefined && web3Provider !== null) {
|
||||
web3Provider.on('accountsChanged', handleAccountsChanged)
|
||||
web3Provider.on('networkChanged', handleNetworkChanged)
|
||||
|
||||
return () => {
|
||||
web3Provider.removeListener('accountsChanged', handleAccountsChanged)
|
||||
web3Provider.removeListener('networkChanged', handleNetworkChanged)
|
||||
}
|
||||
}
|
||||
}, [web3, web3Modal, web3Provider])
|
||||
|
||||
return (
|
||||
<OceanContext.Provider
|
||||
value={
|
||||
{
|
||||
web3,
|
||||
web3Provider,
|
||||
web3Modal,
|
||||
ocean,
|
||||
aquarius,
|
||||
account,
|
||||
accountId,
|
||||
balance,
|
||||
balanceInOcean,
|
||||
chainId,
|
||||
status,
|
||||
config
|
||||
config,
|
||||
connect,
|
||||
logout
|
||||
} as OceanProviderValue
|
||||
}
|
||||
>
|
||||
@ -109,10 +164,5 @@ function OceanProvider({
|
||||
// Helper hook to access the provider values
|
||||
const useOcean = (): OceanProviderValue => useContext(OceanContext)
|
||||
|
||||
export {
|
||||
OceanProvider,
|
||||
useOcean,
|
||||
OceanProviderValue,
|
||||
Config
|
||||
}
|
||||
export { OceanProvider, useOcean, OceanProviderValue }
|
||||
export default OceanProvider
|
||||
|
7
src/providers/OceanProvider/ProviderStatus.ts
Normal file
7
src/providers/OceanProvider/ProviderStatus.ts
Normal file
@ -0,0 +1,7 @@
|
||||
enum ProviderStatus {
|
||||
NOT_AVAILABLE = -1,
|
||||
NOT_CONNECTED = 0,
|
||||
CONNECTED = 1
|
||||
}
|
||||
|
||||
export default ProviderStatus
|
@ -1,2 +1,2 @@
|
||||
export * from './OceanProvider'
|
||||
export * from './OceanConnectionStatus'
|
||||
export * from './ProviderStatus'
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { Ocean, Config, Account, Logger } from '@oceanprotocol/squid'
|
||||
import Balance from '@oceanprotocol/squid/dist/node/models/Balance'
|
||||
import Web3 from 'web3'
|
||||
|
||||
export async function connectOcean(
|
||||
web3: Web3,
|
||||
config: Config
|
||||
): Promise<{
|
||||
ocean: Ocean
|
||||
account: Account
|
||||
accountId: string
|
||||
balance: Balance
|
||||
}> {
|
||||
Logger.debug('Connecting to Ocean...')
|
||||
const ocean = await Ocean.getInstance({
|
||||
web3Provider: web3.currentProvider,
|
||||
...config
|
||||
})
|
||||
Logger.debug('Ocean instance ready.')
|
||||
// TODO : ocean was not connected and yet i got here and account was undefined so getId() threw an unmanaged error
|
||||
const oceanAccounts = await ocean.accounts.list()
|
||||
const account = oceanAccounts[0]
|
||||
const accountId = account.getId()
|
||||
const balance = await account.getBalance()
|
||||
|
||||
return { ocean, account, accountId, balance }
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
# `Web3Provider`
|
||||
|
||||
To get you started, we added this basic `Web3Provider` which assumes an injected provider (like MetaMask), and will ask for user permissions automatically on first mount.
|
||||
|
||||
Also provides a `useWeb3` helper hook to access its context values from any component.
|
||||
|
||||
We suggest you replace this provider with a more complete solution, since there are many UX considerations not handled in that basic provider, like activate only on user intent, listen for account & network changes, display connection instructions and errors, etc.
|
||||
|
||||
Some great solutions we liked to work with:
|
||||
|
||||
- [web3-react](https://github.com/NoahZinsmeister/web3-react)
|
||||
- [web3modal](https://github.com/web3modal/web3modal)
|
||||
|
||||
## Usage
|
||||
|
||||
Wrap your whole app with the `Web3Provider`:
|
||||
|
||||
```tsx
|
||||
import { Web3Provider } from '@oceanprotocol/react'
|
||||
|
||||
function MyApp() {
|
||||
return (
|
||||
<Web3Provider>
|
||||
{({ web3, chainId, account, balance, enable }) => (
|
||||
<ul>
|
||||
<li>Web3 available: {`${Boolean(web3)}`}</li>
|
||||
<li>Chain ID: {chainId}</li>
|
||||
<li>Account: {account}</li>
|
||||
<li>Balance: {balance}</li>
|
||||
</ul>
|
||||
)}
|
||||
</Web3Provider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
You can then access the provider context values with the `useWeb3` hook:
|
||||
|
||||
```tsx
|
||||
import { useWeb3 } from '@oceanprotocol/react'
|
||||
|
||||
function MyComponent() {
|
||||
const { web3, chainId, account, balance, enable } = useWeb3()
|
||||
|
||||
return (
|
||||
<ul>
|
||||
<li>Web3 available: {`${Boolean(web3)}`}</li>
|
||||
<li>Chain ID: {chainId}</li>
|
||||
<li>Account: {account}</li>
|
||||
<li>Balance: {balance}</li>
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
```
|
@ -1,166 +0,0 @@
|
||||
import React, { useContext, useState, createContext, useEffect } from 'react'
|
||||
import Web3 from 'web3'
|
||||
import Web3Connect from 'web3connect'
|
||||
import { getWeb3 } from './utils'
|
||||
import Core from 'web3connect/lib/core'
|
||||
|
||||
export enum InjectedProviderStatus {
|
||||
NOT_AVAILABLE = -1,
|
||||
NOT_CONNECTED = 0,
|
||||
CONNECTED = 1
|
||||
}
|
||||
interface Web3ProviderValue {
|
||||
web3: Web3 | undefined
|
||||
web3Connect: Core
|
||||
account: string | undefined
|
||||
balance: string | undefined
|
||||
chainId: number | undefined
|
||||
ethProviderStatus: InjectedProviderStatus
|
||||
enable: () => void
|
||||
}
|
||||
|
||||
const Web3Context = createContext(null)
|
||||
|
||||
// TODO: this will have to be updated to web3modal
|
||||
function Web3Provider({ children }: { children: any }): any {
|
||||
const [web3, setWeb3] = useState<Web3 | undefined>()
|
||||
const [chainId, setChainId] = useState<number | undefined>()
|
||||
const [account, setAccount] = useState<string | undefined>()
|
||||
const [balance, setBalance] = useState<string | undefined>()
|
||||
const [ethProvider, setEthProvider] = useState<any>(null)
|
||||
const [ethProviderStatus, setEthProviderStatus] = useState(
|
||||
InjectedProviderStatus.NOT_AVAILABLE
|
||||
)
|
||||
const [web3Connect, setWeb3Connect] = useState<Core>(null)
|
||||
|
||||
useEffect(() => {
|
||||
async function initWeb3(): Promise<void> {
|
||||
const web3 = await getWeb3()
|
||||
setWeb3(web3)
|
||||
|
||||
const chainId = web3 && (await web3.eth.getChainId())
|
||||
setChainId(chainId)
|
||||
}
|
||||
initWeb3()
|
||||
}, [])
|
||||
|
||||
function init(networkId?: string | number) {
|
||||
const instance = new Web3Connect.Core({
|
||||
network: `${networkId}`,
|
||||
providerOptions: {}
|
||||
})
|
||||
setWeb3Connect(instance)
|
||||
|
||||
if (Web3Connect.checkInjectedProviders().injectedAvailable) {
|
||||
setEthProviderStatus(InjectedProviderStatus.NOT_CONNECTED)
|
||||
}
|
||||
}
|
||||
|
||||
// On mount setup Web3Connect instance & check for injected provider
|
||||
useEffect(() => {
|
||||
init()
|
||||
}, [])
|
||||
|
||||
async function getAccount(web3: Web3) {
|
||||
const accounts = await web3.eth.getAccounts()
|
||||
return accounts[0]
|
||||
}
|
||||
|
||||
async function getBalance(web3: Web3, address: string) {
|
||||
const balance = await web3.eth.getBalance(address)
|
||||
return Web3.utils.fromWei(balance)
|
||||
}
|
||||
|
||||
//
|
||||
// Listen for provider, account & network changes
|
||||
// and react to it
|
||||
//
|
||||
const handleConnect = async (provider: any) => {
|
||||
console.debug("Handling 'connect' event with payload", provider)
|
||||
setEthProvider(provider)
|
||||
setEthProviderStatus(InjectedProviderStatus.CONNECTED)
|
||||
|
||||
const web3 = new Web3(provider)
|
||||
setWeb3(web3)
|
||||
|
||||
const account = await getAccount(web3)
|
||||
setAccount(account)
|
||||
|
||||
const balance = await getBalance(web3, account)
|
||||
setBalance(balance)
|
||||
}
|
||||
|
||||
const handleAccountsChanged = async (accounts: string[]) => {
|
||||
console.debug("Handling 'accountsChanged' event with payload", accounts)
|
||||
if (accounts.length > 0) {
|
||||
setAccount(accounts[0])
|
||||
|
||||
if (web3) {
|
||||
const balance = await getBalance(web3, accounts[0])
|
||||
setBalance(balance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleNetworkChanged = async (networkId: string | number) => {
|
||||
console.debug("Handling 'networkChanged' event with payload", networkId)
|
||||
ethProvider.autoRefreshOnNetworkChange = false
|
||||
init(networkId)
|
||||
handleConnect(ethProvider)
|
||||
}
|
||||
|
||||
//
|
||||
// Setup event listeners.
|
||||
// Web3Connect only supports a 'connect', 'error', and 'close' event,
|
||||
// so we use the injected provider events to handle the rest.
|
||||
//
|
||||
useEffect(() => {
|
||||
web3Connect && web3Connect.on('connect', handleConnect)
|
||||
|
||||
if (ethProvider) {
|
||||
ethProvider.on('accountsChanged', handleAccountsChanged)
|
||||
ethProvider.on('networkChanged', handleNetworkChanged)
|
||||
|
||||
return () => {
|
||||
ethProvider.removeListener('accountsChanged', handleAccountsChanged)
|
||||
ethProvider.removeListener('networkChanged', handleNetworkChanged)
|
||||
}
|
||||
}
|
||||
}, [web3, web3Connect, ethProvider])
|
||||
|
||||
async function enable(): Promise<boolean> {
|
||||
try {
|
||||
// Request account access
|
||||
await window.ethereum.enable()
|
||||
return true
|
||||
} catch (error) {
|
||||
// User denied account access
|
||||
console.error('User denied account access to wallet.')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Web3Context.Provider
|
||||
value={
|
||||
{
|
||||
web3,
|
||||
web3Connect,
|
||||
chainId,
|
||||
account,
|
||||
balance,
|
||||
ethProviderStatus,
|
||||
enable
|
||||
} as Web3ProviderValue
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Web3Context.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
// Helper hook to access the provider values
|
||||
const useWeb3 = (): Web3ProviderValue => useContext(Web3Context)
|
||||
|
||||
export { Web3Provider, useWeb3, Web3ProviderValue }
|
||||
export default Web3Provider
|
@ -1 +0,0 @@
|
||||
export * from './Web3Provider'
|
@ -1,22 +0,0 @@
|
||||
import Web3 from 'web3'
|
||||
|
||||
async function getWeb3(): Promise<Web3> {
|
||||
let web3: Web3
|
||||
|
||||
// modern dapp browser
|
||||
if (window.ethereum) {
|
||||
web3 = new Web3(window.ethereum)
|
||||
}
|
||||
// legacy dapp browser
|
||||
else if (window.web3) {
|
||||
web3 = new Web3(window.web3.currentProvider)
|
||||
}
|
||||
// no dapp browser
|
||||
else {
|
||||
console.debug('Non-Ethereum browser detected.')
|
||||
}
|
||||
|
||||
return web3
|
||||
}
|
||||
|
||||
export { getWeb3 }
|
@ -1,2 +1 @@
|
||||
export * from './OceanProvider'
|
||||
export * from './Web3Provider'
|
||||
|
@ -1,84 +0,0 @@
|
||||
import axios, { AxiosResponse } from 'axios'
|
||||
import Web3 from 'web3'
|
||||
import { DID } from '@oceanprotocol/squid'
|
||||
|
||||
export declare type RatingResponse = [string, number]
|
||||
export declare type GetRatingResponse = {
|
||||
comment: string
|
||||
datePublished: string
|
||||
vote: number
|
||||
}
|
||||
|
||||
export function gethash(message: string): string {
|
||||
let hex = ''
|
||||
for (let i = 0; i < message.length; i++) {
|
||||
hex += '' + message.charCodeAt(i).toString(16)
|
||||
}
|
||||
const hexMessage = '0x' + hex
|
||||
return hexMessage
|
||||
}
|
||||
|
||||
export async function rateAsset({
|
||||
did,
|
||||
web3,
|
||||
value,
|
||||
configUrl
|
||||
}: {
|
||||
did: DID | string
|
||||
web3: Web3
|
||||
value: number
|
||||
configUrl: string
|
||||
}): Promise<RatingResponse | string> {
|
||||
try {
|
||||
const timestamp = Math.floor(+new Date() / 1000)
|
||||
const accounts = await web3.eth.getAccounts()
|
||||
const signature = await web3.eth.personal.sign(
|
||||
gethash(`${timestamp}`),
|
||||
accounts ? accounts[0] : '',
|
||||
''
|
||||
)
|
||||
const ratingBody = {
|
||||
did,
|
||||
vote: value,
|
||||
comment: '',
|
||||
address: accounts[0],
|
||||
timestamp: timestamp,
|
||||
signature: signature
|
||||
}
|
||||
|
||||
const response: AxiosResponse = await axios.post(configUrl, ratingBody)
|
||||
if (!response) return 'No Response'
|
||||
return response.data
|
||||
} catch (error) {
|
||||
console.error(error.message)
|
||||
return `Error: ${error.message}`
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAssetRating({
|
||||
did,
|
||||
account,
|
||||
configUrl
|
||||
}: {
|
||||
did: DID | string
|
||||
account: string
|
||||
configUrl: string
|
||||
}): Promise<GetRatingResponse | undefined> {
|
||||
try {
|
||||
if (!account) return
|
||||
|
||||
const response = await axios.get(configUrl, {
|
||||
params: {
|
||||
did: did,
|
||||
address: account
|
||||
}
|
||||
})
|
||||
const votesLength = response.data.length
|
||||
|
||||
if (votesLength > 0) {
|
||||
return response.data[votesLength - 1]
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error.message)
|
||||
}
|
||||
}
|
@ -14,8 +14,7 @@ export function readFileContent(file: File): Promise<string> {
|
||||
|
||||
export const feedback: { [key in number]: string } = {
|
||||
99: 'Decrypting file URL...',
|
||||
0: '1/3 Asking for agreement signature...',
|
||||
1: '1/3 Agreement initialized.',
|
||||
2: '2/3 Asking for two payment confirmations...',
|
||||
3: '2/3 Payment confirmed. Requesting access...'
|
||||
0: '1/3 Ordering asset...',
|
||||
1: '1/3 Transfering data token.',
|
||||
2: '2/3 Payment confirmed. Requesting access...'
|
||||
}
|
||||
|
@ -8,7 +8,9 @@
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true
|
||||
"declaration": true,
|
||||
"strictNullChecks": false
|
||||
},
|
||||
"include": ["./src/@types", "./src/index.ts"]
|
||||
"include": ["./src/@types", "./src/index.ts"],
|
||||
"exclude": ["node_modules", "dist", "example"]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user