1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

Feature/wagmi (#1912)

* wagmi + ethers + web3modal setup

* refactor wallet components

* fallback providers, more config

* kick out useWeb3

* remove all useWeb3 imports

* more web3.js usage removal

* isAddress utils replacement

* restore add token / add network

* less accountId changes

* web3 legacy tinkering, utils/web3 → utils/wallet

* legacy web3 object for ocean.js

* graph sync fix, remove custom network switching code

* package updates, merge fixes

* downgrade to ethers v5

* fix project id

* switch to ConnectKit

* connectkit theming

* add existing chains to wagmi

* rewrite getPaymentCollector()

* kick out getPaymentCollector completely, use wagmi hooks instead

* Revert "kick out getPaymentCollector completely, use wagmi hooks instead"

This reverts commit 54c7d1ef1a.

* switch getPaymentCollector

* calcBaseInGivenDatatokensOut reorg

* wip integrate ocean lib 3.0.0

* update orbis components to use wagmi instead of web hooks

* more oceanjs integration updates

* more refactors

* fix build

* update ocean lib

* fix publish

* fix order fixed rate

* remove logs

* debug and stop infinite cycle orbis connect

* fix orbis dm connection

* mock use network and fix some more tests

* mock wagmi switch network

* mock wagmi  useProvider createClient and connectKit getDefaultClient

* fix jest tests

* try storybook fix

* cleanups and bump ocean lib

* fix order

* bump lib to next.5 and add more modal style

* bump ocean.js lib to 3.0.0

---------

Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
Bogdan Fazakas 2023-05-29 13:28:41 +03:00 committed by GitHub
parent ecef35ef61
commit 165a9b0fb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 10685 additions and 3247 deletions

View File

@ -1,4 +1,5 @@
#NEXT_PUBLIC_INFURA_PROJECT_ID="xxx" #NEXT_PUBLIC_INFURA_PROJECT_ID="xxx"
#NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID="xxx"
#NEXT_PUBLIC_MARKET_FEE_ADDRESS="0xxx" #NEXT_PUBLIC_MARKET_FEE_ADDRESS="0xxx"
#NEXT_PUBLIC_PUBLISHER_MARKET_ORDER_FEE="1" #NEXT_PUBLIC_PUBLISHER_MARKET_ORDER_FEE="1"
#NEXT_PUBLIC_PUBLISHER_MARKET_FIXED_SWAP_FEE="1" #NEXT_PUBLIC_PUBLISHER_MARKET_FIXED_SWAP_FEE="1"

View File

@ -0,0 +1,5 @@
export const network = {
account: '0x123',
chainId: 1,
networkId: 1
}

View File

@ -0,0 +1,3 @@
export function getDefaultClient() {
return jest.fn()
}

View File

@ -1,6 +1,6 @@
import marketMetadata from '../__fixtures__/marketMetadata' import marketMetadata from '../__fixtures__/marketMetadata'
import userPreferences from '../__fixtures__/userPreferences' import userPreferences from '../__fixtures__/userPreferences'
import web3 from '../__fixtures__/web3' import { network } from '../__fixtures__/wagni'
import { asset } from '../__fixtures__/datasetWithAccessDetails' import { asset } from '../__fixtures__/datasetWithAccessDetails'
jest.mock('../../src/@context/MarketMetadata', () => ({ jest.mock('../../src/@context/MarketMetadata', () => ({
@ -11,10 +11,13 @@ jest.mock('../../src/@context/UserPreferences', () => ({
useUserPreferences: () => userPreferences useUserPreferences: () => userPreferences
})) }))
jest.mock('../../src/@context/Web3', () => ({
useWeb3: () => web3
}))
jest.mock('../../../@context/Asset', () => ({ jest.mock('../../../@context/Asset', () => ({
useAsset: () => ({ asset }) useAsset: () => ({ asset })
})) }))
jest.mock('wagmi', () => ({
useNetwork: () => ({ network }),
useSwitchNetwork: () => ({ switchNetwork: () => jest.fn() }),
useProvider: () => jest.fn(),
createClient: () => jest.fn()
}))

View File

@ -2,6 +2,7 @@ import '@testing-library/jest-dom/extend-expect'
import { jest } from '@jest/globals' import { jest } from '@jest/globals'
import './__mocks__/matchMedia' import './__mocks__/matchMedia'
import './__mocks__/hooksMocks' import './__mocks__/hooksMocks'
import './__mocks__/connectkit'
jest.mock('next/router', () => ({ jest.mock('next/router', () => ({
useRouter: jest.fn().mockImplementation(() => ({ useRouter: jest.fn().mockImplementation(() => ({

View File

@ -43,7 +43,10 @@ module.exports = {
crypto: false, crypto: false,
os: false, os: false,
stream: false, stream: false,
assert: false assert: false,
tls: false,
net: false,
zlib: false
}) })
config.resolve.fallback = fallback config.resolve.fallback = fallback

View File

@ -238,12 +238,12 @@ function Component() {
For account purgatory: For account purgatory:
```tsx ```tsx
import { useWeb3 } from '@context/Web3' import { useAccount } from 'wagmi'
import { useAccountPurgatory } from '@hooks/useAccountPurgatory' import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
function Component() { function Component() {
const { accountId } = useWeb3() const { address } = useAccount()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId) const { isInPurgatory, purgatoryData } = useAccountPurgatory(address)
return isInPurgatory ? <div>{purgatoryData.reason}</div> : null return isInPurgatory ? <div>{purgatoryData.reason}</div> : null
} }
``` ```
@ -252,14 +252,12 @@ function Component() {
All displayed chain & network metadata is retrieved from `https://chainid.network` on build time and integrated into NEXT's GraphQL layer. This data source is a community-maintained GitHub repository under [ethereum-lists/chains](https://github.com/ethereum-lists/chains). All displayed chain & network metadata is retrieved from `https://chainid.network` on build time and integrated into NEXT's GraphQL layer. This data source is a community-maintained GitHub repository under [ethereum-lists/chains](https://github.com/ethereum-lists/chains).
Within components this metadata can be queried for under `allNetworksMetadataJson`. The `useWeb3()` hook does this in the background to expose the final `networkDisplayName` for use in components: Within components this metadata can be queried for under `allNetworksMetadataJson`. The `useNetworkMetadata()` hook does this in the background to expose the final `networkDisplayName` for use in components:
```tsx ```tsx
export default function NetworkName(): ReactElement { export default function NetworkName(): ReactElement {
const { networkId, isTestnet } = useWeb3() const { isTestnet } = useNetworkMetadata()
const { networksList } = useNetworkMetadata() const { networkData, networkName } = useNetworkMetadata()
const networkData = getNetworkDataById(networksList, networkId)
const networkName = getNetworkDisplayName(networkData)
return ( return (
<> <>

View File

@ -16,8 +16,6 @@ module.exports = {
// List of all supported chainIds. Used to populate the Chains user preferences list. // List of all supported chainIds. Used to populate the Chains user preferences list.
chainIdsSupported: [1, 137, 56, 246, 1285, 5, 80001], chainIdsSupported: [1, 137, 56, 246, 1285, 5, 80001],
infuraProjectId: process.env.NEXT_PUBLIC_INFURA_PROJECT_ID || 'xxx',
defaultDatatokenTemplateIndex: 2, defaultDatatokenTemplateIndex: 2,
// The ETH address the marketplace fee will be sent to. // The ETH address the marketplace fee will be sent to.
marketFeeAddress: marketFeeAddress:

View File

@ -36,7 +36,9 @@ module.exports = (phase, { defaultConfig }) => {
crypto: false, crypto: false,
os: false, os: false,
stream: false, stream: false,
assert: false assert: false,
tls: false,
net: false
}) })
config.resolve.fallback = fallback config.resolve.fallback = fallback

11848
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -29,20 +29,20 @@
"@coingecko/cryptoformat": "^0.5.4", "@coingecko/cryptoformat": "^0.5.4",
"@loadable/component": "^5.15.2", "@loadable/component": "^5.15.2",
"@oceanprotocol/art": "^3.2.0", "@oceanprotocol/art": "^3.2.0",
"@oceanprotocol/lib": "^2.7.0", "@oceanprotocol/lib": "^3.0.0",
"@oceanprotocol/typographies": "^0.1.0", "@oceanprotocol/typographies": "^0.1.0",
"@oceanprotocol/use-dark-mode": "^2.4.3", "@oceanprotocol/use-dark-mode": "^2.4.3",
"@orbisclub/orbis-sdk": "^0.4.40", "@orbisclub/orbis-sdk": "^0.4.40",
"@tippyjs/react": "^4.2.6", "@tippyjs/react": "^4.2.6",
"@uiw/react-codemirror": "^4.19.5", "@uiw/react-codemirror": "^4.19.5",
"@urql/exchange-refocus": "^1.0.0", "@urql/exchange-refocus": "^1.0.0",
"@walletconnect/web3-provider": "^1.8.0",
"axios": "^1.2.0", "axios": "^1.2.0",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"connectkit": "^1.2.3",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"decimal.js": "^10.4.2", "decimal.js": "^10.4.2",
"dom-confetti": "^0.2.2", "dom-confetti": "^0.2.2",
"dotenv": "^16.0.3", "ethers": "^5.7.2",
"filesize": "^10.0.7", "filesize": "^10.0.7",
"formik": "^2.2.9", "formik": "^2.2.9",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
@ -52,6 +52,7 @@
"match-sorter": "^6.3.1", "match-sorter": "^6.3.1",
"myetherwallet-blockies": "^0.1.1", "myetherwallet-blockies": "^0.1.1",
"next": "13.0.5", "next": "13.0.5",
"npm": "^9.6.5",
"posthog-js": "^1.51.4", "posthog-js": "^1.51.4",
"query-string": "^8.1.0", "query-string": "^8.1.0",
"react": "^18.2.0", "react": "^18.2.0",
@ -73,8 +74,7 @@
"slugify": "^1.6.5", "slugify": "^1.6.5",
"swr": "^1.3.0", "swr": "^1.3.0",
"urql": "^3.0.3", "urql": "^3.0.3",
"web3": "^1.8.1", "wagmi": "^0.12.12",
"web3modal": "^1.9.12",
"yup": "^0.32.11" "yup": "^0.32.11"
}, },
"devDependencies": { "devDependencies": {

View File

@ -10,7 +10,6 @@ import React, {
import { Config, LoggerInstance, Purgatory } from '@oceanprotocol/lib' import { Config, LoggerInstance, Purgatory } from '@oceanprotocol/lib'
import { CancelToken } from 'axios' import { CancelToken } from 'axios'
import { getAsset } from '@utils/aquarius' import { getAsset } from '@utils/aquarius'
import { useWeb3 } from './Web3'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean' import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean'
import { getAccessDetails } from '@utils/accessDetailsAndPricing' import { getAccessDetails } from '@utils/accessDetailsAndPricing'
@ -18,6 +17,7 @@ import { useIsMounted } from '@hooks/useIsMounted'
import { useMarketMetadata } from './MarketMetadata' import { useMarketMetadata } from './MarketMetadata'
import { assetStateToString } from '@utils/assetState' import { assetStateToString } from '@utils/assetState'
import { isValidDid } from '@utils/ddo' import { isValidDid } from '@utils/ddo'
import { useAccount, useNetwork } from 'wagmi'
export interface AssetProviderValue { export interface AssetProviderValue {
isInPurgatory: boolean isInPurgatory: boolean
@ -44,8 +44,9 @@ function AssetProvider({
children: ReactNode children: ReactNode
}): ReactElement { }): ReactElement {
const { appConfig } = useMarketMetadata() const { appConfig } = useMarketMetadata()
const { address: accountId } = useAccount()
const { chain } = useNetwork()
const { chainId, accountId } = useWeb3()
const [isInPurgatory, setIsInPurgatory] = useState(false) const [isInPurgatory, setIsInPurgatory] = useState(false)
const [purgatoryData, setPurgatoryData] = useState<Purgatory>() const [purgatoryData, setPurgatoryData] = useState<Purgatory>()
const [asset, setAsset] = useState<AssetExtended>() const [asset, setAsset] = useState<AssetExtended>()
@ -158,11 +159,11 @@ function AssetProvider({
// Check user network against asset network // Check user network against asset network
// ----------------------------------- // -----------------------------------
useEffect(() => { useEffect(() => {
if (!chainId || !asset?.chainId) return if (!chain?.id || !asset?.chainId) return
const isAssetNetwork = chainId === asset?.chainId const isAssetNetwork = chain?.id === asset?.chainId
setIsAssetNetwork(isAssetNetwork) setIsAssetNetwork(isAssetNetwork)
}, [chainId, asset?.chainId]) }, [chain?.id, asset?.chainId])
// ----------------------------------- // -----------------------------------
// Asset owner check against wallet user // Asset owner check against wallet user

View File

@ -9,8 +9,8 @@ import React, {
} from 'react' } from 'react'
import { useInterval } from '@hooks/useInterval' import { useInterval } from '@hooks/useInterval'
import { Orbis } from '@orbisclub/orbis-sdk' import { Orbis } from '@orbisclub/orbis-sdk'
import { useWeb3 } from '../Web3' import { accountTruncate } from '@utils/wallet'
import { accountTruncate } from '@utils/web3' import { useAccount, useSigner, useProvider } from 'wagmi'
import { didToAddress, sleep } from '@shared/DirectMessages/_utils' import { didToAddress, sleep } from '@shared/DirectMessages/_utils'
import { getEnsName } from '@utils/ens' import { getEnsName } from '@utils/ens'
import usePrevious from '@hooks/usePrevious' import usePrevious from '@hooks/usePrevious'
@ -32,7 +32,9 @@ const CONVERSATION_CONTEXT =
process.env.NEXT_PUBLIC_ORBIS_CONTEXT || 'ocean_market' // Can be changed to whatever process.env.NEXT_PUBLIC_ORBIS_CONTEXT || 'ocean_market' // Can be changed to whatever
function OrbisProvider({ children }: { children: ReactNode }): ReactElement { function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
const { web3Provider, accountId } = useWeb3() const { address: accountId } = useAccount()
const { data: signer } = useSigner()
const web3Provider = useProvider()
const prevAccountId = usePrevious(accountId) const prevAccountId = usePrevious(accountId)
const [ceramicSessions, setCeramicSessions] = useLocalStorage<string[]>( const [ceramicSessions, setCeramicSessions] = useLocalStorage<string[]>(
@ -81,12 +83,12 @@ function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
address: string address: string
lit?: boolean lit?: boolean
}) => { }) => {
const signerProvide: any = signer?.provider
const res = await orbis.connect_v2({ const res = await orbis.connect_v2({
provider: web3Provider, provider: signerProvide.provider,
chain: 'ethereum', chain: 'ethereum',
lit lit
}) })
if (res.status === 200) { if (res.status === 200) {
const { data } = await orbis.getProfile(res.did) const { data } = await orbis.getProfile(res.did)
setAccount(data) setAccount(data)
@ -98,7 +100,7 @@ function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
}) })
return data return data
} else { } else {
await connectOrbis({ address }) // await connectOrbis({ address })
} }
} }
@ -137,8 +139,12 @@ function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
setAccount(data) setAccount(data)
return data return data
} else if (autoConnect) { } else if (autoConnect) {
const data = await connectOrbis({ address, lit }) try {
return data const data = await connectOrbis({ address, lit })
return data
} catch (err) {
return null
}
} else { } else {
resetStates() resetStates()
removeLitSignature() removeLitSignature()

View File

@ -7,7 +7,6 @@ export interface OpcFee {
export interface AppConfig { export interface AppConfig {
metadataCacheUri: string metadataCacheUri: string
infuraProjectId: string
chainIds: number[] chainIds: number[]
chainIdsSupported: number[] chainIdsSupported: number[]
defaultDatatokenTemplateIndex: number defaultDatatokenTemplateIndex: number
@ -49,4 +48,5 @@ export interface MarketMetadataProviderValue {
siteContent: SiteContent siteContent: SiteContent
appConfig: AppConfig appConfig: AppConfig
getOpcFeeForToken: (tokenAddress: string, chainId: number) => string getOpcFeeForToken: (tokenAddress: string, chainId: number) => string
approvedBaseTokens: TokenInfo[]
} }

View File

@ -13,8 +13,13 @@ import { opcQuery } from './_queries'
import { MarketMetadataProviderValue, OpcFee } from './_types' import { MarketMetadataProviderValue, OpcFee } from './_types'
import siteContent from '../../../content/site.json' import siteContent from '../../../content/site.json'
import appConfig from '../../../app.config' import appConfig from '../../../app.config'
import { fetchData, getQueryContext } from '@utils/subgraph' import {
fetchData,
getQueryContext,
getOpcsApprovedTokens
} from '@utils/subgraph'
import { LoggerInstance } from '@oceanprotocol/lib' import { LoggerInstance } from '@oceanprotocol/lib'
import { useNetwork, useConnect } from 'wagmi'
const MarketMetadataContext = createContext({} as MarketMetadataProviderValue) const MarketMetadataContext = createContext({} as MarketMetadataProviderValue)
@ -23,7 +28,11 @@ function MarketMetadataProvider({
}: { }: {
children: ReactNode children: ReactNode
}): ReactElement { }): ReactElement {
const { isLoading } = useConnect()
const { chain } = useNetwork()
const [opcFees, setOpcFees] = useState<OpcFee[]>() const [opcFees, setOpcFees] = useState<OpcFee[]>()
const [approvedBaseTokens, setApprovedBaseTokens] = useState<TokenInfo[]>()
useEffect(() => { useEffect(() => {
async function getOpcData() { async function getOpcData() {
@ -64,6 +73,28 @@ function MarketMetadataProvider({
}, },
[opcFees] [opcFees]
) )
// -----------------------------------
// Get and set approved base tokens list
// -----------------------------------
const getApprovedBaseTokens = useCallback(async (chainId: number) => {
try {
const approvedTokensList = await getOpcsApprovedTokens(chainId)
setApprovedBaseTokens(approvedTokensList)
LoggerInstance.log(
'[MarketMetadata] Approved baseTokens',
approvedTokensList
)
} catch (error) {
LoggerInstance.error('[MarketMetadata] Error: ', error.message)
}
}, [])
useEffect(() => {
if (isLoading) return
getApprovedBaseTokens(chain?.id || 1)
}, [chain?.id, getApprovedBaseTokens, isLoading])
return ( return (
<MarketMetadataContext.Provider <MarketMetadataContext.Provider
value={ value={
@ -71,7 +102,8 @@ function MarketMetadataProvider({
opcFees, opcFees,
siteContent, siteContent,
appConfig, appConfig,
getOpcFeeForToken getOpcFeeForToken,
approvedBaseTokens
} as MarketMetadataProviderValue } as MarketMetadataProviderValue
} }
> >

View File

@ -16,9 +16,9 @@ import {
getUserSales getUserSales
} from '@utils/aquarius' } from '@utils/aquarius'
import axios, { CancelToken } from 'axios' import axios, { CancelToken } from 'axios'
import web3 from 'web3'
import { useMarketMetadata } from '../MarketMetadata' import { useMarketMetadata } from '../MarketMetadata'
import { getEnsProfile } from '@utils/ens' import { getEnsProfile } from '@utils/ens'
import { isAddress } from 'ethers/lib/utils'
interface ProfileProviderValue { interface ProfileProviderValue {
profile: Profile profile: Profile
@ -64,7 +64,7 @@ function ProfileProvider({
// when accountId is no ETH address // when accountId is no ETH address
// //
useEffect(() => { useEffect(() => {
const isEthAddress = web3.utils.isAddress(accountId) const isEthAddress = isAddress(accountId)
setIsEthAddress(isEthAddress) setIsEthAddress(isEthAddress)
}, [accountId]) }, [accountId])

View File

@ -1,442 +0,0 @@
import React, {
useContext,
useState,
useEffect,
createContext,
ReactElement,
ReactNode,
useCallback
} from 'react'
import Web3 from 'web3'
import Web3Modal, { getProviderInfo, IProviderInfo } from 'web3modal'
import { infuraProjectId as infuraId } from '../../app.config'
import WalletConnectProvider from '@walletconnect/web3-provider'
import { LoggerInstance } from '@oceanprotocol/lib'
import { isBrowser } from '@utils/index'
import { getEnsProfile } from '@utils/ens'
import useNetworkMetadata, {
getNetworkDataById,
getNetworkDisplayName,
getNetworkType,
NetworkType
} from '../@hooks/useNetworkMetadata'
import { useMarketMetadata } from './MarketMetadata'
import { getTokenBalance } from '@utils/web3'
import { getOpcsApprovedTokens } from '@utils/subgraph'
interface Web3ProviderValue {
web3: Web3
// eslint-disable-next-line @typescript-eslint/no-explicit-any
web3Provider: any
web3Modal: Web3Modal
web3ProviderInfo: IProviderInfo
accountId: string
accountEns: string
accountEnsAvatar: string
balance: UserBalance
networkId: number
chainId: number
networkDisplayName: string
networkData: EthereumListsChain
block: number
isTestnet: boolean
web3Loading: boolean
isSupportedOceanNetwork: boolean
approvedBaseTokens: TokenInfo[]
connect: () => Promise<string>
logout: () => Promise<void>
}
const web3ModalTheme = {
background: 'var(--background-body)',
main: 'var(--font-color-heading)',
secondary: 'var(--brand-grey-light)',
border: 'var(--border-color)',
hover: 'var(--background-highlight)'
}
const providerOptions = isBrowser
? {
walletconnect: {
package: WalletConnectProvider,
options: {
infuraId,
rpc: {
137: 'https://polygon-rpc.com',
80001: 'https://rpc-mumbai.matic.today'
}
}
}
}
: {}
export const web3ModalOpts = {
cacheProvider: true,
providerOptions,
theme: web3ModalTheme
}
const refreshInterval = 20000 // 20 sec.
const Web3Context = createContext({} as Web3ProviderValue)
function Web3Provider({ children }: { children: ReactNode }): ReactElement {
const { networksList } = useNetworkMetadata()
const { appConfig } = useMarketMetadata()
const [web3, setWeb3] = useState<Web3>()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [web3Provider, setWeb3Provider] = useState<any>()
const [web3Modal, setWeb3Modal] = useState<Web3Modal>()
const [web3ProviderInfo, setWeb3ProviderInfo] = useState<IProviderInfo>()
const [networkId, setNetworkId] = useState<number>()
const [chainId, setChainId] = useState<number>()
const [networkDisplayName, setNetworkDisplayName] = useState<string>()
const [networkData, setNetworkData] = useState<EthereumListsChain>()
const [block, setBlock] = useState<number>()
const [isTestnet, setIsTestnet] = useState<boolean>()
const [accountId, setAccountId] = useState<string>()
const [accountEns, setAccountEns] = useState<string>()
const [accountEnsAvatar, setAccountEnsAvatar] = useState<string>()
const [web3Loading, setWeb3Loading] = useState<boolean>(true)
const [balance, setBalance] = useState<UserBalance>({
eth: '0'
})
const [isSupportedOceanNetwork, setIsSupportedOceanNetwork] = useState(true)
const [approvedBaseTokens, setApprovedBaseTokens] = useState<TokenInfo[]>()
// -----------------------------------
// Helper: connect to web3
// -----------------------------------
const connect = useCallback(async () => {
if (!web3Modal) {
setWeb3Loading(false)
return
}
try {
setWeb3Loading(true)
LoggerInstance.log('[web3] Connecting Web3...')
const provider = await web3Modal?.connect()
setWeb3Provider(provider)
const web3 = new Web3(provider)
setWeb3(web3)
LoggerInstance.log('[web3] Web3 created.', web3)
const networkId = await web3.eth.net.getId()
setNetworkId(networkId)
LoggerInstance.log('[web3] network id ', networkId)
const chainId = await web3.eth.getChainId()
setChainId(chainId)
LoggerInstance.log('[web3] chain id ', chainId)
const accountId = (await web3.eth.getAccounts())[0]
setAccountId(accountId)
LoggerInstance.log('[web3] account id', accountId)
return accountId
} catch (error) {
LoggerInstance.error('[web3] Error: ', error.message)
return null
} finally {
setWeb3Loading(false)
}
}, [web3Modal])
// -----------------------------------
// Helper: Get approved base tokens list
// -----------------------------------
const getApprovedBaseTokens = useCallback(async (chainId: number) => {
try {
const approvedTokensList = await getOpcsApprovedTokens(chainId)
setApprovedBaseTokens(approvedTokensList)
LoggerInstance.log('[web3] Approved baseTokens', approvedTokensList)
} catch (error) {
LoggerInstance.error('[web3] Error: ', error.message)
}
}, [])
// -----------------------------------
// Helper: Get user balance
// -----------------------------------
const getUserBalance = useCallback(async () => {
if (!accountId || !networkId || !web3 || !networkData) return
try {
const userBalance = web3.utils.fromWei(
await web3.eth.getBalance(accountId, 'latest')
)
const key = networkData.nativeCurrency.symbol.toLowerCase()
const balance: UserBalance = { [key]: userBalance }
if (approvedBaseTokens?.length > 0) {
await Promise.all(
approvedBaseTokens.map(async (token) => {
const { address, decimals, symbol } = token
const tokenBalance = await getTokenBalance(
accountId,
decimals,
address,
web3
)
balance[symbol.toLocaleLowerCase()] = tokenBalance
})
)
}
setBalance(balance)
LoggerInstance.log('[web3] Balance: ', balance)
} catch (error) {
LoggerInstance.error('[web3] Error: ', error.message)
}
}, [accountId, approvedBaseTokens, networkId, web3, networkData])
// -----------------------------------
// Helper: Get user ENS info
// -----------------------------------
const getUserEns = useCallback(async () => {
if (!accountId) return
try {
const profile = await getEnsProfile(accountId)
if (!profile) {
setAccountEns(null)
setAccountEnsAvatar(null)
return
}
setAccountEns(profile.name)
LoggerInstance.log(
`[web3] ENS name found for ${accountId}:`,
profile.name
)
if (profile.avatar) {
setAccountEnsAvatar(profile.avatar)
LoggerInstance.log(
`[web3] ENS avatar found for ${accountId}:`,
profile.avatar
)
} else {
setAccountEnsAvatar(null)
}
} catch (error) {
LoggerInstance.error('[web3] Error: ', error.message)
}
}, [accountId])
// -----------------------------------
// Create initial Web3Modal instance
// -----------------------------------
useEffect(() => {
if (web3Modal) {
setWeb3Loading(false)
return
}
async function init() {
// note: needs artificial await here so the log message is reached and output
const web3ModalInstance = await new Web3Modal(web3ModalOpts)
setWeb3Modal(web3ModalInstance)
LoggerInstance.log(
'[web3] Web3Modal instance created.',
web3ModalInstance
)
}
init()
}, [connect, web3Modal])
// -----------------------------------
// Reconnect automatically for returning users
// -----------------------------------
useEffect(() => {
if (!web3Modal?.cachedProvider) return
async function connectCached() {
LoggerInstance.log(
'[web3] Connecting to cached provider: ',
web3Modal.cachedProvider
)
await connect()
}
connectCached()
}, [connect, web3Modal])
// -----------------------------------
// Get and set approved base tokens list
// -----------------------------------
useEffect(() => {
if (web3Loading) return
getApprovedBaseTokens(chainId || 1)
}, [chainId, getApprovedBaseTokens, web3Loading])
// -----------------------------------
// Get and set user balance
// -----------------------------------
useEffect(() => {
getUserBalance()
// init periodic refresh of wallet balance
const balanceInterval = setInterval(() => getUserBalance(), refreshInterval)
return () => {
clearInterval(balanceInterval)
}
}, [getUserBalance])
// -----------------------------------
// Get and set user ENS info
// -----------------------------------
useEffect(() => {
getUserEns()
}, [getUserEns])
// -----------------------------------
// Get and set network metadata
// -----------------------------------
useEffect(() => {
if (!networkId) return
const networkData = getNetworkDataById(networksList, networkId)
setNetworkData(networkData)
LoggerInstance.log(
networkData
? `[web3] Network metadata found.`
: `[web3] No network metadata found.`,
networkData
)
// Construct network display name
const networkDisplayName = getNetworkDisplayName(networkData)
setNetworkDisplayName(networkDisplayName)
setIsTestnet(getNetworkType(networkData) !== NetworkType.Mainnet)
LoggerInstance.log(
`[web3] Network display name set to: ${networkDisplayName}`
)
}, [networkId, networksList])
// -----------------------------------
// Get and set latest head block
// -----------------------------------
useEffect(() => {
if (!web3) return
async function getBlock() {
const block = await web3.eth.getBlockNumber()
setBlock(block)
LoggerInstance.log('[web3] Head block: ', block)
}
getBlock()
}, [web3, networkId])
// -----------------------------------
// Get and set web3 provider info
// -----------------------------------
// Workaround cause getInjectedProviderName() always returns `MetaMask`
// https://github.com/oceanprotocol/market/issues/332
useEffect(() => {
if (!web3Provider) return
const providerInfo = getProviderInfo(web3Provider)
setWeb3ProviderInfo(providerInfo)
}, [web3Provider])
// -----------------------------------
// Logout helper
// -----------------------------------
async function logout() {
/* eslint-disable @typescript-eslint/no-explicit-any */
if ((web3?.currentProvider as any)?.close) {
await (web3.currentProvider as any).close()
}
/* eslint-enable @typescript-eslint/no-explicit-any */
await web3Modal.clearCachedProvider()
}
// -----------------------------------
// Get valid Networks and set isSupportedOceanNetwork
// -----------------------------------
useEffect(() => {
if (appConfig.chainIdsSupported.includes(networkId)) {
setIsSupportedOceanNetwork(true)
} else {
setIsSupportedOceanNetwork(false)
}
}, [networkId, appConfig.chainIdsSupported])
// -----------------------------------
// Handle change events
// -----------------------------------
async function handleChainChanged(chainId: string) {
LoggerInstance.log('[web3] Chain changed', chainId)
const networkId = await web3.eth.net.getId()
setChainId(Number(chainId))
setNetworkId(Number(networkId))
}
async function handleNetworkChanged(networkId: string) {
LoggerInstance.log('[web3] Network changed', networkId)
const chainId = await web3.eth.getChainId()
setNetworkId(Number(networkId))
setChainId(Number(chainId))
}
async function handleAccountsChanged(accounts: string[]) {
LoggerInstance.log('[web3] Account changed', accounts[0])
setAccountId(accounts[0])
}
useEffect(() => {
if (!web3Provider || !web3) return
web3Provider.on('chainChanged', handleChainChanged)
web3Provider.on('networkChanged', handleNetworkChanged)
web3Provider.on('accountsChanged', handleAccountsChanged)
return () => {
web3Provider.removeListener('chainChanged', handleChainChanged)
web3Provider.removeListener('networkChanged', handleNetworkChanged)
web3Provider.removeListener('accountsChanged', handleAccountsChanged)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [web3Provider, web3])
return (
<Web3Context.Provider
value={{
web3,
web3Provider,
web3Modal,
web3ProviderInfo,
accountId,
accountEns,
accountEnsAvatar,
balance,
networkId,
chainId,
networkDisplayName,
networkData,
block,
isTestnet,
web3Loading,
isSupportedOceanNetwork,
approvedBaseTokens,
connect,
logout
}}
>
{children}
</Web3Context.Provider>
)
}
// Helper hook to access the provider values
const useWeb3 = (): Web3ProviderValue => useContext(Web3Context)
export { Web3Provider, useWeb3, Web3Context }
export default Web3Provider

73
src/@hooks/useBalance.tsx Normal file
View File

@ -0,0 +1,73 @@
import { useState, useEffect, useCallback } from 'react'
import { LoggerInstance } from '@oceanprotocol/lib'
import { useMarketMetadata } from '../@context/MarketMetadata'
import {
useNetwork,
useAccount,
useProvider,
useBalance as useBalanceWagmi
} from 'wagmi'
import { getTokenBalance } from '@utils/wallet'
interface BalanceProviderValue {
balance: UserBalance
}
function useBalance(): BalanceProviderValue {
const { address } = useAccount()
const { data: balanceNativeToken } = useBalanceWagmi({ address })
const web3provider = useProvider()
const { approvedBaseTokens } = useMarketMetadata()
const { chain } = useNetwork()
const [balance, setBalance] = useState<UserBalance>({
eth: '0'
})
// -----------------------------------
// Helper: Get user balance
// -----------------------------------
const getUserBalance = useCallback(async () => {
if (
!balanceNativeToken?.formatted ||
!address ||
!chain?.id ||
!web3provider
)
return
try {
const userBalance = balanceNativeToken?.formatted
const key = balanceNativeToken?.symbol.toLowerCase()
const newBalance: UserBalance = { [key]: userBalance }
if (approvedBaseTokens?.length > 0) {
await Promise.all(
approvedBaseTokens.map(async (token) => {
const { address: tokenAddress, decimals, symbol } = token
const tokenBalance = await getTokenBalance(
address,
decimals,
tokenAddress,
web3provider
)
newBalance[symbol.toLocaleLowerCase()] = tokenBalance
})
)
}
setBalance(newBalance)
LoggerInstance.log('[useBalance] Balance: ', newBalance)
} catch (error) {
LoggerInstance.error('[useBalance] Error: ', error.message)
}
}, [address, approvedBaseTokens, chain?.id, web3provider, balanceNativeToken])
useEffect(() => {
getUserBalance()
}, [getUserBalance])
return { balance }
}
export default useBalance

View File

@ -1,14 +1,10 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { useWeb3 } from '@context/Web3'
import { Config, LoggerInstance } from '@oceanprotocol/lib' import { Config, LoggerInstance } from '@oceanprotocol/lib'
import Web3 from 'web3'
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig } from '@utils/ocean'
import { useBlockNumber } from 'wagmi'
const blockDifferenceThreshold = 30 const blockDifferenceThreshold = 30
const ethGraphUrl = `https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks`
const ethGraphQueryBody =
'{"query":" query Blocks{ blocks(first: 1, skip: 0, orderBy: number, orderDirection: desc, where: {number_gt: 9300000}) { id number timestamp author difficulty gasUsed gasLimit } }","variables":{},"operationName":"Blocks"}'
const graphQueryBody = const graphQueryBody =
'{"query": "query Meta { _meta { block { hash number } deployment hasIndexingErrors } }", "variables": {},"operationName":"Meta"}' '{"query": "query Meta { _meta { block { hash number } deployment hasIndexingErrors } }", "variables": {},"operationName":"Meta"}'
@ -30,21 +26,6 @@ async function fetchGraph(
} }
} }
async function getBlockHead(config: Config) {
if (!config) return
// for ETH main, get block from graph fetch
if (config.network === 'mainnet') {
const response: any = await fetchGraph(ethGraphUrl, ethGraphQueryBody)
return Number(response?.data?.blocks[0]?.number)
}
// for everything else, create new web3 instance with infura
// TODO: this fails randomly , WHY!?!?!?!?!
const web3Instance = new Web3(config.nodeUri)
const blockHead = await web3Instance.eth.getBlockNumber()
return blockHead
}
async function getBlockSubgraph(subgraphUri: string) { async function getBlockSubgraph(subgraphUri: string) {
const response: any = await fetchGraph( const response: any = await fetchGraph(
`${subgraphUri}/subgraphs/name/oceanprotocol/ocean-subgraph`, `${subgraphUri}/subgraphs/name/oceanprotocol/ocean-subgraph`,
@ -55,11 +36,10 @@ async function getBlockSubgraph(subgraphUri: string) {
} }
export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus { export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus {
const { block, web3Loading } = useWeb3() const { data: blockHead, isLoading } = useBlockNumber()
const [blockGraph, setBlockGraph] = useState<number>() const [blockGraph, setBlockGraph] = useState<number>()
const [blockHead, setBlockHead] = useState<number>()
const [isGraphSynced, setIsGraphSynced] = useState(true) const [isGraphSynced, setIsGraphSynced] = useState(true)
const [subgraphLoading, setSubgraphLoading] = useState(false) const [isSubgraphLoading, setIsSubgraphLoading] = useState(false)
const [oceanConfig, setOceanConfig] = useState<Config>() const [oceanConfig, setOceanConfig] = useState<Config>()
// Grab ocean config based on passed networkId // Grab ocean config based on passed networkId
@ -70,27 +50,21 @@ export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus {
setOceanConfig(oceanConfig) setOceanConfig(oceanConfig)
}, [networkId]) }, [networkId])
// Get and set head block // Log head block
useEffect(() => { useEffect(() => {
if (!oceanConfig?.nodeUri || web3Loading) return if (!blockHead) return
LoggerInstance.log('[GraphStatus] Head block: ', blockHead)
async function initBlockHead() { }, [blockHead])
const blockHead = block || (await getBlockHead(oceanConfig))
setBlockHead(blockHead)
LoggerInstance.log('[GraphStatus] Head block: ', blockHead)
}
initBlockHead()
}, [web3Loading, block, oceanConfig])
// Get and set subgraph block // Get and set subgraph block
useEffect(() => { useEffect(() => {
if (!oceanConfig?.subgraphUri) return if (!oceanConfig?.subgraphUri) return
async function initBlockSubgraph() { async function initBlockSubgraph() {
setSubgraphLoading(true) setIsSubgraphLoading(true)
const blockGraph = await getBlockSubgraph(oceanConfig.subgraphUri) const blockGraph = await getBlockSubgraph(oceanConfig.subgraphUri)
setBlockGraph(blockGraph) setBlockGraph(blockGraph)
setSubgraphLoading(false) setIsSubgraphLoading(false)
LoggerInstance.log( LoggerInstance.log(
'[GraphStatus] Latest block from subgraph: ', '[GraphStatus] Latest block from subgraph: ',
blockGraph blockGraph
@ -101,7 +75,7 @@ export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus {
// Set sync status // Set sync status
useEffect(() => { useEffect(() => {
if ((!blockGraph && !blockHead) || web3Loading || subgraphLoading) return if ((!blockGraph && !blockHead) || isLoading || isSubgraphLoading) return
const difference = blockHead - blockGraph const difference = blockHead - blockGraph
@ -110,7 +84,7 @@ export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus {
return return
} }
setIsGraphSynced(true) setIsGraphSynced(true)
}, [blockGraph, blockHead, web3Loading, subgraphLoading]) }, [blockGraph, blockHead, isLoading, isSubgraphLoading])
return { blockHead, blockGraph, isGraphSynced } return { blockHead, blockGraph, isGraphSynced }
} }

View File

@ -1,9 +1,57 @@
import { UseNetworkMetadata } from './types' import { UseNetworkMetadata } from './types'
import networkdata from '../../../content/networks-metadata.json' import networkdata from '../../../content/networks-metadata.json'
import { useEffect, useState } from 'react'
import {
getNetworkDataById,
getNetworkDisplayName,
getNetworkType,
NetworkType
} from './utils'
import { useMarketMetadata } from '@context/MarketMetadata'
import { useNetwork } from 'wagmi'
export default function useNetworkMetadata(): UseNetworkMetadata { export default function useNetworkMetadata(): UseNetworkMetadata {
const { appConfig } = useMarketMetadata()
const { chain } = useNetwork()
const [networkDisplayName, setNetworkDisplayName] = useState<string>()
const [networkData, setNetworkData] = useState<EthereumListsChain>()
const [isTestnet, setIsTestnet] = useState<boolean>()
const [isSupportedOceanNetwork, setIsSupportedOceanNetwork] = useState(true)
const networksList: EthereumListsChain[] = networkdata const networksList: EthereumListsChain[] = networkdata
return { networksList }
// -----------------------------------
// Get and set network metadata
// -----------------------------------
useEffect(() => {
if (!chain?.id) return
const networkData = getNetworkDataById(networksList, chain.id)
setNetworkData(networkData)
// Construct network display name
const networkDisplayName = getNetworkDisplayName(networkData)
setNetworkDisplayName(networkDisplayName)
// Check if network is supported by Ocean Protocol
if (appConfig.chainIdsSupported.includes(chain.id)) {
setIsSupportedOceanNetwork(true)
} else {
setIsSupportedOceanNetwork(false)
}
// Check if network is testnet
setIsTestnet(getNetworkType(networkData) !== NetworkType.Mainnet)
}, [chain?.id, networksList, appConfig.chainIdsSupported])
return {
networksList,
networkDisplayName,
networkData,
isTestnet,
isSupportedOceanNetwork
}
} }
export * from './utils' export * from './utils'

View File

@ -1,3 +1,7 @@
export interface UseNetworkMetadata { export interface UseNetworkMetadata {
networkDisplayName: string
networkData: EthereumListsChain
isTestnet: boolean
isSupportedOceanNetwork: boolean
networksList: EthereumListsChain[] networksList: EthereumListsChain[]
} }

View File

@ -1,18 +1,20 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { NftFactory } from '@oceanprotocol/lib' import { NftFactory } from '@oceanprotocol/lib'
import { useWeb3 } from '@context/Web3'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig } from '@utils/ocean'
import { useNetwork, useSigner } from 'wagmi'
function useNftFactory(): NftFactory { function useNftFactory(): NftFactory {
const { web3, chainId } = useWeb3() const { chain } = useNetwork()
const { data: signer } = useSigner()
const [nftFactory, setNftFactory] = useState<NftFactory>() const [nftFactory, setNftFactory] = useState<NftFactory>()
useEffect(() => { useEffect(() => {
if (!web3 || !chainId) return if (!signer || !chain?.id) return
const config = getOceanConfig(chainId)
const factory = new NftFactory(config?.nftFactoryAddress, web3) const config = getOceanConfig(chain.id)
const factory = new NftFactory(config?.nftFactoryAddress, signer)
setNftFactory(factory) setNftFactory(factory)
}, [web3, chainId]) }, [signer, chain?.id])
return nftFactory return nftFactory
} }

View File

@ -9,12 +9,13 @@ import {
ProviderFees, ProviderFees,
ProviderInstance ProviderInstance
} from '@oceanprotocol/lib' } from '@oceanprotocol/lib'
import { getFixedBuyPrice } from './fixedRateExchange' import { getFixedBuyPrice } from './ocean/fixedRateExchange'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import { import {
consumeMarketOrderFee, consumeMarketOrderFee,
publisherMarketOrderFee publisherMarketOrderFee
} from '../../app.config' } from '../../app.config'
import { Signer } from 'ethers'
const tokenPriceQuery = gql` const tokenPriceQuery = gql`
query TokenPriceQuery($datatokenId: ID!, $account: String) { query TokenPriceQuery($datatokenId: ID!, $account: String) {
@ -158,7 +159,8 @@ function getAccessDetailsFromTokenPrice(
*/ */
export async function getOrderPriceAndFees( export async function getOrderPriceAndFees(
asset: AssetExtended, asset: AssetExtended,
accountId?: string, accountId: string,
signer: Signer,
providerFees?: ProviderFees providerFees?: ProviderFees
): Promise<OrderPriceAndFees> { ): Promise<OrderPriceAndFees> {
const orderPriceAndFee = { const orderPriceAndFee = {
@ -187,7 +189,11 @@ export async function getOrderPriceAndFees(
// fetch price and swap fees // fetch price and swap fees
if (asset?.accessDetails?.type === 'fixed') { if (asset?.accessDetails?.type === 'fixed') {
const fixed = await getFixedBuyPrice(asset?.accessDetails, asset?.chainId) const fixed = await getFixedBuyPrice(
asset?.accessDetails,
asset?.chainId,
signer
)
orderPriceAndFee.price = fixed.baseTokenAmount orderPriceAndFee.price = fixed.baseTokenAmount
orderPriceAndFee.opcFee = fixed.oceanFeeAmount orderPriceAndFee.opcFee = fixed.oceanFeeAmount
orderPriceAndFee.publisherMarketFixedSwapFee = fixed.marketFeeAmount orderPriceAndFee.publisherMarketFixedSwapFee = fixed.marketFeeAmount

View File

@ -143,12 +143,8 @@ export async function getComputeEnviroment(
const computeEnvs = await ProviderInstance.getComputeEnvironments( const computeEnvs = await ProviderInstance.getComputeEnvironments(
asset.services[0].serviceEndpoint asset.services[0].serviceEndpoint
) )
const computeEnv = Array.isArray(computeEnvs) if (!computeEnvs[asset.chainId][0]) return null
? computeEnvs[0] return computeEnvs[asset.chainId][0]
: computeEnvs[asset.chainId][0]
if (!computeEnv) return null
return computeEnv
} catch (e) { } catch (e) {
LoggerInstance.error('[compute] Fetch compute enviroment: ', e.message) LoggerInstance.error('[compute] Fetch compute enviroment: ', e.message)
} }

View File

@ -1,14 +1,13 @@
import { LoggerInstance, Datatoken } from '@oceanprotocol/lib' import { LoggerInstance, Datatoken } from '@oceanprotocol/lib'
import Web3 from 'web3' import { Signer, ethers } from 'ethers'
import { TransactionReceipt } from 'web3-core'
export async function setMinterToPublisher( export async function setMinterToPublisher(
web3: Web3, signer: Signer,
datatokenAddress: string, datatokenAddress: string,
accountId: string, accountId: string,
setError: (msg: string) => void setError: (msg: string) => void
): Promise<TransactionReceipt> { ): Promise<ethers.providers.TransactionResponse> {
const datatokenInstance = new Datatoken(web3) const datatokenInstance = new Datatoken(signer)
const response = await datatokenInstance.removeMinter( const response = await datatokenInstance.removeMinter(
datatokenAddress, datatokenAddress,
@ -24,12 +23,12 @@ export async function setMinterToPublisher(
} }
export async function setMinterToDispenser( export async function setMinterToDispenser(
web3: Web3, signer: Signer,
datatokenAddress: string, datatokenAddress: string,
accountId: string, accountId: string,
setError: (msg: string) => void setError: (msg: string) => void
): Promise<TransactionReceipt> { ): Promise<ethers.providers.TransactionResponse> {
const datatokenInstance = new Datatoken(web3) const datatokenInstance = new Datatoken(signer)
const response = await datatokenInstance.addMinter( const response = await datatokenInstance.addMinter(
datatokenAddress, datatokenAddress,

View File

@ -9,8 +9,7 @@ import {
NftCreateData NftCreateData
} from '@oceanprotocol/lib' } from '@oceanprotocol/lib'
import { SvgWaves } from './SvgWaves' import { SvgWaves } from './SvgWaves'
import Web3 from 'web3' import { Signer, ethers } from 'ethers'
import { TransactionReceipt } from 'web3-core'
// https://docs.opensea.io/docs/metadata-standards // https://docs.opensea.io/docs/metadata-standards
export interface NftMetadata { export interface NftMetadata {
@ -67,7 +66,7 @@ export function generateNftCreateData(
nftMetadata: NftMetadata, nftMetadata: NftMetadata,
accountId: string, accountId: string,
transferable = true transferable = true
): any { ): NftCreateData {
const nftCreateData: NftCreateData = { const nftCreateData: NftCreateData = {
name: nftMetadata.name, name: nftMetadata.name,
symbol: nftMetadata.symbol, symbol: nftMetadata.symbol,
@ -99,9 +98,9 @@ export function decodeTokenURI(tokenURI: string): NftMetadata {
export async function setNftMetadata( export async function setNftMetadata(
asset: Asset | DDO, asset: Asset | DDO,
accountId: string, accountId: string,
web3: Web3, signer: Signer,
signal: AbortSignal signal: AbortSignal
): Promise<TransactionReceipt> { ): Promise<ethers.providers.TransactionResponse> {
const encryptedDdo = await ProviderInstance.encrypt( const encryptedDdo = await ProviderInstance.encrypt(
asset, asset,
asset.chainId, asset.chainId,
@ -111,7 +110,7 @@ export async function setNftMetadata(
LoggerInstance.log('[setNftMetadata] Got encrypted DDO', encryptedDdo) LoggerInstance.log('[setNftMetadata] Got encrypted DDO', encryptedDdo)
const metadataHash = getHash(JSON.stringify(asset)) const metadataHash = getHash(JSON.stringify(asset))
const nft = new Nft(web3) const nft = new Nft(signer)
// theoretically used by aquarius or provider, not implemented yet, will remain hardcoded // theoretically used by aquarius or provider, not implemented yet, will remain hardcoded
const flags = '0x2' const flags = '0x2'
@ -133,10 +132,10 @@ export async function setNftMetadata(
export async function setNFTMetadataAndTokenURI( export async function setNFTMetadataAndTokenURI(
asset: Asset | DDO, asset: Asset | DDO,
accountId: string, accountId: string,
web3: Web3, signer: Signer,
nftMetadata: NftMetadata, nftMetadata: NftMetadata,
signal: AbortSignal signal: AbortSignal
): Promise<TransactionReceipt> { ): Promise<ethers.providers.TransactionResponse> {
const encryptedDdo = await ProviderInstance.encrypt( const encryptedDdo = await ProviderInstance.encrypt(
asset, asset,
asset.chainId, asset.chainId,
@ -159,7 +158,7 @@ export async function setNFTMetadataAndTokenURI(
external_url: externalUrl external_url: externalUrl
}) })
).toString('base64') ).toString('base64')
const nft = new Nft(web3) const nft = new Nft(signer)
// theoretically used by aquarius or provider, not implemented yet, will remain hardcoded // theoretically used by aquarius or provider, not implemented yet, will remain hardcoded
const flags = '0x02' const flags = '0x02'

View File

@ -1,35 +1,30 @@
import { FixedRateExchange, PriceAndFees } from '@oceanprotocol/lib' import {
import { consumeMarketFixedSwapFee } from '../../app.config' amountToUnits,
import Web3 from 'web3' FixedRateExchange,
import { getOceanConfig } from './ocean' PriceAndFees,
import { getDummyWeb3 } from './web3' unitsToAmount
} from '@oceanprotocol/lib'
import { ethers, Signer } from 'ethers'
import abiFre from '@oceanprotocol/contracts/artifacts/contracts/pools/fixedRate/FixedRateExchange.sol/FixedRateExchange.json'
import { getOceanConfig } from '.'
import { consumeMarketFixedSwapFee } from '../../../app.config'
/** /**
* This is used to calculate the price to buy one datatoken from a fixed rate exchange. You need to pass either a web3 object or a chainId. If you pass a chainId a dummy web3 object will be created * This is used to calculate the price to buy one datatoken from a fixed rate exchange. You need to pass either a web3 object or a chainId. If you pass a chainId a dummy web3 object will be created
* @param {AccessDetails} accessDetails
* @param {number} chainId
* @param {Web3?} web3
* @return {Promise<PriceAndFees>}
*/ */
export async function getFixedBuyPrice( export async function getFixedBuyPrice(
accessDetails: AccessDetails, accessDetails: AccessDetails,
chainId?: number, chainId: number,
web3?: Web3 provider: Signer
): Promise<PriceAndFees> { ): Promise<PriceAndFees> {
if (!web3 && !chainId)
throw new Error("web3 and chainId can't be undefined at the same time!")
if (!web3) {
web3 = await getDummyWeb3(chainId)
}
const config = getOceanConfig(chainId) const config = getOceanConfig(chainId)
const fixed = new FixedRateExchange(config.fixedRateExchangeAddress, web3) const fixed = new FixedRateExchange(config.fixedRateExchangeAddress, provider)
const estimatedPrice = await fixed.calcBaseInGivenDatatokensOut( const estimatedPrice = await fixed.calcBaseInGivenDatatokensOut(
accessDetails.addressOrId, accessDetails.addressOrId,
'1', '1',
consumeMarketFixedSwapFee consumeMarketFixedSwapFee
) )
return estimatedPrice return estimatedPrice
} }

View File

@ -1,5 +1,7 @@
import { ConfigHelper, Config } from '@oceanprotocol/lib' import { ConfigHelper, Config } from '@oceanprotocol/lib'
// import contractAddresses from '@oceanprotocol/contracts/artifacts/address.json' import { ethers } from 'ethers'
import abiDatatoken from '@oceanprotocol/contracts/artifacts/contracts/templates/ERC20TemplateEnterprise.sol/ERC20TemplateEnterprise.json'
export function getOceanConfig(network: string | number): Config { export function getOceanConfig(network: string | number): Config {
const config = new ConfigHelper().getConfig( const config = new ConfigHelper().getConfig(
@ -28,3 +30,18 @@ export function getDevelopmentConfig(): Config {
subgraphUri: 'https://v4.subgraph.goerli.oceanprotocol.com' subgraphUri: 'https://v4.subgraph.goerli.oceanprotocol.com'
} as Config } as Config
} }
/**
* getPaymentCollector - returns the current paymentCollector
* @param dtAddress datatoken address
* @param provider the ethers.js web3 provider
* @return {Promise<string>}
*/
export async function getPaymentCollector(
dtAddress: string,
provider: ethers.providers.Provider
): Promise<string> {
const dtContract = new ethers.Contract(dtAddress, abiDatatoken.abi, provider)
const paymentCollector = await dtContract.getPaymentCollector()
return paymentCollector
}

View File

@ -13,9 +13,8 @@ import {
ProviderInstance, ProviderInstance,
ProviderInitialize ProviderInitialize
} from '@oceanprotocol/lib' } from '@oceanprotocol/lib'
import Web3 from 'web3' import { Signer, ethers } from 'ethers'
import { getOceanConfig } from './ocean' import { getOceanConfig } from './ocean'
import { TransactionReceipt } from 'web3-eth'
import { import {
marketFeeAddress, marketFeeAddress,
consumeMarketOrderFee, consumeMarketOrderFee,
@ -44,23 +43,24 @@ async function initializeProvider(
} }
/** /**
* @param web3 * @param signer
* @param asset * @param asset
* @param orderPriceAndFees * @param orderPriceAndFees
* @param accountId * @param accountId
* @param providerFees * @param providerFees
* @param computeConsumerAddress * @param computeConsumerAddress
* @returns {TransactionReceipt} receipt of the order * @returns {ethers.providers.TransactionResponse | BigNumber} receipt of the order
*/ */
export async function order( export async function order(
web3: Web3, signer: Signer,
asset: AssetExtended, asset: AssetExtended,
orderPriceAndFees: OrderPriceAndFees, orderPriceAndFees: OrderPriceAndFees,
accountId: string, accountId: string,
hasDatatoken: boolean,
providerFees?: ProviderFees, providerFees?: ProviderFees,
computeConsumerAddress?: string computeConsumerAddress?: string
): Promise<TransactionReceipt> { ): Promise<ethers.providers.TransactionResponse> {
const datatoken = new Datatoken(web3) const datatoken = new Datatoken(signer)
const config = getOceanConfig(asset.chainId) const config = getOceanConfig(asset.chainId)
const initializeData = await initializeProvider( const initializeData = await initializeProvider(
@ -97,36 +97,38 @@ export async function order(
} as FreOrderParams } as FreOrderParams
if (asset.accessDetails.templateId === 1) { if (asset.accessDetails.templateId === 1) {
// buy datatoken if (!hasDatatoken) {
const txApprove = await approve( // buy datatoken
web3, const txApprove = await approve(
config, signer,
accountId, config,
asset.accessDetails.baseToken.address, accountId,
config.fixedRateExchangeAddress, asset.accessDetails.baseToken.address,
await amountToUnits( config.fixedRateExchangeAddress,
web3, await amountToUnits(
asset?.accessDetails?.baseToken?.address, signer,
orderPriceAndFees.price asset?.accessDetails?.baseToken?.address,
), orderPriceAndFees.price
false ),
) false
if (!txApprove) { )
return if (!txApprove) {
return
}
const fre = new FixedRateExchange(
config.fixedRateExchangeAddress,
signer
)
const freTx = await fre.buyDatatokens(
asset.accessDetails?.addressOrId,
'1',
orderPriceAndFees.price,
marketFeeAddress,
consumeMarketFixedSwapFee
)
} }
const fre = new FixedRateExchange(config.fixedRateExchangeAddress, web3)
const freTx = await fre.buyDatatokens(
accountId,
asset.accessDetails?.addressOrId,
'1',
orderPriceAndFees.price,
marketFeeAddress,
consumeMarketFixedSwapFee
)
return await datatoken.startOrder( return await datatoken.startOrder(
asset.accessDetails.datatoken.address, asset.accessDetails.datatoken.address,
accountId,
orderParams.consumer, orderParams.consumer,
orderParams.serviceIndex, orderParams.serviceIndex,
orderParams._providerFee, orderParams._providerFee,
@ -135,13 +137,13 @@ export async function order(
} }
if (asset.accessDetails.templateId === 2) { if (asset.accessDetails.templateId === 2) {
const txApprove = await approve( const txApprove = await approve(
web3, signer,
config, config,
accountId, accountId,
asset.accessDetails.baseToken.address, asset.accessDetails.baseToken.address,
asset.accessDetails.datatoken.address, asset.accessDetails.datatoken.address,
await amountToUnits( await amountToUnits(
web3, signer,
asset?.accessDetails?.baseToken?.address, asset?.accessDetails?.baseToken?.address,
orderPriceAndFees.price orderPriceAndFees.price
), ),
@ -152,7 +154,6 @@ export async function order(
} }
return await datatoken.buyFromFreAndOrder( return await datatoken.buyFromFreAndOrder(
asset.accessDetails.datatoken.address, asset.accessDetails.datatoken.address,
accountId,
orderParams, orderParams,
freParams freParams
) )
@ -161,16 +162,14 @@ export async function order(
} }
case 'free': { case 'free': {
if (asset.accessDetails.templateId === 1) { if (asset.accessDetails.templateId === 1) {
const dispenser = new Dispenser(config.dispenserAddress, web3) const dispenser = new Dispenser(config.dispenserAddress, signer)
const dispenserTx = await dispenser.dispense( const dispenserTx = await dispenser.dispense(
asset.accessDetails?.datatoken.address, asset.accessDetails?.datatoken.address,
accountId,
'1', '1',
accountId accountId
) )
return await datatoken.startOrder( return await datatoken.startOrder(
asset.accessDetails.datatoken.address, asset.accessDetails.datatoken.address,
accountId,
orderParams.consumer, orderParams.consumer,
orderParams.serviceIndex, orderParams.serviceIndex,
orderParams._providerFee, orderParams._providerFee,
@ -180,7 +179,6 @@ export async function order(
if (asset.accessDetails.templateId === 2) { if (asset.accessDetails.templateId === 2) {
return await datatoken.buyFromDispenserAndOrder( return await datatoken.buyFromDispenserAndOrder(
asset.services[0].datatokenAddress, asset.services[0].datatokenAddress,
accountId,
orderParams, orderParams,
config.dispenserAddress config.dispenserAddress
) )
@ -191,7 +189,7 @@ export async function order(
/** /**
* called when having a valid order, but with expired provider access, requires approval of the provider fee * called when having a valid order, but with expired provider access, requires approval of the provider fee
* @param web3 * @param signer
* @param asset * @param asset
* @param accountId * @param accountId
* @param validOrderTx * @param validOrderTx
@ -199,13 +197,13 @@ export async function order(
* @returns {TransactionReceipt} receipt of the order * @returns {TransactionReceipt} receipt of the order
*/ */
export async function reuseOrder( export async function reuseOrder(
web3: Web3, signer: Signer,
asset: AssetExtended, asset: AssetExtended,
accountId: string, accountId: string,
validOrderTx: string, validOrderTx: string,
providerFees?: ProviderFees providerFees?: ProviderFees
): Promise<TransactionReceipt> { ): Promise<ethers.providers.TransactionResponse> {
const datatoken = new Datatoken(web3) const datatoken = new Datatoken(signer)
const initializeData = await initializeProvider( const initializeData = await initializeProvider(
asset, asset,
accountId, accountId,
@ -214,7 +212,6 @@ export async function reuseOrder(
const tx = await datatoken.reuseOrder( const tx = await datatoken.reuseOrder(
asset.accessDetails.datatoken.address, asset.accessDetails.datatoken.address,
accountId,
validOrderTx, validOrderTx,
providerFees || initializeData.providerFee providerFees || initializeData.providerFee
) )
@ -225,16 +222,16 @@ export async function reuseOrder(
async function approveProviderFee( async function approveProviderFee(
asset: AssetExtended, asset: AssetExtended,
accountId: string, accountId: string,
web3: Web3, signer: Signer,
providerFeeAmount: string providerFeeAmount: string
): Promise<TransactionReceipt> { ): Promise<ethers.providers.TransactionResponse> {
const config = getOceanConfig(asset.chainId) const config = getOceanConfig(asset.chainId)
const baseToken = const baseToken =
asset?.accessDetails?.type === 'free' asset?.accessDetails?.type === 'free'
? getOceanConfig(asset.chainId).oceanTokenAddress ? getOceanConfig(asset.chainId).oceanTokenAddress
: asset?.accessDetails?.baseToken?.address : asset?.accessDetails?.baseToken?.address
const txApproveWei = await approveWei( const txApproveWei = await approveWei(
web3, signer,
config, config,
accountId, accountId,
baseToken, baseToken,
@ -249,7 +246,7 @@ async function approveProviderFee(
* - have validOrder and no providerFees -> then order is valid, providerFees are valid, it returns the valid order value * - have validOrder and no providerFees -> then order is valid, providerFees are valid, it returns the valid order value
* - have validOrder and providerFees -> then order is valid but providerFees are not valid, we need to call reuseOrder and pay only providerFees * - have validOrder and providerFees -> then order is valid but providerFees are not valid, we need to call reuseOrder and pay only providerFees
* - no validOrder -> we need to call order, to pay 1 DT & providerFees * - no validOrder -> we need to call order, to pay 1 DT & providerFees
* @param web3 * @param signer
* @param asset * @param asset
* @param orderPriceAndFees * @param orderPriceAndFees
* @param accountId * @param accountId
@ -259,11 +256,12 @@ async function approveProviderFee(
* @returns {Promise<string>} tx id * @returns {Promise<string>} tx id
*/ */
export async function handleComputeOrder( export async function handleComputeOrder(
web3: Web3, signer: Signer,
asset: AssetExtended, asset: AssetExtended,
orderPriceAndFees: OrderPriceAndFees, orderPriceAndFees: OrderPriceAndFees,
accountId: string, accountId: string,
initializeData: ProviderComputeInitialize, initializeData: ProviderComputeInitialize,
hasDatatoken,
computeConsumerAddress?: string computeConsumerAddress?: string
): Promise<string> { ): Promise<string> {
LoggerInstance.log( LoggerInstance.log(
@ -288,7 +286,7 @@ export async function handleComputeOrder(
const txApproveProvider = await approveProviderFee( const txApproveProvider = await approveProviderFee(
asset, asset,
accountId, accountId,
web3, signer,
initializeData.providerFee.providerFeeAmount initializeData.providerFee.providerFeeAmount
) )
@ -301,30 +299,33 @@ export async function handleComputeOrder(
if (initializeData?.validOrder) { if (initializeData?.validOrder) {
LoggerInstance.log('[compute] Calling reuseOrder ...', initializeData) LoggerInstance.log('[compute] Calling reuseOrder ...', initializeData)
const txReuseOrder = await reuseOrder( const txReuseOrder = await reuseOrder(
web3, signer,
asset, asset,
accountId, accountId,
initializeData.validOrder, initializeData.validOrder,
initializeData.providerFee initializeData.providerFee
) )
if (!txReuseOrder) throw new Error('Failed to reuse order!') if (!txReuseOrder) throw new Error('Failed to reuse order!')
LoggerInstance.log('[compute] Reused order:', txReuseOrder) const tx = await txReuseOrder.wait()
return txReuseOrder?.transactionHash LoggerInstance.log('[compute] Reused order:', tx)
return tx?.transactionHash
} }
LoggerInstance.log('[compute] Calling order ...', initializeData) LoggerInstance.log('[compute] Calling order ...', initializeData)
const txStartOrder = await order( const txStartOrder = await order(
web3, signer,
asset, asset,
orderPriceAndFees, orderPriceAndFees,
accountId, accountId,
hasDatatoken,
initializeData.providerFee, initializeData.providerFee,
computeConsumerAddress computeConsumerAddress
) )
LoggerInstance.log('[compute] Order succeeded', txStartOrder) const tx = await txStartOrder.wait()
return txStartOrder?.transactionHash LoggerInstance.log('[compute] Order succeeded', tx)
return tx?.transactionHash
} catch (error) { } catch (error) {
toast.error(error.message) toast.error(error.message)
LoggerInstance.error(`[compute] ${error.message}`) LoggerInstance.error(`[compute] ${error.message}`)

View File

@ -11,11 +11,11 @@ import {
LoggerInstance, LoggerInstance,
ProviderComputeInitializeResults, ProviderComputeInitializeResults,
ProviderInstance, ProviderInstance,
UrlFile UrlFile,
AbiItem
} from '@oceanprotocol/lib' } from '@oceanprotocol/lib'
import { QueryHeader } from '@shared/FormInput/InputElement/Headers' import { QueryHeader } from '@shared/FormInput/InputElement/Headers'
import Web3 from 'web3' import { Signer } from 'ethers'
import { AbiItem } from 'web3-utils/types'
import { getValidUntilTime } from './compute' import { getValidUntilTime } from './compute'
export async function initializeProviderForCompute( export async function initializeProviderForCompute(
@ -173,19 +173,18 @@ export async function getFileInfo(
} }
export async function downloadFile( export async function downloadFile(
web3: Web3, signer: Signer,
asset: AssetExtended, asset: AssetExtended,
accountId: string, accountId: string,
validOrderTx?: string validOrderTx?: string
) { ) {
const downloadUrl = await ProviderInstance.getDownloadUrl( const downloadUrl = await ProviderInstance.getDownloadUrl(
asset.id, asset.id,
accountId,
asset.services[0].id, asset.services[0].id,
0, 0,
validOrderTx || asset.accessDetails.validOrderTx, validOrderTx || asset.accessDetails.validOrderTx,
asset.services[0].serviceEndpoint, asset.services[0].serviceEndpoint,
web3 signer
) )
await downloadFileBrowser(downloadUrl) await downloadFileBrowser(downloadUrl)
} }

View File

@ -0,0 +1,84 @@
import { Chain } from 'wagmi'
import * as wagmiChains from 'wagmi/chains'
export const energyWeb = {
id: 246,
name: 'Energy Web Chain',
network: 'energyweb',
nativeCurrency: {
decimals: 18,
name: 'EWT',
symbol: 'EWT'
},
rpcUrls: {
public: {
http: ['https://rpc.energyweb.org'],
webSocket: ['wss://rpc.energyweb.org/ws']
},
default: {
http: ['https://rpc.energyweb.org'],
webSocket: ['wss://rpc.energyweb.org/ws']
}
},
blockExplorers: {
default: {
name: 'Energy Web Chain',
url: 'https://explorer.energyweb.org/'
},
blockscout: {
name: 'Energy Web Chain',
url: 'https://explorer.energyweb.org/'
}
},
testnet: false
} as Chain
// TODO: remove once moonriver is shipped in wagmi as it is already in codebase
// https://github.com/wagmi-dev/references/blob/main/packages/chains/src/moonriver.ts
export const moonriver = {
id: 1285,
name: 'Moonriver',
network: 'moonriver',
nativeCurrency: {
decimals: 18,
name: 'MOVR',
symbol: 'MOVR'
},
rpcUrls: {
public: {
http: ['https://moonriver.public.blastapi.io'],
webSocket: ['wss://moonriver.public.blastapi.io']
},
default: {
http: ['https://moonriver.public.blastapi.io'],
webSocket: ['wss://moonriver.public.blastapi.io']
}
},
blockExplorers: {
default: {
name: 'Moonscan',
url: 'https://moonriver.moonscan.io'
},
etherscan: {
name: 'Moonscan',
url: 'https://moonriver.moonscan.io'
}
},
contracts: {
multicall3: {
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
blockCreated: 1597904
}
},
testnet: false
} as Chain
export const getSupportedChains = (chainIdsSupported: number[]): Chain[] => {
const chains = [wagmiChains, energyWeb, moonriver].map((chain) => {
return Object.values(chain).filter((chain) =>
chainIdsSupported.includes(chain.id)
)
})
console.log(chains.flat())
return chains.flat()
}

View File

@ -1,8 +1,37 @@
import { getNetworkDisplayName } from '@hooks/useNetworkMetadata'
import { LoggerInstance } from '@oceanprotocol/lib' import { LoggerInstance } from '@oceanprotocol/lib'
import Web3 from 'web3' import { createClient, erc20ABI } from 'wagmi'
import { getOceanConfig } from './ocean' import { mainnet, polygon, bsc, goerli, polygonMumbai } from 'wagmi/chains'
import { AbiItem } from 'web3-utils/types' import { ethers, Contract } from 'ethers'
import { formatEther } from 'ethers/lib/utils'
import { getDefaultClient } from 'connectkit'
import { energyWeb, moonriver } from './chains'
import { getNetworkDisplayName } from '@hooks/useNetworkMetadata'
import { getOceanConfig } from '../ocean'
// Wagmi client
export const wagmiClient = createClient(
getDefaultClient({
appName: 'Ocean Market',
infuraId: process.env.NEXT_PUBLIC_INFURA_PROJECT_ID,
// TODO: mapping between appConfig.chainIdsSupported and wagmi chainId
chains: [mainnet, polygon, bsc, energyWeb, moonriver, goerli, polygonMumbai]
})
)
// ConnectKit CSS overrides
// https://docs.family.co/connectkit/theming#theme-variables
export const connectKitTheme = {
'--ck-font-family': 'var(--font-family-base)',
'--ck-border-radius': 'var(--border-radius)',
'--ck-overlay-background': 'var(--background-body-transparent)',
'--ck-modal-box-shadow': '0 0 20px 20px var(--box-shadow-color)',
'--ck-body-background': 'var(--background-body)',
'--ck-body-color': 'var(--font-color-text)',
'--ck-primary-button-border-radius': 'var(--border-radius)',
'--ck-primary-button-color': 'var(--font-color-heading)',
'--ck-primary-button-background': 'var(--background-content)',
'--ck-secondary-button-border-radius': 'var(--border-radius)'
}
export function accountTruncate(account: string): string { export function accountTruncate(account: string): string {
if (!account || account === '') return if (!account || account === '') return
@ -10,14 +39,41 @@ export function accountTruncate(account: string): string {
const truncated = account.replace(middle, '…') const truncated = account.replace(middle, '…')
return truncated return truncated
} }
/**
* returns a dummy web3 instance, only usable to get info from the chain export async function addTokenToWallet(
* @param chainId address: string,
* @returns Web3 instance symbol: string,
*/ logo?: string
export async function getDummyWeb3(chainId: number): Promise<Web3> { ): Promise<void> {
const config = getOceanConfig(chainId) const image =
return new Web3(config.nodeUri) logo ||
'https://raw.githubusercontent.com/oceanprotocol/art/main/logo/token.png'
const tokenMetadata = {
type: 'ERC20',
options: { address, symbol, image, decimals: 18 }
}
;(window?.ethereum.request as any)(
{
method: 'wallet_watchAsset',
params: tokenMetadata,
id: Math.round(Math.random() * 100000)
},
(err: { code: number; message: string }, added: any) => {
if (err || 'error' in added) {
LoggerInstance.error(
`Couldn't add ${tokenMetadata.options.symbol} (${
tokenMetadata.options.address
}) to MetaMask, error: ${err.message || added.error}`
)
} else {
LoggerInstance.log(
`Added ${tokenMetadata.options.symbol} (${tokenMetadata.options.address}) to MetaMask`
)
}
}
)
} }
export async function addCustomNetwork( export async function addCustomNetwork(
@ -75,78 +131,19 @@ export async function addCustomNetwork(
) )
} }
export async function addTokenToWallet(
web3Provider: any,
address: string,
symbol: string,
logo?: string
): Promise<void> {
const image =
logo ||
'https://raw.githubusercontent.com/oceanprotocol/art/main/logo/token.png'
const tokenMetadata = {
type: 'ERC20',
options: { address, symbol, image, decimals: 18 }
}
web3Provider.sendAsync(
{
method: 'wallet_watchAsset',
params: tokenMetadata,
id: Math.round(Math.random() * 100000)
},
(err: { code: number; message: string }, added: any) => {
if (err || 'error' in added) {
LoggerInstance.error(
`Couldn't add ${tokenMetadata.options.symbol} (${
tokenMetadata.options.address
}) to MetaMask, error: ${err.message || added.error}`
)
} else {
LoggerInstance.log(
`Added ${tokenMetadata.options.symbol} (${tokenMetadata.options.address}) to MetaMask`
)
}
}
)
}
export async function getTokenBalance( export async function getTokenBalance(
accountId: string, accountId: string,
decimals: number, decimals: number,
tokenAddress: string, tokenAddress: string,
web3: Web3 web3Provider: ethers.providers.Provider
): Promise<string> { ): Promise<string> {
const minABI = [ if (!web3Provider || !accountId || !tokenAddress) return
{
constant: true,
inputs: [
{
name: '_owner',
type: 'address'
}
],
name: 'balanceOf',
outputs: [
{
name: 'balance',
type: 'uint256'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
}
] as AbiItem[]
try { try {
const token = new web3.eth.Contract(minABI, tokenAddress, { const token = new Contract(tokenAddress, erc20ABI, web3Provider)
from: accountId const balance = await token.balanceOf(accountId)
})
const balance = await token.methods.balanceOf(accountId).call()
const adjustedDecimalsBalance = `${balance}${'0'.repeat(18 - decimals)}` const adjustedDecimalsBalance = `${balance}${'0'.repeat(18 - decimals)}`
return web3.utils.fromWei(adjustedDecimalsBalance) return formatEther(adjustedDecimalsBalance)
} catch (e) { } catch (e) {
LoggerInstance.error(`ERROR: Failed to get the balance: ${e.message}`) LoggerInstance.error(`ERROR: Failed to get the balance: ${e.message}`)
} }
@ -157,6 +154,7 @@ export function getTokenBalanceFromSymbol(
symbol: string symbol: string
): string { ): string {
if (!symbol) return if (!symbol) return
const baseTokenBalance = balance?.[symbol.toLocaleLowerCase()] const baseTokenBalance = balance?.[symbol.toLocaleLowerCase()]
return baseTokenBalance || '0' return baseTokenBalance || '0'
} }

View File

@ -1,7 +1,7 @@
import { isCID } from '@utils/ipfs' import { isCID } from '@utils/ipfs'
import isUrl from 'is-url-superb' import isUrl from 'is-url-superb'
import * as Yup from 'yup' import * as Yup from 'yup'
import web3 from 'web3' import { ethers } from 'ethers'
import { isGoogleUrl } from './url/index' import { isGoogleUrl } from './url/index'
export function testLinks(isEdit?: boolean) { export function testLinks(isEdit?: boolean) {
@ -49,7 +49,7 @@ export function testLinks(isEdit?: boolean) {
: 'Transaction ID not valid.' : 'Transaction ID not valid.'
break break
case 'smartcontract': case 'smartcontract':
validField = web3.utils.isAddress(value?.toString()) validField = ethers.utils.isAddress(value?.toString())
errorMessage = !value?.toString() errorMessage = !value?.toString()
? 'Address required.' ? 'Address required.'
: 'Address not valid.' : 'Address not valid.'

View File

@ -3,7 +3,7 @@ import React from 'react'
import testRender from '../../../../.jest/testRender' import testRender from '../../../../.jest/testRender'
import AddToken from './index' import AddToken from './index'
jest.mock('../../../@utils/web3', () => ({ addTokenToWallet: jest.fn() })) jest.mock('../../../@utils/wallet', () => ({ addTokenToWallet: jest.fn() }))
describe('@shared/AddToken', () => { describe('@shared/AddToken', () => {
const propsBase = { const propsBase = {

View File

@ -1,7 +1,6 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import { addTokenToWallet } from '@utils/web3' import { addTokenToWallet } from '@utils/wallet'
import { useWeb3 } from '@context/Web3'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import OceanLogo from '@images/logo.svg' import OceanLogo from '@images/logo.svg'
import styles from './index.module.css' import styles from './index.module.css'
@ -23,8 +22,6 @@ export default function AddToken({
className, className,
minimal minimal
}: AddTokenProps): ReactElement { }: AddTokenProps): ReactElement {
const { web3Provider } = useWeb3()
const styleClasses = cx({ const styleClasses = cx({
button: true, button: true,
minimal, minimal,
@ -32,9 +29,9 @@ export default function AddToken({
}) })
async function handleAddToken() { async function handleAddToken() {
if (!web3Provider) return if (!window?.ethereum) return
await addTokenToWallet(web3Provider, address, symbol) await addTokenToWallet(address, symbol)
} }
return ( return (

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import styles from './DmButton.module.css' import styles from './DmButton.module.css'
import { useWeb3 } from '@context/Web3' import { useAccount, useConnect } from 'wagmi'
import { useOrbis } from '@context/DirectMessages' import { useOrbis } from '@context/DirectMessages'
export default function DmButton({ export default function DmButton({
@ -11,7 +11,7 @@ export default function DmButton({
accountId: string accountId: string
text?: string text?: string
}) { }) {
const { accountId: ownAccountId, connect } = useWeb3() const { address: ownAccountId } = useAccount()
const { const {
checkOrbisConnection, checkOrbisConnection,
getConversationByDid, getConversationByDid,
@ -24,10 +24,9 @@ export default function DmButton({
const [isCreatingConversation, setIsCreatingConversation] = useState(false) const [isCreatingConversation, setIsCreatingConversation] = useState(false)
const handleActivation = async () => { const handleActivation = async () => {
const resConnect = await connect() if (ownAccountId) {
if (resConnect) {
await checkOrbisConnection({ await checkOrbisConnection({
address: resConnect, address: ownAccountId,
autoConnect: true, autoConnect: true,
lit: true lit: true
}) })

View File

@ -1,6 +1,6 @@
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import styles from './Header.module.css' import styles from './Header.module.css'
import { useWeb3 } from '@context/Web3' import { useAccount } from 'wagmi'
import { useOrbis } from '@context/DirectMessages' import { useOrbis } from '@context/DirectMessages'
import { didToAddress } from './_utils' import { didToAddress } from './_utils'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
@ -10,7 +10,7 @@ import ChevronUp from '@images/chevronup.svg'
import Copy from '@images/copy.svg' import Copy from '@images/copy.svg'
export default function Header() { export default function Header() {
const { accountId } = useWeb3() const { address: accountId } = useAccount()
const { const {
conversations, conversations,
conversationId, conversationId,

View File

@ -2,7 +2,7 @@ import React, { useRef } from 'react'
import styles from './Postbox.module.css' import styles from './Postbox.module.css'
import { useOrbis } from '@context/DirectMessages' import { useOrbis } from '@context/DirectMessages'
import SendIcon from '@images/send.svg' import SendIcon from '@images/send.svg'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/wallet'
import { didToAddress } from './_utils' import { didToAddress } from './_utils'
import { import {
IOrbisMessage, IOrbisMessage,

View File

@ -2,19 +2,18 @@ import React from 'react'
import styles from './index.module.css' import styles from './index.module.css'
import Conversation from './Conversation' import Conversation from './Conversation'
import { useOrbis } from '@context/DirectMessages' import { useOrbis } from '@context/DirectMessages'
import { useWeb3 } from '@context/Web3' import { useAccount, useConnect } from 'wagmi'
import Header from './Header' import Header from './Header'
import List from './List' import List from './List'
import walletStyles from '../../Header/Wallet/Account.module.css' import walletStyles from '../../Header/Wallet/Account.module.css'
const BodyContent = () => { const BodyContent = () => {
const { account, conversationId, checkOrbisConnection } = useOrbis() const { account, conversationId, checkOrbisConnection } = useOrbis()
const { accountId, connect } = useWeb3() const { address: accountId } = useAccount()
const handleActivation = async (e: React.MouseEvent) => { const handleActivation = async (e: React.MouseEvent) => {
e.preventDefault() e.preventDefault()
const resConnect = await connect() if (accountId) {
if (resConnect) {
await checkOrbisConnection({ await checkOrbisConnection({
address: accountId, address: accountId,
autoConnect: true, autoConnect: true,

View File

@ -7,7 +7,7 @@ import { getFileInfo, checkValidProvider } from '@utils/provider'
import { LoggerInstance, FileInfo } from '@oceanprotocol/lib' import { LoggerInstance, FileInfo } from '@oceanprotocol/lib'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import styles from './index.module.css' import styles from './index.module.css'
import { useWeb3 } from '@context/Web3' import { useNetwork } from 'wagmi'
import InputHeaders from '../Headers' import InputHeaders from '../Headers'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import Loader from '@shared/atoms/Loader' import Loader from '@shared/atoms/Loader'
@ -21,7 +21,8 @@ export default function FilesInput(props: InputProps): ReactElement {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [disabledButton, setDisabledButton] = useState(true) const [disabledButton, setDisabledButton] = useState(true)
const { asset } = useAsset() const { asset } = useAsset()
const { chainId } = useWeb3() const { chain } = useNetwork()
const chainId = chain?.id
const providerUrl = props.form?.values?.services const providerUrl = props.form?.values?.services
? props.form?.values?.services[0].providerUrl.url ? props.form?.values?.services[0].providerUrl.url
@ -60,7 +61,7 @@ export default function FilesInput(props: InputProps): ReactElement {
query, query,
headers, headers,
abi, abi,
chainId, chain?.id,
method method
) )

View File

@ -8,12 +8,12 @@ import Button from '@shared/atoms/Button'
import { LoggerInstance, ProviderInstance } from '@oceanprotocol/lib' import { LoggerInstance, ProviderInstance } from '@oceanprotocol/lib'
import { FormPublishData } from '@components/Publish/_types' import { FormPublishData } from '@components/Publish/_types'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig } from '@utils/ocean'
import { useWeb3 } from '@context/Web3'
import axios from 'axios' import axios from 'axios'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { useNetwork } from 'wagmi'
export default function CustomProvider(props: InputProps): ReactElement { export default function CustomProvider(props: InputProps): ReactElement {
const { chainId } = useWeb3() const { chain } = useNetwork()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
const { initialValues, setFieldError } = useFormikContext<FormPublishData>() const { initialValues, setFieldError } = useFormikContext<FormPublishData>()
const [field, meta, helpers] = useField(props.name) const [field, meta, helpers] = useField(props.name)
@ -40,7 +40,7 @@ export default function CustomProvider(props: InputProps): ReactElement {
const providerResponse = await axios.get(field.value.url, { const providerResponse = await axios.get(field.value.url, {
cancelToken: newCancelToken() cancelToken: newCancelToken()
}) })
const userChainId = chainId || 1 const userChainId = chain?.id || 1
const providerChain = const providerChain =
providerResponse?.data?.chainId || providerResponse?.data?.chainIds providerResponse?.data?.chainId || providerResponse?.data?.chainIds
@ -71,7 +71,7 @@ export default function CustomProvider(props: InputProps): ReactElement {
function handleDefault(e: React.SyntheticEvent) { function handleDefault(e: React.SyntheticEvent) {
e.preventDefault() e.preventDefault()
const oceanConfig = getOceanConfig(chainId) const oceanConfig = getOceanConfig(chain?.id)
const providerUrl = const providerUrl =
oceanConfig?.providerUri || initialValues.services[0].providerUrl.url oceanConfig?.providerUri || initialValues.services[0].providerUrl.url

View File

@ -7,7 +7,6 @@ import InputGroup from '@shared/FormInput/InputGroup'
import InputElement from '@shared/FormInput/InputElement' import InputElement from '@shared/FormInput/InputElement'
import isUrl from 'is-url-superb' import isUrl from 'is-url-superb'
import { isCID } from '@utils/ipfs' import { isCID } from '@utils/ipfs'
import web3 from 'web3'
export interface URLInputProps { export interface URLInputProps {
submitText: string submitText: string
handleButtonClick(e: React.SyntheticEvent, data: string): void handleButtonClick(e: React.SyntheticEvent, data: string): void

View File

@ -1,7 +1,7 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import styles from './index.module.css' import styles from './index.module.css'
import Link from 'next/link' import Link from 'next/link'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/wallet'
import { getEnsName } from '@utils/ens' import { getEnsName } from '@utils/ens'
import { useIsMounted } from '@hooks/useIsMounted' import { useIsMounted } from '@hooks/useIsMounted'

View File

@ -2,7 +2,7 @@ import { render, fireEvent, screen } from '@testing-library/react'
import React from 'react' import React from 'react'
import WalletNetworkSwitcher from './' import WalletNetworkSwitcher from './'
jest.mock('../../../@utils/web3', () => ({ jest.mock('../../../@utils/wallet', () => ({
addCustomNetwork: () => jest.fn() addCustomNetwork: () => jest.fn()
})) }))

View File

@ -1,21 +1,21 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { useWeb3 } from '@context/Web3'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import styles from './index.module.css' import styles from './index.module.css'
import { addCustomNetwork } from '@utils/web3'
import useNetworkMetadata, { import useNetworkMetadata, {
getNetworkDataById, getNetworkDataById,
getNetworkDisplayName getNetworkDisplayName
} from '@hooks/useNetworkMetadata' } from '@hooks/useNetworkMetadata'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useNetwork, useSwitchNetwork } from 'wagmi'
export default function WalletNetworkSwitcher(): ReactElement { export default function WalletNetworkSwitcher(): ReactElement {
const { networkId, web3Provider } = useWeb3() const { chain } = useNetwork()
const { asset } = useAsset() const { asset } = useAsset()
const { switchNetwork } = useSwitchNetwork({ chainId: asset?.chainId })
const { networksList } = useNetworkMetadata() const { networksList } = useNetworkMetadata()
const ddoNetworkData = getNetworkDataById(networksList, asset.chainId) const ddoNetworkData = getNetworkDataById(networksList, asset.chainId)
const walletNetworkData = getNetworkDataById(networksList, networkId) const walletNetworkData = getNetworkDataById(networksList, chain?.id)
const ddoNetworkName = ( const ddoNetworkName = (
<strong>{getNetworkDisplayName(ddoNetworkData)}</strong> <strong>{getNetworkDisplayName(ddoNetworkData)}</strong>
@ -24,13 +24,6 @@ export default function WalletNetworkSwitcher(): ReactElement {
<strong>{getNetworkDisplayName(walletNetworkData)}</strong> <strong>{getNetworkDisplayName(walletNetworkData)}</strong>
) )
async function switchWalletNetwork() {
const networkNode = await networksList.find(
(data) => data.chainId === asset.chainId
)
addCustomNetwork(web3Provider, networkNode)
}
return ( return (
<> <>
<p className={styles.text}> <p className={styles.text}>
@ -38,7 +31,7 @@ export default function WalletNetworkSwitcher(): ReactElement {
to {walletNetworkName}. Connect to {ddoNetworkName} to interact with to {walletNetworkName}. Connect to {ddoNetworkName} to interact with
this asset. this asset.
</p> </p>
<Button size="small" onClick={() => switchWalletNetwork()}> <Button size="small" onClick={() => switchNetwork()}>
Switch to {ddoNetworkName} Switch to {ddoNetworkName}
</Button> </Button>
</> </>

View File

@ -33,11 +33,11 @@ export default function Web3Feedback({
if (!accountId) { if (!accountId) {
setState('error') setState('error')
setTitle('No account connected') setTitle('No account connected')
setMessage('Please connect your Web3 wallet.') setMessage('Please connect your wallet.')
} else if (isAssetNetwork === false) { } else if (isAssetNetwork === false) {
setState('error') setState('error')
setTitle('Not connected to asset network') setTitle('Not connected to asset network')
setMessage('Please connect your Web3 wallet.') setMessage('Please connect your wallet.')
} else if (isGraphSynced === false) { } else if (isGraphSynced === false) {
setState('warning') setState('warning')
setTitle('Data out of sync') setTitle('Data out of sync')

View File

@ -2,7 +2,6 @@ import React, { ReactElement } from 'react'
import Alert from '@shared/atoms/Alert' import Alert from '@shared/atoms/Alert'
import Footer from '../Footer/Footer' import Footer from '../Footer/Footer'
import Header from '../Header' import Header from '../Header'
import { useWeb3 } from '@context/Web3'
import { useAccountPurgatory } from '@hooks/useAccountPurgatory' import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
import AnnouncementBanner from '@shared/AnnouncementBanner' import AnnouncementBanner from '@shared/AnnouncementBanner'
import PrivacyPreferenceCenter from '../Privacy/PrivacyPreferenceCenter' import PrivacyPreferenceCenter from '../Privacy/PrivacyPreferenceCenter'
@ -10,6 +9,7 @@ import styles from './index.module.css'
import { ToastContainer } from 'react-toastify' import { ToastContainer } from 'react-toastify'
import contentPurgatory from '../../../content/purgatory.json' import contentPurgatory from '../../../content/purgatory.json'
import { useMarketMetadata } from '@context/MarketMetadata' import { useMarketMetadata } from '@context/MarketMetadata'
import { useAccount } from 'wagmi'
export default function App({ export default function App({
children children
@ -17,8 +17,8 @@ export default function App({
children: ReactElement children: ReactElement
}): ReactElement { }): ReactElement {
const { siteContent, appConfig } = useMarketMetadata() const { siteContent, appConfig } = useMarketMetadata()
const { accountId } = useWeb3() const { address } = useAccount()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId) const { isInPurgatory, purgatoryData } = useAccountPurgatory(address)
return ( return (
<div className={styles.app}> <div className={styles.app}>

View File

@ -1,16 +1,16 @@
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import { useWeb3 } from '@context/Web3'
import Tooltip from '@shared/atoms/Tooltip' import Tooltip from '@shared/atoms/Tooltip'
import { formatNumber } from '@utils/numbers' import { formatNumber } from '@utils/numbers'
import { getNftOwnAllocation } from '@utils/veAllocation' import { getNftOwnAllocation } from '@utils/veAllocation'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { useAccount } from 'wagmi'
import styles from './index.module.css' import styles from './index.module.css'
export default function AssetStats() { export default function AssetStats() {
const { locale } = useUserPreferences() const { locale } = useUserPreferences()
const { asset } = useAsset() const { asset } = useAsset()
const { accountId } = useWeb3() const { address: accountId } = useAccount()
const [ownAllocation, setOwnAllocation] = useState(0) const [ownAllocation, setOwnAllocation] = useState(0)

View File

@ -16,7 +16,8 @@ const downloadProps: ButtonBuyProps = {
priceType: 'fixed', priceType: 'fixed',
isConsumable: true, isConsumable: true,
isBalanceSufficient: true, isBalanceSufficient: true,
consumableFeedback: 'TEST: consumableFeedback' consumableFeedback: 'TEST: consumableFeedback',
isAccountConnected: true
} }
const computeProps: ButtonBuyProps = { const computeProps: ButtonBuyProps = {
@ -114,7 +115,7 @@ describe('Asset/AssetActions/ButtonBuy', () => {
render(<ButtonBuy {...computeProps} />) render(<ButtonBuy {...computeProps} />)
expect( expect(
screen.getByText( screen.getByText(
'To use this algorithm, you will buy 1 dtSymbol and immediately send it back to the publisher. Connect to the correct network to interact with this asset. The C2D resources required to start the job are available, no payment is required for them. Please note that network gas fees still apply, even when using free assets.' 'To use this algorithm, you will buy 1 dtSymbol and immediately send it back to the publisher. Additionally, the selected selectedComputeAssetType is free to use. The C2D resources required to start the job are available, no payment is required for them. Please note that network gas fees still apply, even when using free assets.'
) )
).toBeInTheDocument() ).toBeInTheDocument()
}) })
@ -123,7 +124,7 @@ describe('Asset/AssetActions/ButtonBuy', () => {
render(<ButtonBuy {...computeProps} priceType="free" />) render(<ButtonBuy {...computeProps} priceType="free" />)
expect( expect(
screen.getByText( screen.getByText(
'This algorithm is free to use. Connect to the correct network to interact with this asset. The C2D resources required to start the job are available, no payment is required for them. Please note that network gas fees still apply, even when using free assets.' 'This algorithm is free to use. Additionally, the selected selectedComputeAssetType is free to use. The C2D resources required to start the job are available, no payment is required for them. Please note that network gas fees still apply, even when using free assets.'
) )
).toBeInTheDocument() ).toBeInTheDocument()
}) })
@ -132,7 +133,7 @@ describe('Asset/AssetActions/ButtonBuy', () => {
render(<ButtonBuy {...computeProps} algorithmPriceType="fixed" />) render(<ButtonBuy {...computeProps} algorithmPriceType="fixed" />)
expect( expect(
screen.getByText( screen.getByText(
'To use this algorithm, you will buy 1 dtSymbol and immediately send it back to the publisher. Connect to the correct network to interact with this asset. The C2D resources required to start the job are available, no payment is required for them.' 'To use this algorithm, you will buy 1 dtSymbol and immediately send it back to the publisher. Additionally, you will buy 1 dtSymbol for the selectedComputeAssetType and send it back to the publisher. The C2D resources required to start the job are available, no payment is required for them.'
) )
).toBeInTheDocument() ).toBeInTheDocument()
}) })

View File

@ -2,8 +2,6 @@ import React, { FormEvent, ReactElement } from 'react'
import Button from '../../../@shared/atoms/Button' import Button from '../../../@shared/atoms/Button'
import styles from './index.module.css' import styles from './index.module.css'
import Loader from '../../../@shared/atoms/Loader' import Loader from '../../../@shared/atoms/Loader'
import { useWeb3 } from '@context/Web3'
import Web3 from 'web3'
export interface ButtonBuyProps { export interface ButtonBuyProps {
action: 'download' | 'compute' action: 'download' | 'compute'
@ -31,6 +29,7 @@ export interface ButtonBuyProps {
algorithmPriceType?: string algorithmPriceType?: string
isAlgorithmConsumable?: boolean isAlgorithmConsumable?: boolean
isSupportedOceanNetwork?: boolean isSupportedOceanNetwork?: boolean
isAccountConnected?: boolean
hasProviderFee?: boolean hasProviderFee?: boolean
retry?: boolean retry?: boolean
} }
@ -46,13 +45,13 @@ function getConsumeHelpText(
isBalanceSufficient: boolean, isBalanceSufficient: boolean,
consumableFeedback: string, consumableFeedback: string,
isSupportedOceanNetwork: boolean, isSupportedOceanNetwork: boolean,
web3: Web3, isAccountConnected: boolean,
priceType: string priceType: string
) { ) {
const text = const text =
isConsumable === false isConsumable === false
? consumableFeedback ? consumableFeedback
: hasPreviousOrder && web3 && isSupportedOceanNetwork : hasPreviousOrder && isAccountConnected && isSupportedOceanNetwork
? `You bought this ${assetType} already allowing you to use it without paying again.` ? `You bought this ${assetType} already allowing you to use it without paying again.`
: hasDatatoken : hasDatatoken
? `You own ${dtBalance} ${dtSymbol} allowing you to use this dataset by spending 1 ${dtSymbol}, but without paying ${btSymbol} again.` ? `You own ${dtBalance} ${dtSymbol} allowing you to use this dataset by spending 1 ${dtSymbol}, but without paying ${btSymbol} again.`
@ -74,7 +73,7 @@ function getAlgoHelpText(
hasDatatokenSelectedComputeAsset: boolean, hasDatatokenSelectedComputeAsset: boolean,
isBalanceSufficient: boolean, isBalanceSufficient: boolean,
isSupportedOceanNetwork: boolean, isSupportedOceanNetwork: boolean,
web3: Web3, isAccountConnected: boolean,
algorithmPriceType: string algorithmPriceType: string
) { ) {
const text = const text =
@ -82,11 +81,13 @@ function getAlgoHelpText(
isConsumable === false || isConsumable === false ||
isAlgorithmConsumable === false isAlgorithmConsumable === false
? '' ? ''
: hasPreviousOrderSelectedComputeAsset && web3 && isSupportedOceanNetwork : hasPreviousOrderSelectedComputeAsset &&
isAccountConnected &&
isSupportedOceanNetwork
? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.` ? `You already bought the selected ${selectedComputeAssetType}, allowing you to use it without paying again.`
: hasDatatokenSelectedComputeAsset : hasDatatokenSelectedComputeAsset
? `You own ${dtBalanceSelectedComputeAsset} ${dtSymbolSelectedComputeAsset} allowing you to use the selected ${selectedComputeAssetType} by spending 1 ${dtSymbolSelectedComputeAsset}, but without paying OCEAN again.` ? `You own ${dtBalanceSelectedComputeAsset} ${dtSymbolSelectedComputeAsset} allowing you to use the selected ${selectedComputeAssetType} by spending 1 ${dtSymbolSelectedComputeAsset}, but without paying OCEAN again.`
: web3 && !isSupportedOceanNetwork : isAccountConnected && !isSupportedOceanNetwork
? `Connect to the correct network to interact with this asset.` ? `Connect to the correct network to interact with this asset.`
: isBalanceSufficient === false : isBalanceSufficient === false
? '' ? ''
@ -115,7 +116,7 @@ function getComputeAssetHelpText(
selectedComputeAssetType?: string, selectedComputeAssetType?: string,
isAlgorithmConsumable?: boolean, isAlgorithmConsumable?: boolean,
isSupportedOceanNetwork?: boolean, isSupportedOceanNetwork?: boolean,
web3?: Web3, isAccountConnected?: boolean,
hasProviderFee?: boolean hasProviderFee?: boolean
) { ) {
const computeAssetHelpText = getConsumeHelpText( const computeAssetHelpText = getConsumeHelpText(
@ -129,7 +130,7 @@ function getComputeAssetHelpText(
isBalanceSufficient, isBalanceSufficient,
consumableFeedback, consumableFeedback,
isSupportedOceanNetwork, isSupportedOceanNetwork,
web3, isAccountConnected,
priceType priceType
) )
@ -143,7 +144,7 @@ function getComputeAssetHelpText(
hasDatatokenSelectedComputeAsset, hasDatatokenSelectedComputeAsset,
isBalanceSufficient, isBalanceSufficient,
isSupportedOceanNetwork, isSupportedOceanNetwork,
web3, isAccountConnected,
algorithmPriceType algorithmPriceType
) )
@ -183,9 +184,9 @@ export default function ButtonBuy({
isAlgorithmConsumable, isAlgorithmConsumable,
hasProviderFee, hasProviderFee,
retry, retry,
isSupportedOceanNetwork isSupportedOceanNetwork,
isAccountConnected
}: ButtonBuyProps): ReactElement { }: ButtonBuyProps): ReactElement {
const { web3 } = useWeb3()
const buttonText = retry const buttonText = retry
? 'Retry' ? 'Retry'
: action === 'download' : action === 'download'
@ -216,7 +217,7 @@ export default function ButtonBuy({
isBalanceSufficient, isBalanceSufficient,
consumableFeedback, consumableFeedback,
isSupportedOceanNetwork, isSupportedOceanNetwork,
web3, isAccountConnected,
priceType priceType
) )
} else { } else {
@ -239,7 +240,7 @@ export default function ButtonBuy({
selectedComputeAssetType, selectedComputeAssetType,
isAlgorithmConsumable, isAlgorithmConsumable,
isSupportedOceanNetwork, isSupportedOceanNetwork,
web3, isAccountConnected,
hasProviderFee hasProviderFee
) )
} }

View File

@ -7,15 +7,17 @@ import { compareAsBN } from '@utils/numbers'
import ButtonBuy from '../ButtonBuy' import ButtonBuy from '../ButtonBuy'
import PriceOutput from './PriceOutput' import PriceOutput from './PriceOutput'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3'
import content from '../../../../../content/pages/startComputeDataset.json' import content from '../../../../../content/pages/startComputeDataset.json'
import { Asset, ZERO_ADDRESS } from '@oceanprotocol/lib' import { Asset, ZERO_ADDRESS } from '@oceanprotocol/lib'
import { getAccessDetails } from '@utils/accessDetailsAndPricing' import { getAccessDetails } from '@utils/accessDetailsAndPricing'
import { useMarketMetadata } from '@context/MarketMetadata' import { useMarketMetadata } from '@context/MarketMetadata'
import Alert from '@shared/atoms/Alert' import Alert from '@shared/atoms/Alert'
import { getTokenBalanceFromSymbol } from '@utils/web3' import { getTokenBalanceFromSymbol } from '@utils/wallet'
import { MAX_DECIMALS } from '@utils/constants' import { MAX_DECIMALS } from '@utils/constants'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import { useAccount } from 'wagmi'
import useBalance from '@hooks/useBalance'
import useNetworkMetadata from '@hooks/useNetworkMetadata'
export default function FormStartCompute({ export default function FormStartCompute({
algorithms, algorithms,
@ -77,7 +79,9 @@ export default function FormStartCompute({
retry: boolean retry: boolean
}): ReactElement { }): ReactElement {
const { siteContent } = useMarketMetadata() const { siteContent } = useMarketMetadata()
const { accountId, balance, isSupportedOceanNetwork } = useWeb3() const { address: accountId, isConnected } = useAccount()
const { balance } = useBalance()
const { isSupportedOceanNetwork } = useNetworkMetadata()
const { isValid, values }: FormikContextType<{ algorithm: string }> = const { isValid, values }: FormikContextType<{ algorithm: string }> =
useFormikContext() useFormikContext()
const { asset, isAssetNetwork } = useAsset() const { asset, isAssetNetwork } = useAsset()
@ -303,6 +307,7 @@ export default function FormStartCompute({
isSupportedOceanNetwork={isSupportedOceanNetwork} isSupportedOceanNetwork={isSupportedOceanNetwork}
hasProviderFee={providerFeeAmount && providerFeeAmount !== '0'} hasProviderFee={providerFeeAmount && providerFeeAmount !== '0'}
retry={retry} retry={retry}
isAccountConnected={isConnected}
/> />
</Form> </Form>
) )

View File

@ -5,7 +5,7 @@ import Tooltip from '@shared/atoms/Tooltip'
import styles from './PriceOutput.module.css' import styles from './PriceOutput.module.css'
import { MAX_DECIMALS } from '@utils/constants' import { MAX_DECIMALS } from '@utils/constants'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import { useWeb3 } from '@context/Web3' import useNetworkMetadata from '@hooks/useNetworkMetadata'
interface PriceOutputProps { interface PriceOutputProps {
hasPreviousOrder: boolean hasPreviousOrder: boolean

View File

@ -20,7 +20,6 @@ import { toast } from 'react-toastify'
import Price from '@shared/Price' import Price from '@shared/Price'
import FileIcon from '@shared/FileIcon' import FileIcon from '@shared/FileIcon'
import Alert from '@shared/atoms/Alert' import Alert from '@shared/atoms/Alert'
import { useWeb3 } from '@context/Web3'
import { Formik } from 'formik' import { Formik } from 'formik'
import { getInitialValues, validationSchema } from './_constants' import { getInitialValues, validationSchema } from './_constants'
import FormStartComputeDataset from './FormComputeDataset' import FormStartComputeDataset from './FormComputeDataset'
@ -44,12 +43,12 @@ import { useAbortController } from '@hooks/useAbortController'
import { getOrderPriceAndFees } from '@utils/accessDetailsAndPricing' import { getOrderPriceAndFees } from '@utils/accessDetailsAndPricing'
import { handleComputeOrder } from '@utils/order' import { handleComputeOrder } from '@utils/order'
import { getComputeFeedback } from '@utils/feedback' import { getComputeFeedback } from '@utils/feedback'
import { getDummyWeb3 } from '@utils/web3'
import { initializeProviderForCompute } from '@utils/provider' import { initializeProviderForCompute } from '@utils/provider'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import { useAsset } from '@context/Asset' import { useAccount, useSigner } from 'wagmi'
const refreshInterval = 10000 // 10 sec. const refreshInterval = 10000 // 10 sec.
export default function Compute({ export default function Compute({
asset, asset,
dtBalance, dtBalance,
@ -63,9 +62,9 @@ export default function Compute({
fileIsLoading?: boolean fileIsLoading?: boolean
consumableFeedback?: string consumableFeedback?: string
}): ReactElement { }): ReactElement {
const { accountId, web3, isSupportedOceanNetwork, networkId } = useWeb3() const { address: accountId } = useAccount()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const { isAssetNetwork } = useAsset() const { data: signer } = useSigner()
const newAbortController = useAbortController() const newAbortController = useAbortController()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
@ -116,10 +115,9 @@ export default function Compute({
const isUnsupportedPricing = asset?.accessDetails?.type === 'NOT_SUPPORTED' const isUnsupportedPricing = asset?.accessDetails?.type === 'NOT_SUPPORTED'
async function checkAssetDTBalance(asset: DDO): Promise<boolean> { async function checkAssetDTBalance(asset: DDO) {
if (!asset?.services[0].datatokenAddress) return if (!asset?.services[0].datatokenAddress) return
const web3 = await getDummyWeb3(asset?.chainId) const datatokenInstance = new Datatoken(signer)
const datatokenInstance = new Datatoken(web3)
const dtBalance = await datatokenInstance.balance( const dtBalance = await datatokenInstance.balance(
asset?.services[0].datatokenAddress, asset?.services[0].datatokenAddress,
accountId || ZERO_ADDRESS // if the user is not connected, we use ZERO_ADDRESS as accountId accountId || ZERO_ADDRESS // if the user is not connected, we use ZERO_ADDRESS as accountId
@ -127,7 +125,6 @@ export default function Compute({
setAlgorithmDTBalance(new Decimal(dtBalance).toString()) setAlgorithmDTBalance(new Decimal(dtBalance).toString())
const hasAlgoDt = Number(dtBalance) >= 1 const hasAlgoDt = Number(dtBalance) >= 1
setHasAlgoAssetDatatoken(hasAlgoDt) setHasAlgoAssetDatatoken(hasAlgoDt)
return hasAlgoDt
} }
async function setComputeFees( async function setComputeFees(
@ -145,21 +142,22 @@ export default function Compute({
const feeValidity = providerData?.datasets?.[0]?.providerFee?.validUntil const feeValidity = providerData?.datasets?.[0]?.providerFee?.validUntil
const feeAmount = await unitsToAmount( const feeAmount = await unitsToAmount(
!isSupportedOceanNetwork || !isAssetNetwork // !isSupportedOceanNetwork || !isAssetNetwork
? await getDummyWeb3(asset?.chainId) // ? await getDummyWeb3(asset?.chainId)
: web3, // : web3,
signer,
providerFeeToken, providerFeeToken,
providerFeeAmount providerFeeAmount
) )
setProviderFeeAmount(feeAmount) setProviderFeeAmount(feeAmount)
const datatoken = new Datatoken( const datatoken = new Datatoken(signer)
await getDummyWeb3(asset?.chainId), // const datatoken = new Datatoken(
null, // await getDummyWeb3(asset?.chainId),
null, // null,
minAbi // null,
) // minAbi
// )
setProviderFeesSymbol(await datatoken.getSymbol(providerFeeToken)) setProviderFeesSymbol(await datatoken.getSymbol(providerFeeToken))
const computeDuration = asset.accessDetails.validProviderFees const computeDuration = asset.accessDetails.validProviderFees
@ -179,6 +177,7 @@ export default function Compute({
const algorithmOrderPriceAndFees = await getOrderPriceAndFees( const algorithmOrderPriceAndFees = await getOrderPriceAndFees(
selectedAlgorithmAsset, selectedAlgorithmAsset,
ZERO_ADDRESS, ZERO_ADDRESS,
signer,
algoProviderFees algoProviderFees
) )
if (!algorithmOrderPriceAndFees) if (!algorithmOrderPriceAndFees)
@ -197,6 +196,7 @@ export default function Compute({
const datasetPriceAndFees = await getOrderPriceAndFees( const datasetPriceAndFees = await getOrderPriceAndFees(
asset, asset,
ZERO_ADDRESS, ZERO_ADDRESS,
signer,
datasetProviderFees datasetProviderFees
) )
if (!datasetPriceAndFees) if (!datasetPriceAndFees)
@ -373,11 +373,12 @@ export default function Compute({
) )
const algorithmOrderTx = await handleComputeOrder( const algorithmOrderTx = await handleComputeOrder(
web3, signer,
selectedAlgorithmAsset, selectedAlgorithmAsset,
algoOrderPriceAndFees, algoOrderPriceAndFees,
accountId, accountId,
initializedProviderResponse.algorithm, initializedProviderResponse.algorithm,
hasAlgoAssetDatatoken,
computeEnv.consumerAddress computeEnv.consumerAddress
) )
if (!algorithmOrderTx) throw new Error('Failed to order algorithm.') if (!algorithmOrderTx) throw new Error('Failed to order algorithm.')
@ -391,11 +392,12 @@ export default function Compute({
) )
const datasetOrderTx = await handleComputeOrder( const datasetOrderTx = await handleComputeOrder(
web3, signer,
asset, asset,
datasetOrderPriceAndFees, datasetOrderPriceAndFees,
accountId, accountId,
initializedProviderResponse.datasets[0], initializedProviderResponse.datasets[0],
hasDatatoken,
computeEnv.consumerAddress computeEnv.consumerAddress
) )
if (!datasetOrderTx) throw new Error('Failed to order dataset.') if (!datasetOrderTx) throw new Error('Failed to order dataset.')
@ -414,8 +416,7 @@ export default function Compute({
setComputeStatusText(getComputeFeedback()[4]) setComputeStatusText(getComputeFeedback()[4])
const response = await ProviderInstance.computeStart( const response = await ProviderInstance.computeStart(
asset.services[0].serviceEndpoint, asset.services[0].serviceEndpoint,
web3, signer,
accountId,
computeEnv?.id, computeEnv?.id,
computeAsset, computeAsset,
computeAlgorithm, computeAlgorithm,

View File

@ -2,7 +2,6 @@ import React, { ReactElement, useEffect, useState } from 'react'
import FileIcon from '@shared/FileIcon' import FileIcon from '@shared/FileIcon'
import Price from '@shared/Price' import Price from '@shared/Price'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3'
import ButtonBuy from './ButtonBuy' import ButtonBuy from './ButtonBuy'
import { secondsToString } from '@utils/ddo' import { secondsToString } from '@utils/ddo'
import AlgorithmDatasetsListForCompute from './Compute/AlgorithmDatasetsListForCompute' import AlgorithmDatasetsListForCompute from './Compute/AlgorithmDatasetsListForCompute'
@ -17,6 +16,8 @@ import { useIsMounted } from '@hooks/useIsMounted'
import { useMarketMetadata } from '@context/MarketMetadata' import { useMarketMetadata } from '@context/MarketMetadata'
import Alert from '@shared/atoms/Alert' import Alert from '@shared/atoms/Alert'
import Loader from '@shared/atoms/Loader' import Loader from '@shared/atoms/Loader'
import { useAccount, useSigner } from 'wagmi'
import useNetworkMetadata from '@hooks/useNetworkMetadata'
export default function Download({ export default function Download({
asset, asset,
@ -33,7 +34,9 @@ export default function Download({
fileIsLoading?: boolean fileIsLoading?: boolean
consumableFeedback?: string consumableFeedback?: string
}): ReactElement { }): ReactElement {
const { accountId, web3, isSupportedOceanNetwork } = useWeb3() const { address: accountId, isConnected } = useAccount()
const { data: signer } = useSigner()
const { isSupportedOceanNetwork } = useNetworkMetadata()
const { getOpcFeeForToken } = useMarketMetadata() const { getOpcFeeForToken } = useMarketMetadata()
const { isInPurgatory, isAssetNetwork } = useAsset() const { isInPurgatory, isAssetNetwork } = useAsset()
const isMounted = useIsMounted() const isMounted = useIsMounted()
@ -72,16 +75,24 @@ export default function Download({
async function init() { async function init() {
if ( if (
asset.accessDetails.addressOrId === ZERO_ADDRESS || asset.accessDetails.addressOrId === ZERO_ADDRESS ||
asset.accessDetails.type === 'free' || asset.accessDetails.type === 'free'
isLoading
) )
return return
!orderPriceAndFees && setIsPriceLoading(true) try {
!orderPriceAndFees && setIsPriceLoading(true)
const _orderPriceAndFees = await getOrderPriceAndFees(asset, ZERO_ADDRESS) const _orderPriceAndFees = await getOrderPriceAndFees(
setOrderPriceAndFees(_orderPriceAndFees) asset,
!orderPriceAndFees && setIsPriceLoading(false) ZERO_ADDRESS,
signer
)
setOrderPriceAndFees(_orderPriceAndFees)
!orderPriceAndFees && setIsPriceLoading(false)
} catch (error) {
LoggerInstance.error('getOrderPriceAndFees', error)
setIsPriceLoading(false)
}
} }
init() init()
@ -92,7 +103,7 @@ export default function Download({
* Not adding isLoading and getOpcFeeForToken because we set these here. It is a compromise * Not adding isLoading and getOpcFeeForToken because we set these here. It is a compromise
*/ */
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [asset, accountId, getOpcFeeForToken, isUnsupportedPricing]) }, [asset, getOpcFeeForToken, isUnsupportedPricing])
useEffect(() => { useEffect(() => {
setHasDatatoken(Number(dtBalance) >= 1) setHasDatatoken(Number(dtBalance) >= 1)
@ -144,7 +155,7 @@ export default function Download({
)[3] )[3]
) )
await downloadFile(web3, asset, accountId, validOrderTx) await downloadFile(signer, asset, accountId, validOrderTx)
} else { } else {
setStatusText( setStatusText(
getOrderFeedback( getOrderFeedback(
@ -152,12 +163,19 @@ export default function Download({
asset.accessDetails.datatoken?.symbol asset.accessDetails.datatoken?.symbol
)[asset.accessDetails.type === 'fixed' ? 2 : 1] )[asset.accessDetails.type === 'fixed' ? 2 : 1]
) )
const orderTx = await order(web3, asset, orderPriceAndFees, accountId) const orderTx = await order(
if (!orderTx) { signer,
asset,
orderPriceAndFees,
accountId,
hasDatatoken
)
const tx = await orderTx.wait()
if (!tx) {
throw new Error() throw new Error()
} }
setIsOwned(true) setIsOwned(true)
setValidOrderTx(orderTx.transactionHash) setValidOrderTx(tx?.transactionHash)
} }
} catch (error) { } catch (error) {
LoggerInstance.error(error) LoggerInstance.error(error)
@ -190,6 +208,7 @@ export default function Download({
consumableFeedback={consumableFeedback} consumableFeedback={consumableFeedback}
retry={retry} retry={retry}
isSupportedOceanNetwork={isSupportedOceanNetwork} isSupportedOceanNetwork={isSupportedOceanNetwork}
isAccountConnected={isConnected}
/> />
) )

View File

@ -4,7 +4,6 @@ import Download from './Download'
import { FileInfo, LoggerInstance, Datatoken } from '@oceanprotocol/lib' import { FileInfo, LoggerInstance, Datatoken } from '@oceanprotocol/lib'
import { compareAsBN } from '@utils/numbers' import { compareAsBN } from '@utils/numbers'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3'
import Web3Feedback from '@shared/Web3Feedback' import Web3Feedback from '@shared/Web3Feedback'
import { getFileDidInfo, getFileInfo } from '@utils/provider' import { getFileDidInfo, getFileInfo } from '@utils/provider'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig } from '@utils/ocean'
@ -13,15 +12,20 @@ import { useIsMounted } from '@hooks/useIsMounted'
import styles from './index.module.css' import styles from './index.module.css'
import { useFormikContext } from 'formik' import { useFormikContext } from 'formik'
import { FormPublishData } from '@components/Publish/_types' import { FormPublishData } from '@components/Publish/_types'
import { getTokenBalanceFromSymbol } from '@utils/web3' import { getTokenBalanceFromSymbol } from '@utils/wallet'
import AssetStats from './AssetStats' import AssetStats from './AssetStats'
import { useAccount, useProvider, useNetwork } from 'wagmi'
import useBalance from '@hooks/useBalance'
export default function AssetActions({ export default function AssetActions({
asset asset
}: { }: {
asset: AssetExtended asset: AssetExtended
}): ReactElement { }): ReactElement {
const { accountId, balance, web3, chainId } = useWeb3() const { address: accountId } = useAccount()
const { balance } = useBalance()
const { chain } = useNetwork()
const web3Provider = useProvider()
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
const isMounted = useIsMounted() const isMounted = useIsMounted()
@ -72,7 +76,7 @@ export default function AssetActions({
query, query,
headers, headers,
abi, abi,
chainId, chain?.id,
method method
) )
: await getFileDidInfo(asset?.id, asset?.services[0]?.id, providerUrl) : await getFileDidInfo(asset?.id, asset?.services[0]?.id, providerUrl)
@ -100,11 +104,11 @@ export default function AssetActions({
// Get and set user DT balance // Get and set user DT balance
useEffect(() => { useEffect(() => {
if (!web3 || !accountId || !isAssetNetwork) return if (!web3Provider || !accountId || !isAssetNetwork) return
async function init() { async function init() {
try { try {
const datatokenInstance = new Datatoken(web3) const datatokenInstance = new Datatoken(web3Provider as any)
const dtBalance = await datatokenInstance.balance( const dtBalance = await datatokenInstance.balance(
asset.services[0].datatokenAddress, asset.services[0].datatokenAddress,
accountId accountId
@ -115,7 +119,7 @@ export default function AssetActions({
} }
} }
init() init()
}, [web3, accountId, asset, isAssetNetwork]) }, [web3Provider, accountId, asset, isAssetNetwork])
// Check user balance against price // Check user balance against price
useEffect(() => { useEffect(() => {

View File

@ -3,28 +3,35 @@ import MetaItem from './MetaItem'
import styles from './MetaFull.module.css' import styles from './MetaFull.module.css'
import Publisher from '@shared/Publisher' import Publisher from '@shared/Publisher'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { getDummyWeb3 } from '@utils/web3' import { Asset, LoggerInstance } from '@oceanprotocol/lib'
import { Asset, Datatoken, LoggerInstance } from '@oceanprotocol/lib' import { getPaymentCollector } from '@utils/ocean'
import { useProvider } from 'wagmi'
export default function MetaFull({ ddo }: { ddo: Asset }): ReactElement { export default function MetaFull({ ddo }: { ddo: Asset }): ReactElement {
const [paymentCollector, setPaymentCollector] = useState<string>()
const { isInPurgatory, assetState } = useAsset() const { isInPurgatory, assetState } = useAsset()
const provider = useProvider()
const [paymentCollector, setPaymentCollector] = useState<string>()
useEffect(() => { useEffect(() => {
if (!ddo || !provider) return
async function getInitialPaymentCollector() { async function getInitialPaymentCollector() {
try { try {
if (!ddo) return const paymentCollector = await getPaymentCollector(
const web3 = await getDummyWeb3(ddo.chainId) ddo.datatokens[0].address,
const datatoken = new Datatoken(web3) provider
setPaymentCollector(
await datatoken.getPaymentCollector(ddo.datatokens[0].address)
) )
setPaymentCollector(paymentCollector)
} catch (error) { } catch (error) {
LoggerInstance.error('[MetaFull: getInitialPaymentCollector]', error) LoggerInstance.error(
'[MetaFull: getInitialPaymentCollector]',
error.message
)
} }
} }
getInitialPaymentCollector() getInitialPaymentCollector()
}, [ddo]) }, [ddo, provider])
function DockerImage() { function DockerImage() {
const containerInfo = ddo?.metadata?.algorithm?.container const containerInfo = ddo?.metadata?.algorithm?.container

View File

@ -1,10 +1,10 @@
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useWeb3 } from '@context/Web3'
import { Asset } from '@oceanprotocol/lib' import { Asset } from '@oceanprotocol/lib'
import AddToken from '@shared/AddToken' import AddToken from '@shared/AddToken'
import ExplorerLink from '@shared/ExplorerLink' import ExplorerLink from '@shared/ExplorerLink'
import Publisher from '@shared/Publisher' import Publisher from '@shared/Publisher'
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { useAccount } from 'wagmi'
import styles from './MetaAsset.module.css' import styles from './MetaAsset.module.css'
export default function MetaAsset({ export default function MetaAsset({
@ -15,7 +15,7 @@ export default function MetaAsset({
isBlockscoutExplorer: boolean isBlockscoutExplorer: boolean
}): ReactElement { }): ReactElement {
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
const { web3ProviderInfo } = useWeb3() const { connector: activeConnector } = useAccount()
const dataTokenSymbol = asset?.datatokens[0]?.symbol const dataTokenSymbol = asset?.datatokens[0]?.symbol
@ -36,7 +36,7 @@ export default function MetaAsset({
> >
{`Accessed with ${dataTokenSymbol}`} {`Accessed with ${dataTokenSymbol}`}
</ExplorerLink> </ExplorerLink>
{web3ProviderInfo?.name === 'MetaMask' && isAssetNetwork && ( {activeConnector?.name === 'MetaMask' && isAssetNetwork && (
<span className={styles.addWrap}> <span className={styles.addWrap}>
<AddToken <AddToken
address={asset?.services[0].datatokenAddress} address={asset?.services[0].datatokenAddress}

View File

@ -5,7 +5,7 @@ import { NftMetadata } from '@utils/nft'
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import styles from './NftTooltip.module.css' import styles from './NftTooltip.module.css'
import explorerLinkStyles from '@shared/ExplorerLink/index.module.css' import explorerLinkStyles from '@shared/ExplorerLink/index.module.css'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/wallet'
// Supported OpenSea networks: // Supported OpenSea networks:
// https://support.opensea.io/hc/en-us/articles/4404027708051-Which-blockchains-does-OpenSea-support- // https://support.opensea.io/hc/en-us/articles/4404027708051-Which-blockchains-does-OpenSea-support-

View File

@ -13,12 +13,11 @@ import EditHistory from './EditHistory'
import styles from './index.module.css' import styles from './index.module.css'
import NetworkName from '@shared/NetworkName' import NetworkName from '@shared/NetworkName'
import content from '../../../../content/purgatory.json' import content from '../../../../content/purgatory.json'
import Web3 from 'web3'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import RelatedAssets from '../RelatedAssets' import RelatedAssets from '../RelatedAssets'
import DmButton from '@shared/DirectMessages/DmButton' import DmButton from '@shared/DirectMessages/DmButton'
import Web3Feedback from '@components/@shared/Web3Feedback' import Web3Feedback from '@components/@shared/Web3Feedback'
import { useWeb3 } from '@context/Web3' import { useAccount } from 'wagmi'
export default function AssetContent({ export default function AssetContent({
asset asset
@ -26,17 +25,17 @@ export default function AssetContent({
asset: AssetExtended asset: AssetExtended
}): ReactElement { }): ReactElement {
const { isInPurgatory, purgatoryData, isOwner, isAssetNetwork } = useAsset() const { isInPurgatory, purgatoryData, isOwner, isAssetNetwork } = useAsset()
const { accountId } = useWeb3() const { address: accountId } = useAccount()
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const [receipts, setReceipts] = useState([]) const [receipts, setReceipts] = useState([])
const [nftPublisher, setNftPublisher] = useState<string>() const [nftPublisher, setNftPublisher] = useState<string>()
useEffect(() => { useEffect(() => {
setNftPublisher( if (!receipts.length) return
Web3.utils.toChecksumAddress(
receipts?.find((e) => e.type === 'METADATA_CREATED')?.nft?.owner const publisher = receipts?.find((e) => e.type === 'METADATA_CREATED')?.nft
) ?.owner
) setNftPublisher(publisher)
}, [receipts]) }, [receipts])
return ( return (

View File

@ -1,4 +1,3 @@
import { useWeb3 } from '@context/Web3'
import { Formik } from 'formik' import { Formik } from 'formik'
import React, { ReactElement, useState } from 'react' import React, { ReactElement, useState } from 'react'
import FormEditComputeDataset from './FormEditComputeDataset' import FormEditComputeDataset from './FormEditComputeDataset'
@ -24,6 +23,7 @@ import { useAsset } from '@context/Asset'
import EditFeedback from './EditFeedback' import EditFeedback from './EditFeedback'
import { setNftMetadata } from '@utils/nft' import { setNftMetadata } from '@utils/nft'
import { ComputeEditForm } from './_types' import { ComputeEditForm } from './_types'
import { useAccount, useSigner } from 'wagmi'
export default function EditComputeDataset({ export default function EditComputeDataset({
asset asset
@ -31,8 +31,10 @@ export default function EditComputeDataset({
asset: AssetExtended asset: AssetExtended
}): ReactElement { }): ReactElement {
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { accountId, web3 } = useWeb3() const { address: accountId } = useAccount()
const { data: signer } = useSigner()
const { fetchAsset, isAssetNetwork } = useAsset() const { fetchAsset, isAssetNetwork } = useAsset()
const [success, setSuccess] = useState<string>() const [success, setSuccess] = useState<string>()
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
const newAbortController = useAbortController() const newAbortController = useAbortController()
@ -46,7 +48,7 @@ export default function EditComputeDataset({
asset?.accessDetails?.isPurchasable asset?.accessDetails?.isPurchasable
) { ) {
const tx = await setMinterToPublisher( const tx = await setMinterToPublisher(
web3, signer,
asset?.accessDetails?.datatoken?.address, asset?.accessDetails?.datatoken?.address,
accountId, accountId,
setError setError
@ -84,7 +86,7 @@ export default function EditComputeDataset({
const setMetadataTx = await setNftMetadata( const setMetadataTx = await setNftMetadata(
updatedAsset, updatedAsset,
accountId, accountId,
web3, signer,
newAbortController() newAbortController()
) )
@ -97,7 +99,7 @@ export default function EditComputeDataset({
} else { } else {
if (asset.accessDetails.type === 'free') { if (asset.accessDetails.type === 'free') {
const tx = await setMinterToDispenser( const tx = await setMinterToDispenser(
web3, signer,
asset?.accessDetails?.datatoken?.address, asset?.accessDetails?.datatoken?.address,
accountId, accountId,
setError setError

View File

@ -12,7 +12,6 @@ import {
import { validationSchema } from './_validation' import { validationSchema } from './_validation'
import { getInitialValues } from './_constants' import { getInitialValues } from './_constants'
import { MetadataEditForm } from './_types' import { MetadataEditForm } from './_types'
import { useWeb3 } from '@context/Web3'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import Web3Feedback from '@shared/Web3Feedback' import Web3Feedback from '@shared/Web3Feedback'
import FormEditMetadata from './FormEditMetadata' import FormEditMetadata from './FormEditMetadata'
@ -21,13 +20,14 @@ import styles from './index.module.css'
import content from '../../../../content/pages/editMetadata.json' import content from '../../../../content/pages/editMetadata.json'
import { useAbortController } from '@hooks/useAbortController' import { useAbortController } from '@hooks/useAbortController'
import DebugEditMetadata from './DebugEditMetadata' import DebugEditMetadata from './DebugEditMetadata'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig, getPaymentCollector } from '@utils/ocean'
import EditFeedback from './EditFeedback' import EditFeedback from './EditFeedback'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { setNftMetadata } from '@utils/nft' import { setNftMetadata } from '@utils/nft'
import { sanitizeUrl } from '@utils/url' import { sanitizeUrl } from '@utils/url'
import { getEncryptedFiles } from '@utils/provider' import { getEncryptedFiles } from '@utils/provider'
import { assetStateToNumber } from '@utils/assetState' import { assetStateToNumber } from '@utils/assetState'
import { useAccount, useProvider, useNetwork, useSigner } from 'wagmi'
export default function Edit({ export default function Edit({
asset asset
@ -36,8 +36,12 @@ export default function Edit({
}): ReactElement { }): ReactElement {
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { fetchAsset, isAssetNetwork, assetState } = useAsset() const { fetchAsset, isAssetNetwork, assetState } = useAsset()
const { accountId, web3, chainId } = useWeb3() const { address: accountId } = useAccount()
const { chain } = useNetwork()
const provider = useProvider()
const { data: signer } = useSigner()
const newAbortController = useAbortController() const newAbortController = useAbortController()
const [success, setSuccess] = useState<string>() const [success, setSuccess] = useState<string>()
const [paymentCollector, setPaymentCollector] = useState<string>() const [paymentCollector, setPaymentCollector] = useState<string>()
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
@ -45,12 +49,15 @@ export default function Edit({
const hasFeedback = error || success const hasFeedback = error || success
useEffect(() => { useEffect(() => {
if (!asset || !provider) return
async function getInitialPaymentCollector() { async function getInitialPaymentCollector() {
try { try {
const datatoken = new Datatoken(web3) const paymentCollector = await getPaymentCollector(
setPaymentCollector( asset.datatokens[0].address,
await datatoken.getPaymentCollector(asset?.datatokens[0].address) provider
) )
setPaymentCollector(paymentCollector)
} catch (error) { } catch (error) {
LoggerInstance.error( LoggerInstance.error(
'[EditMetadata: getInitialPaymentCollector]', '[EditMetadata: getInitialPaymentCollector]',
@ -59,18 +66,17 @@ export default function Edit({
} }
} }
getInitialPaymentCollector() getInitialPaymentCollector()
}, [asset, web3]) }, [asset, provider])
async function updateFixedPrice(newPrice: string) { async function updateFixedPrice(newPrice: string) {
const config = getOceanConfig(asset.chainId) const config = getOceanConfig(asset.chainId)
const fixedRateInstance = new FixedRateExchange( const fixedRateInstance = new FixedRateExchange(
config.fixedRateExchangeAddress, config.fixedRateExchangeAddress,
web3 signer
) )
const setPriceResp = await fixedRateInstance.setRate( const setPriceResp = await fixedRateInstance.setRate(
accountId,
asset.accessDetails.addressOrId, asset.accessDetails.addressOrId,
newPrice.toString() newPrice.toString()
) )
@ -103,7 +109,7 @@ export default function Edit({
(await updateFixedPrice(values.price)) (await updateFixedPrice(values.price))
if (values.paymentCollector !== paymentCollector) { if (values.paymentCollector !== paymentCollector) {
const datatoken = new Datatoken(web3) const datatoken = new Datatoken(signer)
await datatoken.setPaymentCollector( await datatoken.setPaymentCollector(
asset?.datatokens[0].address, asset?.datatokens[0].address,
accountId, accountId,
@ -115,7 +121,9 @@ export default function Edit({
const file = { const file = {
nftAddress: asset.nftAddress, nftAddress: asset.nftAddress,
datatokenAddress: asset.services[0].datatokenAddress, datatokenAddress: asset.services[0].datatokenAddress,
files: [normalizeFile(values.files[0].type, values.files[0], chainId)] files: [
normalizeFile(values.files[0].type, values.files[0], chain?.id)
]
} }
const filesEncrypted = await getEncryptedFiles( const filesEncrypted = await getEncryptedFiles(
@ -146,12 +154,12 @@ export default function Edit({
const setMetadataTx = await setNftMetadata( const setMetadataTx = await setNftMetadata(
updatedAsset, updatedAsset,
accountId, accountId,
web3, signer,
newAbortController() newAbortController()
) )
if (values.assetState !== assetState) { if (values.assetState !== assetState) {
const nft = new Nft(web3) const nft = new Nft(signer)
await nft.setMetadataState( await nft.setMetadataState(
asset?.nftAddress, asset?.nftAddress,

View File

@ -1,6 +1,6 @@
import { FileInfo } from '@oceanprotocol/lib' import { FileInfo } from '@oceanprotocol/lib'
import * as Yup from 'yup' import * as Yup from 'yup'
import web3 from 'web3' import { isAddress } from 'ethers/lib/utils'
import { testLinks } from '../../../@utils/yup' import { testLinks } from '../../../@utils/yup'
export const validationSchema = Yup.object().shape({ export const validationSchema = Yup.object().shape({
@ -41,7 +41,7 @@ export const validationSchema = Yup.object().shape({
'ValidAddress', 'ValidAddress',
'Must be a valid Ethereum Address.', 'Must be a valid Ethereum Address.',
(value) => { (value) => {
return web3.utils.isAddress(value) return isAddress(value)
} }
), ),
retireAsset: Yup.string() retireAsset: Yup.string()

View File

@ -1,30 +1,38 @@
import React, { FormEvent } from 'react' import React, { FormEvent } from 'react'
import Caret from '@images/caret.svg' import Caret from '@images/caret.svg'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/wallet'
import Loader from '@shared/atoms/Loader' // import Loader from '@shared/atoms/Loader'
import styles from './Account.module.css' import styles from './Account.module.css'
import { useWeb3 } from '@context/Web3'
import Avatar from '@shared/atoms/Avatar' import Avatar from '@shared/atoms/Avatar'
import { useAccount, useEnsName, useEnsAvatar } from 'wagmi'
import { useModal } from 'connectkit'
// Forward ref for Tippy.js // Forward ref for Tippy.js
// eslint-disable-next-line // eslint-disable-next-line
const Account = React.forwardRef((props, ref: any) => { const Account = React.forwardRef((props, ref: any) => {
const { accountId, accountEns, accountEnsAvatar, web3Modal, connect } = const { address: accountId } = useAccount()
useWeb3() const { data: accountEns } = useEnsName({ address: accountId, chainId: 1 })
const { data: accountEnsAvatar } = useEnsAvatar({
address: accountId,
chainId: 1
})
const { setOpen } = useModal()
async function handleActivation(e: FormEvent<HTMLButtonElement>) { async function handleActivation(e: FormEvent<HTMLButtonElement>) {
// prevent accidentially submitting a form the button might be in // prevent accidentially submitting a form the button might be in
e.preventDefault() e.preventDefault()
await connect() setOpen(true)
} }
return !accountId && web3Modal?.cachedProvider ? ( // return
// Improve user experience for cached provider when connecting takes some time // !accountId && provider ? (
<button className={styles.button} onClick={(e) => e.preventDefault()}> // // Improve user experience for cached provider when connecting takes some time
<Loader /> // <button className={styles.button} onClick={(e) => e.preventDefault()}>
</button> // <Loader />
) : accountId ? ( // </button>
// ) :
return accountId ? (
<button <button
className={styles.button} className={styles.button}
aria-label="Account" aria-label="Account"

View File

@ -4,24 +4,24 @@ import { useUserPreferences } from '@context/UserPreferences'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import AddToken from '@shared/AddToken' import AddToken from '@shared/AddToken'
import Conversion from '@shared/Price/Conversion' import Conversion from '@shared/Price/Conversion'
import { useWeb3 } from '@context/Web3'
import { useOrbis } from '@context/DirectMessages' import { useOrbis } from '@context/DirectMessages'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig } from '@utils/ocean'
import { useNetwork, useDisconnect, useAccount, useConnect } from 'wagmi'
import { useModal } from 'connectkit'
import styles from './Details.module.css' import styles from './Details.module.css'
import useBalance from '@hooks/useBalance'
import useNetworkMetadata from '@hooks/useNetworkMetadata'
export default function Details(): ReactElement { export default function Details(): ReactElement {
const { const { chain } = useNetwork()
accountId, const { connector: activeConnector, address: accountId } = useAccount()
web3ProviderInfo, const { connect } = useConnect()
web3Modal, const { setOpen } = useModal()
connect, const { disconnect } = useDisconnect()
logout, const { balance } = useBalance()
networkData, const { networkData } = useNetworkMetadata()
networkId,
balance
} = useWeb3()
const { checkOrbisConnection, disconnectOrbis } = useOrbis()
const { locale } = useUserPreferences() const { locale } = useUserPreferences()
const { checkOrbisConnection, disconnectOrbis } = useOrbis()
const [mainCurrency, setMainCurrency] = useState<string>() const [mainCurrency, setMainCurrency] = useState<string>()
const [oceanTokenMetadata, setOceanTokenMetadata] = useState<{ const [oceanTokenMetadata, setOceanTokenMetadata] = useState<{
@ -30,19 +30,19 @@ export default function Details(): ReactElement {
}>() }>()
useEffect(() => { useEffect(() => {
if (!networkId) return if (!chain?.id) return
const symbol = networkData?.nativeCurrency.symbol const symbol = networkData?.nativeCurrency.symbol
setMainCurrency(symbol) setMainCurrency(symbol)
const oceanConfig = getOceanConfig(networkId) const oceanConfig = getOceanConfig(chain.id)
oceanConfig && oceanConfig &&
setOceanTokenMetadata({ setOceanTokenMetadata({
address: oceanConfig.oceanTokenAddress, address: oceanConfig.oceanTokenAddress,
symbol: oceanConfig.oceanTokenSymbol symbol: oceanConfig.oceanTokenSymbol
}) })
}, [networkData, networkId]) }, [networkData, chain?.id])
return ( return (
<div className={styles.details}> <div className={styles.details}>
@ -68,10 +68,10 @@ export default function Details(): ReactElement {
<li className={styles.actions}> <li className={styles.actions}>
<div title="Connected provider" className={styles.walletInfo}> <div title="Connected provider" className={styles.walletInfo}>
<span className={styles.walletLogoWrap}> <span className={styles.walletLogoWrap}>
<img className={styles.walletLogo} src={web3ProviderInfo?.logo} /> {/* <img className={styles.walletLogo} src={activeConnector?.logo} /> */}
{web3ProviderInfo?.name} {activeConnector?.name}
</span> </span>
{web3ProviderInfo?.name === 'MetaMask' && ( {activeConnector?.name === 'MetaMask' && (
<AddToken <AddToken
address={oceanTokenMetadata?.address} address={oceanTokenMetadata?.address}
symbol={oceanTokenMetadata?.symbol} symbol={oceanTokenMetadata?.symbol}
@ -84,7 +84,6 @@ export default function Details(): ReactElement {
style="text" style="text"
size="small" size="small"
onClick={async () => { onClick={async () => {
await web3Modal?.clearCachedProvider()
connect() connect()
checkOrbisConnection({ address: accountId }) checkOrbisConnection({ address: accountId })
}} }}
@ -95,7 +94,7 @@ export default function Details(): ReactElement {
style="text" style="text"
size="small" size="small"
onClick={() => { onClick={() => {
logout() disconnect()
disconnectOrbis(accountId) disconnectOrbis(accountId)
location.reload() location.reload()
}} }}

View File

@ -2,21 +2,23 @@ import React, { ReactElement } from 'react'
import Status from '@shared/atoms/Status' import Status from '@shared/atoms/Status'
import Badge from '@shared/atoms/Badge' import Badge from '@shared/atoms/Badge'
import Tooltip from '@shared/atoms/Tooltip' import Tooltip from '@shared/atoms/Tooltip'
import { useWeb3 } from '@context/Web3'
import NetworkName from '@shared/NetworkName' import NetworkName from '@shared/NetworkName'
import styles from './Network.module.css' import styles from './Network.module.css'
import { useNetwork } from 'wagmi'
import useNetworkMetadata from '@hooks/useNetworkMetadata'
export default function Network(): ReactElement { export default function Network(): ReactElement {
const { networkId, isTestnet, isSupportedOceanNetwork } = useWeb3() const { chain } = useNetwork()
const { isTestnet, isSupportedOceanNetwork } = useNetworkMetadata()
return networkId ? ( return chain?.id ? (
<div className={styles.network}> <div className={styles.network}>
{!isSupportedOceanNetwork && ( {!isSupportedOceanNetwork && (
<Tooltip content="No Ocean Protocol contracts are deployed to this network."> <Tooltip content="No Ocean Protocol contracts are deployed to this network.">
<Status state="error" className={styles.warning} /> <Status state="error" className={styles.warning} />
</Tooltip> </Tooltip>
)} )}
<NetworkName className={styles.name} networkId={networkId} minimal /> <NetworkName className={styles.name} networkId={chain.id} minimal />
{isTestnet && <Badge label="Test" className={styles.badge} />} {isTestnet && <Badge label="Test" className={styles.badge} />}
</div> </div>
) : null ) : null

View File

@ -4,10 +4,10 @@ import Details from './Details'
import Tooltip from '@shared/atoms/Tooltip' import Tooltip from '@shared/atoms/Tooltip'
import Network from './Network' import Network from './Network'
import styles from './index.module.css' import styles from './index.module.css'
import { useWeb3 } from '@context/Web3' import { useAccount } from 'wagmi'
export default function Wallet(): ReactElement { export default function Wallet(): ReactElement {
const { accountId } = useWeb3() const { address: accountId } = useAccount()
return ( return (
<div className={styles.wallet}> <div className={styles.wallet}>

View File

@ -1,5 +1,4 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import { useWeb3 } from '@context/Web3'
import { AssetWithOwnAllocation, getOwnAllocations } from '@utils/veAllocation' import { AssetWithOwnAllocation, getOwnAllocations } from '@utils/veAllocation'
import styles from './index.module.css' import styles from './index.module.css'
import { import {
@ -12,9 +11,10 @@ import { useCancelToken } from '@hooks/useCancelToken'
import { useIsMounted } from '@hooks/useIsMounted' import { useIsMounted } from '@hooks/useIsMounted'
import { LoggerInstance } from '@oceanprotocol/lib' import { LoggerInstance } from '@oceanprotocol/lib'
import AssetListTable from './AssetListTable' import AssetListTable from './AssetListTable'
import { useAccount } from 'wagmi'
export default function Allocations(): ReactElement { export default function Allocations(): ReactElement {
const { accountId } = useWeb3() const { address: accountId } = useAccount()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const isMounted = useIsMounted() const isMounted = useIsMounted()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()

View File

@ -7,8 +7,8 @@ import Tooltip from '@shared/atoms/Tooltip'
import AssetTitle from '@shared/AssetListTitle' import AssetTitle from '@shared/AssetListTitle'
import { getAssetsFromDids } from '@utils/aquarius' import { getAssetsFromDids } from '@utils/aquarius'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { useWeb3 } from '@context/Web3'
import { useMarketMetadata } from '@context/MarketMetadata' import { useMarketMetadata } from '@context/MarketMetadata'
import { useAccount } from 'wagmi'
const columns: TableOceanColumn<AssetExtended>[] = [ const columns: TableOceanColumn<AssetExtended>[] = [
{ {
@ -38,7 +38,7 @@ const columns: TableOceanColumn<AssetExtended>[] = [
export default function Bookmarks(): ReactElement { export default function Bookmarks(): ReactElement {
const { appConfig } = useMarketMetadata() const { appConfig } = useMarketMetadata()
const { accountId } = useWeb3() const { address: accountId } = useAccount()
const { bookmarks } = useUserPreferences() const { bookmarks } = useUserPreferences()
const [pinned, setPinned] = useState<AssetExtended[]>() const [pinned, setPinned] = useState<AssetExtended[]>()

View File

@ -2,7 +2,7 @@ import React, { ReactElement, useEffect, useState } from 'react'
import Dotdotdot from 'react-dotdotdot' import Dotdotdot from 'react-dotdotdot'
import Link from 'next/link' import Link from 'next/link'
import styles from './index.module.css' import styles from './index.module.css'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/wallet'
import Avatar from '../../../@shared/atoms/Avatar' import Avatar from '../../../@shared/atoms/Avatar'
import { getEnsProfile } from '@utils/ens' import { getEnsProfile } from '@utils/ens'
import { UserSales } from '@utils/aquarius' import { UserSales } from '@utils/aquarius'

View File

@ -7,7 +7,7 @@ import Copy from '@shared/atoms/Copy'
import Avatar from '@shared/atoms/Avatar' import Avatar from '@shared/atoms/Avatar'
import styles from './Account.module.css' import styles from './Account.module.css'
import { useProfile } from '@context/Profile' import { useProfile } from '@context/Profile'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/wallet'
export default function Account({ export default function Account({
accountId accountId

View File

@ -8,14 +8,14 @@ import { useProfile } from '@context/Profile'
import { getLocked } from '@utils/veAllocation' import { getLocked } from '@utils/veAllocation'
import PriceUnit from '@shared/Price/PriceUnit' import PriceUnit from '@shared/Price/PriceUnit'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import { useWeb3 } from '@context/Web3' import { useAccount } from 'wagmi'
export default function Stats({ export default function Stats({
accountId accountId
}: { }: {
accountId: string accountId: string
}): ReactElement { }): ReactElement {
const web3 = useWeb3() const { address } = useAccount()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const { assets, assetsTotal, sales } = useProfile() const { assets, assetsTotal, sales } = useProfile()
@ -73,7 +73,7 @@ export default function Stats({
<NumberUnit label="Published" value={assetsTotal} /> <NumberUnit label="Published" value={assetsTotal} />
<NumberUnit <NumberUnit
label={ label={
lockedOcean === 0 && accountId === web3.accountId ? ( lockedOcean === 0 && accountId === address ? (
<Button <Button
className={styles.link} className={styles.link}
style="text" style="text"

View File

@ -10,9 +10,9 @@ import Button from '@shared/atoms/Button'
import styles from './Results.module.css' import styles from './Results.module.css'
import FormHelp from '@shared/FormInput/Help' import FormHelp from '@shared/FormInput/Help'
import content from '../../../../../content/pages/history.json' import content from '../../../../../content/pages/history.json'
import { useWeb3 } from '@context/Web3'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { getAsset } from '@utils/aquarius' import { getAsset } from '@utils/aquarius'
import { useAccount, useSigner } from 'wagmi'
export default function Results({ export default function Results({
job job
@ -20,12 +20,14 @@ export default function Results({
job: ComputeJobMetaData job: ComputeJobMetaData
}): ReactElement { }): ReactElement {
const providerInstance = new Provider() const providerInstance = new Provider()
const { accountId, web3 } = useWeb3() const { address: accountId } = useAccount()
const isFinished = job.dateFinished !== null const { data: signer } = useSigner()
const [datasetProvider, setDatasetProvider] = useState<string>() const [datasetProvider, setDatasetProvider] = useState<string>()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
const isFinished = job.dateFinished !== null
useEffect(() => { useEffect(() => {
async function getAssetMetadata() { async function getAssetMetadata() {
const ddo = await getAsset(job.inputDID[0], newCancelToken()) const ddo = await getAsset(job.inputDID[0], newCancelToken())
@ -62,8 +64,7 @@ export default function Results({
try { try {
const jobResult = await providerInstance.getComputeResultUrl( const jobResult = await providerInstance.getComputeResultUrl(
datasetProvider, datasetProvider,
web3, signer,
accountId,
job.jobId, job.jobId,
resultIndex resultIndex
) )

View File

@ -2,13 +2,13 @@ import React, { ReactElement, useState } from 'react'
import Time from '@shared/atoms/Time' import Time from '@shared/atoms/Time'
import Table, { TableOceanColumn } from '@shared/atoms/Table' import Table, { TableOceanColumn } from '@shared/atoms/Table'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import { useWeb3 } from '@context/Web3'
import Details from './Details' import Details from './Details'
import Refresh from '@images/refresh.svg' import Refresh from '@images/refresh.svg'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import NetworkName from '@shared/NetworkName' import NetworkName from '@shared/NetworkName'
import styles from './index.module.css' import styles from './index.module.css'
import AssetListTitle from '@shared/AssetListTitle' import AssetListTitle from '@shared/AssetListTitle'
import { useAccount } from 'wagmi'
export function Status({ children }: { children: string }): ReactElement { export function Status({ children }: { children: string }): ReactElement {
return <div className={styles.status}>{children}</div> return <div className={styles.status}>{children}</div>
@ -55,7 +55,7 @@ export default function ComputeJobs({
isLoading?: boolean isLoading?: boolean
refetchJobs?: any refetchJobs?: any
}): ReactElement { }): ReactElement {
const { accountId } = useWeb3() const { address: accountId } = useAccount()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const [columnsMinimal] = useState([columns[4], columns[5], columns[3]]) const [columnsMinimal] = useState([columns[4], columns[5], columns[3]])
@ -84,6 +84,6 @@ export default function ComputeJobs({
/> />
</> </>
) : ( ) : (
<div>Please connect your Web3 wallet.</div> <div>Please connect your wallet.</div>
) )
} }

View File

@ -42,6 +42,6 @@ export default function ComputeDownloads({
emptyMessage={chainIds.length === 0 ? 'No network selected' : null} emptyMessage={chainIds.length === 0 ? 'No network selected' : null}
/> />
) : ( ) : (
<div>Please connect your Web3 wallet.</div> <div>Please connect your wallet.</div>
) )
} }

View File

@ -97,6 +97,6 @@ export default function PublishedList({
/> />
</> </>
) : ( ) : (
<div>Please connect your Web3 wallet.</div> <div>Please connect your wallet.</div>
) )
} }

View File

@ -4,11 +4,11 @@ import PublishedList from './PublishedList'
import Downloads from './Downloads' import Downloads from './Downloads'
import ComputeJobs from './ComputeJobs' import ComputeJobs from './ComputeJobs'
import styles from './index.module.css' import styles from './index.module.css'
import { useWeb3 } from '@context/Web3'
import { getComputeJobs } from '@utils/compute' import { getComputeJobs } from '@utils/compute'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { LoggerInstance } from '@oceanprotocol/lib' import { LoggerInstance } from '@oceanprotocol/lib'
import { useAccount } from 'wagmi'
interface HistoryTab { interface HistoryTab {
title: string title: string
@ -56,7 +56,7 @@ export default function HistoryPage({
}: { }: {
accountIdentifier: string accountIdentifier: string
}): ReactElement { }): ReactElement {
const { accountId } = useWeb3() const { address: accountId } = useAccount()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()

View File

@ -5,12 +5,12 @@ import { FormikContextType, useFormikContext } from 'formik'
import { FormPublishData } from '../_types' import { FormPublishData } from '../_types'
import { wizardSteps } from '../_constants' import { wizardSteps } from '../_constants'
import SuccessConfetti from '@shared/SuccessConfetti' import SuccessConfetti from '@shared/SuccessConfetti'
import { useWeb3 } from '@context/Web3'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Tooltip from '@shared/atoms/Tooltip' import Tooltip from '@shared/atoms/Tooltip'
import AvailableNetworks from '@components/Publish/AvailableNetworks' import AvailableNetworks from '@components/Publish/AvailableNetworks'
import Info from '@images/info.svg' import Info from '@images/info.svg'
import Loader from '@shared/atoms/Loader' import Loader from '@shared/atoms/Loader'
import useNetworkMetadata from '@hooks/useNetworkMetadata'
export default function Actions({ export default function Actions({
scrollToRef, scrollToRef,
@ -20,21 +20,19 @@ export default function Actions({
did: string did: string
}): ReactElement { }): ReactElement {
const router = useRouter() const router = useRouter()
const { isSupportedOceanNetwork } = useWeb3() const { isSupportedOceanNetwork } = useNetworkMetadata()
const { const {
values, values,
errors, errors,
isValid, isValid,
isSubmitting isSubmitting
}: FormikContextType<FormPublishData> = useFormikContext() }: FormikContextType<FormPublishData> = useFormikContext()
const { connect, accountId } = useWeb3() // async function handleActivation(e: FormEvent<HTMLButtonElement>) {
// // prevent accidentially submitting a form the button might be in
// e.preventDefault()
async function handleActivation(e: FormEvent<HTMLButtonElement>) { // await connect()
// prevent accidentially submitting a form the button might be in // }
e.preventDefault()
await connect()
}
function handleAction(action: string) { function handleAction(action: string) {
const currentStep: string = router.query.step as string const currentStep: string = router.query.step as string
@ -92,11 +90,12 @@ export default function Actions({
> >
Continue Continue
</Button> </Button>
) : !accountId ? ( ) : // !address ? (
<Button type="submit" style="primary" onClick={handleActivation}> // <Button type="submit" style="primary" onClick={handleActivation}>
Connect Wallet // Connect Wallet
</Button> // </Button>
) : !isSupportedOceanNetwork ? ( // ) :
!isSupportedOceanNetwork ? (
<Tooltip content={<AvailableNetworks />}> <Tooltip content={<AvailableNetworks />}>
<Button <Button
type="submit" type="submit"

View File

@ -3,8 +3,7 @@ import NetworkName from '@shared/NetworkName'
import styles from './Network.module.css' import styles from './Network.module.css'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import useNetworkMetadata from '@hooks/useNetworkMetadata' import useNetworkMetadata from '@hooks/useNetworkMetadata'
import { addCustomNetwork } from '@utils/web3' // TODO: import { addCustomNetwork } from '@utils/wallet'
import { useWeb3 } from '@context/Web3'
export default function Network({ export default function Network({
chainId chainId
@ -12,11 +11,10 @@ export default function Network({
chainId: number chainId: number
}): ReactElement { }): ReactElement {
const { networksList } = useNetworkMetadata() const { networksList } = useNetworkMetadata()
const { web3Provider } = useWeb3()
function changeNetwork(chainId: number) { function changeNetwork(chainId: number) {
const networkNode = networksList.find((data) => data.chainId === chainId) const networkNode = networksList.find((data) => data.chainId === chainId)
addCustomNetwork(web3Provider, networkNode) // addCustomNetwork(networkNode)
} }
return ( return (

View File

@ -6,18 +6,18 @@ import { transformPublishFormToDdo } from '../_utils'
import styles from './index.module.css' import styles from './index.module.css'
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import { previewDebugPatch } from '@utils/ddo' import { previewDebugPatch } from '@utils/ddo'
import { useWeb3 } from '@context/Web3' import { useNetwork } from 'wagmi'
export default function Debug(): ReactElement { export default function Debug(): ReactElement {
const { values } = useFormikContext<FormPublishData>() const { values } = useFormikContext<FormPublishData>()
const [valuePreview, setValuePreview] = useState({}) const [valuePreview, setValuePreview] = useState({})
const [ddo, setDdo] = useState<DDO>() const [ddo, setDdo] = useState<DDO>()
const { chainId } = useWeb3() const { chain } = useNetwork()
useEffect(() => { useEffect(() => {
async function makeDdo() { async function makeDdo() {
const ddo = await transformPublishFormToDdo(values) const ddo = await transformPublishFormToDdo(values)
setValuePreview(previewDebugPatch(values, chainId)) setValuePreview(previewDebugPatch(values, chain?.id))
setDdo(ddo) setDdo(ddo)
} }
makeDdo() makeDdo()

View File

@ -4,9 +4,9 @@ import styles from './Fees.module.css'
import Input from '@shared/FormInput' import Input from '@shared/FormInput'
import { getOpcFees } from '@utils/subgraph' import { getOpcFees } from '@utils/subgraph'
import { OpcFeesQuery_opc as OpcFeesData } from '../../../@types/subgraph/OpcFeesQuery' import { OpcFeesQuery_opc as OpcFeesData } from '../../../@types/subgraph/OpcFeesQuery'
import { useWeb3 } from '@context/Web3'
import { useMarketMetadata } from '@context/MarketMetadata' import { useMarketMetadata } from '@context/MarketMetadata'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import { useNetwork } from 'wagmi'
const Default = ({ const Default = ({
title, title,
@ -40,18 +40,18 @@ export default function Fees({
tooltips: { [key: string]: string } tooltips: { [key: string]: string }
}): ReactElement { }): ReactElement {
const [oceanCommunitySwapFee, setOceanCommunitySwapFee] = useState<string>('') const [oceanCommunitySwapFee, setOceanCommunitySwapFee] = useState<string>('')
const { chainId } = useWeb3() const { chain } = useNetwork()
const { appConfig } = useMarketMetadata() const { appConfig } = useMarketMetadata()
useEffect(() => { useEffect(() => {
getOpcFees(chainId || 1).then((response: OpcFeesData) => { getOpcFees(chain?.id || 1).then((response: OpcFeesData) => {
setOceanCommunitySwapFee( setOceanCommunitySwapFee(
response?.swapOceanFee response?.swapOceanFee
? new Decimal(response.swapOceanFee).mul(100).toString() ? new Decimal(response.swapOceanFee).mul(100).toString()
: '0' : '0'
) )
}) })
}, [chainId]) }, [chain?.id])
return ( return (
<> <>

View File

@ -7,11 +7,13 @@ import Free from './Free'
import content from '../../../../content/price.json' import content from '../../../../content/price.json'
import styles from './index.module.css' import styles from './index.module.css'
import { useMarketMetadata } from '@context/MarketMetadata' import { useMarketMetadata } from '@context/MarketMetadata'
import { useWeb3 } from '@context/Web3' import { useNetwork } from 'wagmi'
export default function PricingFields(): ReactElement { export default function PricingFields(): ReactElement {
const { appConfig } = useMarketMetadata() const { appConfig } = useMarketMetadata()
const { approvedBaseTokens, chainId } = useWeb3() const { chain } = useNetwork()
const { approvedBaseTokens } = useMarketMetadata()
// Connect with main publish form // Connect with main publish form
const { values, setFieldValue } = useFormikContext<FormPublishData>() const { values, setFieldValue } = useFormikContext<FormPublishData>()
const { pricing } = values const { pricing } = values
@ -22,6 +24,23 @@ export default function PricingFields(): ReactElement {
token.name.toLowerCase().includes('ocean') token.name.toLowerCase().includes('ocean')
) || approvedBaseTokens?.[0] ) || approvedBaseTokens?.[0]
const isBaseTokenSet = !!approvedBaseTokens?.find(
(token) => token?.address === values?.pricing?.baseToken?.address
)
useEffect(() => {
if (!approvedBaseTokens?.length) return
if (isBaseTokenSet) return
setFieldValue('pricing.baseToken', defaultBaseToken)
}, [
approvedBaseTokens,
chain?.id,
defaultBaseToken,
isBaseTokenSet,
setFieldValue,
values.pricing.baseToken
])
// Switch type value upon tab change // Switch type value upon tab change
function handleTabChange(tabName: string) { function handleTabChange(tabName: string) {
const type = tabName.toLowerCase() const type = tabName.toLowerCase()

View File

@ -1,28 +1,31 @@
import { ReactElement, useEffect } from 'react' import { ReactElement, useEffect } from 'react'
import { useFormikContext } from 'formik' import { useFormikContext } from 'formik'
import { wizardSteps, initialPublishFeedback } from './_constants' import { wizardSteps, initialPublishFeedback } from './_constants'
import { useWeb3 } from '@context/Web3'
import { FormPublishData, PublishFeedback } from './_types' import { FormPublishData, PublishFeedback } from './_types'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig } from '@utils/ocean'
import { useAccount, useNetwork } from 'wagmi'
import { useMarketMetadata } from '@context/MarketMetadata'
export function Steps({ export function Steps({
feedback feedback
}: { }: {
feedback: PublishFeedback feedback: PublishFeedback
}): ReactElement { }): ReactElement {
const { chainId, accountId, approvedBaseTokens } = useWeb3() const { address: accountId } = useAccount()
const { chain } = useNetwork()
const { approvedBaseTokens } = useMarketMetadata()
const { values, setFieldValue, touched, setTouched } = const { values, setFieldValue, touched, setTouched } =
useFormikContext<FormPublishData>() useFormikContext<FormPublishData>()
const isCustomProviderUrl = values?.services?.[0]?.providerUrl.custom const isCustomProviderUrl = values?.services?.[0]?.providerUrl.custom
// auto-sync user chainId & account into form data values // auto-sync user chain?.id & account into form data values
useEffect(() => { useEffect(() => {
if (!chainId || !accountId) return if (!chain?.id || !accountId) return
setFieldValue('user.chainId', chainId) setFieldValue('user.chainId', chain?.id)
setFieldValue('user.accountId', accountId) setFieldValue('user.accountId', accountId)
}, [chainId, accountId, setFieldValue]) }, [chain?.id, accountId, setFieldValue])
useEffect(() => { useEffect(() => {
if (!approvedBaseTokens?.length) return if (!approvedBaseTokens?.length) return
@ -37,7 +40,7 @@ export function Steps({
if (isBaseTokenSet) return if (isBaseTokenSet) return
setFieldValue('pricing.baseToken', defaultBaseToken) setFieldValue('pricing.baseToken', defaultBaseToken)
}, [approvedBaseTokens]) }, [approvedBaseTokens, values?.pricing?.baseToken?.address])
// auto-sync publish feedback into form data values // auto-sync publish feedback into form data values
useEffect(() => { useEffect(() => {

View File

@ -3,16 +3,19 @@ import NetworkName from '@shared/NetworkName'
import Tooltip from '@shared/atoms/Tooltip' import Tooltip from '@shared/atoms/Tooltip'
import styles from './index.module.css' import styles from './index.module.css'
import content from '../../../../content/publish/index.json' import content from '../../../../content/publish/index.json'
import { useWeb3 } from '@context/Web3'
import Info from '@images/info.svg' import Info from '@images/info.svg'
import AvailableNetworks from '@components/Publish/AvailableNetworks' import AvailableNetworks from '@components/Publish/AvailableNetworks'
import useNetworkMetadata from '@hooks/useNetworkMetadata'
import { useAccount } from 'wagmi'
export default function Title({ export default function Title({
networkId networkId
}: { }: {
networkId: number networkId: number
}): ReactElement { }): ReactElement {
const { isSupportedOceanNetwork, accountId } = useWeb3() const { address: accountId } = useAccount()
const { isSupportedOceanNetwork } = useNetworkMetadata()
return ( return (
<> <>
{content.title}{' '} {content.title}{' '}

View File

@ -11,13 +11,13 @@ import {
NftCreateData, NftCreateData,
NftFactory, NftFactory,
Service, Service,
ZERO_ADDRESS ZERO_ADDRESS,
getEventFromTx
} from '@oceanprotocol/lib' } from '@oceanprotocol/lib'
import { mapTimeoutStringToSeconds, normalizeFile } from '@utils/ddo' import { mapTimeoutStringToSeconds, normalizeFile } from '@utils/ddo'
import { generateNftCreateData } from '@utils/nft' import { generateNftCreateData } from '@utils/nft'
import { getEncryptedFiles } from '@utils/provider' import { getEncryptedFiles } from '@utils/provider'
import slugify from 'slugify' import slugify from 'slugify'
import Web3 from 'web3'
import { algorithmContainerPresets } from './_constants' import { algorithmContainerPresets } from './_constants'
import { FormPublishData, MetadataAlgorithmContainer } from './_types' import { FormPublishData, MetadataAlgorithmContainer } from './_types'
import { import {
@ -28,6 +28,7 @@ import {
} from '../../../app.config' } from '../../../app.config'
import { sanitizeUrl } from '@utils/url' import { sanitizeUrl } from '@utils/url'
import { getContainerChecksum } from '@utils/docker' import { getContainerChecksum } from '@utils/docker'
import { parseEther } from 'ethers/lib/utils'
function getUrlFileExtension(fileUrl: string): string { function getUrlFileExtension(fileUrl: string): string {
const splittedFileUrl = fileUrl.split('.') const splittedFileUrl = fileUrl.split('.')
@ -193,8 +194,7 @@ export async function createTokensAndPricing(
values: FormPublishData, values: FormPublishData,
accountId: string, accountId: string,
config: Config, config: Config,
nftFactory: NftFactory, nftFactory: NftFactory
web3: Web3
) { ) {
const nftCreateData: NftCreateData = generateNftCreateData( const nftCreateData: NftCreateData = generateNftCreateData(
values.metadata.nft, values.metadata.nft,
@ -241,15 +241,18 @@ export async function createTokensAndPricing(
) )
const result = await nftFactory.createNftWithDatatokenWithFixedRate( const result = await nftFactory.createNftWithDatatokenWithFixedRate(
accountId,
nftCreateData, nftCreateData,
ercParams, ercParams,
freParams freParams
) )
erc721Address = result.events.NFTCreated.returnValues[0] const trxReceipt = await result.wait()
datatokenAddress = result.events.TokenCreated.returnValues[0] const nftCreatedEvent = getEventFromTx(trxReceipt, 'NFTCreated')
txHash = result.transactionHash const tokenCreatedEvent = getEventFromTx(trxReceipt, 'TokenCreated')
erc721Address = nftCreatedEvent.args.newTokenAddress
datatokenAddress = tokenCreatedEvent.args.newTokenAddress
txHash = trxReceipt.transactionHash
LoggerInstance.log('[publish] createNftErcWithFixedRate tx', txHash) LoggerInstance.log('[publish] createNftErcWithFixedRate tx', txHash)
@ -261,8 +264,8 @@ export async function createTokensAndPricing(
// both will be just 1 for the market // both will be just 1 for the market
const dispenserParams: DispenserCreationParams = { const dispenserParams: DispenserCreationParams = {
dispenserAddress: config.dispenserAddress, dispenserAddress: config.dispenserAddress,
maxTokens: web3.utils.toWei('1'), maxTokens: parseEther('1').toString(),
maxBalance: web3.utils.toWei('1'), maxBalance: parseEther('1').toString(),
withMint: true, withMint: true,
allowedSwapper: ZERO_ADDRESS allowedSwapper: ZERO_ADDRESS
} }
@ -273,14 +276,17 @@ export async function createTokensAndPricing(
) )
const result = await nftFactory.createNftWithDatatokenWithDispenser( const result = await nftFactory.createNftWithDatatokenWithDispenser(
accountId,
nftCreateData, nftCreateData,
ercParams, ercParams,
dispenserParams dispenserParams
) )
erc721Address = result.events.NFTCreated.returnValues[0] const trxReceipt = await result.wait()
datatokenAddress = result.events.TokenCreated.returnValues[0] const nftCreatedEvent = getEventFromTx(trxReceipt, 'NFTCreated')
txHash = result.transactionHash const tokenCreatedEvent = getEventFromTx(trxReceipt, 'TokenCreated')
erc721Address = nftCreatedEvent.args.newTokenAddress
datatokenAddress = tokenCreatedEvent.args.newTokenAddress
txHash = trxReceipt.transactionHash
LoggerInstance.log('[publish] createNftErcWithDispenser tx', txHash) LoggerInstance.log('[publish] createNftErcWithDispenser tx', txHash)

View File

@ -2,7 +2,6 @@ import React, { ReactElement, useState, useRef } from 'react'
import { Form, Formik } from 'formik' import { Form, Formik } from 'formik'
import { initialPublishFeedback, initialValues } from './_constants' import { initialPublishFeedback, initialValues } from './_constants'
import { useAccountPurgatory } from '@hooks/useAccountPurgatory' import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
import { useWeb3 } from '@context/Web3'
import { createTokensAndPricing, transformPublishFormToDdo } from './_utils' import { createTokensAndPricing, transformPublishFormToDdo } from './_utils'
import PageHeader from '@shared/Page/PageHeader' import PageHeader from '@shared/Page/PageHeader'
import Title from './Title' import Title from './Title'
@ -19,6 +18,7 @@ import { getOceanConfig } from '@utils/ocean'
import { validationSchema } from './_validation' import { validationSchema } from './_validation'
import { useAbortController } from '@hooks/useAbortController' import { useAbortController } from '@hooks/useAbortController'
import { setNFTMetadataAndTokenURI } from '@utils/nft' import { setNFTMetadataAndTokenURI } from '@utils/nft'
import { useAccount, useNetwork, useSigner } from 'wagmi'
export default function PublishPage({ export default function PublishPage({
content content
@ -26,7 +26,9 @@ export default function PublishPage({
content: { title: string; description: string; warning: string } content: { title: string; description: string; warning: string }
}): ReactElement { }): ReactElement {
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { accountId, web3, chainId } = useWeb3() const { address: accountId } = useAccount()
const { data: signer } = useSigner()
const { chain } = useNetwork()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId) const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
const scrollToRef = useRef() const scrollToRef = useRef()
const nftFactory = useNftFactory() const nftFactory = useNftFactory()
@ -60,17 +62,11 @@ export default function PublishPage({
})) }))
try { try {
const config = getOceanConfig(chainId) const config = getOceanConfig(chain?.id)
LoggerInstance.log('[publish] using config: ', config) LoggerInstance.log('[publish] using config: ', config)
const { erc721Address, datatokenAddress, txHash } = const { erc721Address, datatokenAddress, txHash } =
await createTokensAndPricing( await createTokensAndPricing(values, accountId, config, nftFactory)
values,
accountId,
config,
nftFactory,
web3
)
const isSuccess = Boolean(erc721Address && datatokenAddress && txHash) const isSuccess = Boolean(erc721Address && datatokenAddress && txHash)
if (!isSuccess) throw new Error('No Token created. Please try again.') if (!isSuccess) throw new Error('No Token created. Please try again.')
@ -197,23 +193,24 @@ export default function PublishPage({
const res = await setNFTMetadataAndTokenURI( const res = await setNFTMetadataAndTokenURI(
ddo, ddo,
accountId, accountId,
web3, signer,
values.metadata.nft, values.metadata.nft,
newAbortController() newAbortController()
) )
if (!res?.transactionHash) const tx = await res.wait()
if (!tx?.transactionHash)
throw new Error( throw new Error(
'Metadata could not be written into the NFT. Please try again.' 'Metadata could not be written into the NFT. Please try again.'
) )
LoggerInstance.log('[publish] setMetadata result', res) LoggerInstance.log('[publish] setMetadata result', tx)
setFeedback((prevState) => ({ setFeedback((prevState) => ({
...prevState, ...prevState,
'3': { '3': {
...prevState['3'], ...prevState['3'],
status: res ? 'success' : 'error', status: tx ? 'success' : 'error',
txHash: res?.transactionHash txHash: tx?.transactionHash
} }
})) }))

View File

@ -1,18 +1,19 @@
// import App from "next/app"; // import App from "next/app";
import React, { ReactElement, useEffect } from 'react' import React, { ReactElement, useEffect } from 'react'
import type { AppProps /*, AppContext */ } from 'next/app' import type { AppProps /*, AppContext */ } from 'next/app'
import Web3Provider from '@context/Web3'
import { UserPreferencesProvider } from '@context/UserPreferences' import { UserPreferencesProvider } from '@context/UserPreferences'
import PricesProvider from '@context/Prices' import PricesProvider from '@context/Prices'
import UrqlProvider from '@context/UrqlProvider' import UrqlProvider from '@context/UrqlProvider'
import ConsentProvider from '@context/CookieConsent' import ConsentProvider from '@context/CookieConsent'
import App from '../../src/components/App'
import { OrbisProvider } from '@context/DirectMessages' import { OrbisProvider } from '@context/DirectMessages'
import App from 'src/components/App'
import '@oceanprotocol/typographies/css/ocean-typo.css' import '@oceanprotocol/typographies/css/ocean-typo.css'
import '../stylesGlobal/styles.css' import '../stylesGlobal/styles.css'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import MarketMetadataProvider from '@context/MarketMetadata' import MarketMetadataProvider from '@context/MarketMetadata'
import { WagmiConfig } from 'wagmi'
import { ConnectKitProvider } from 'connectkit'
import { connectKitTheme, wagmiClient } from '@utils/wallet'
import posthog from 'posthog-js' import posthog from 'posthog-js'
import { PostHogProvider } from 'posthog-js/react' import { PostHogProvider } from 'posthog-js/react'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
@ -40,25 +41,32 @@ function MyApp({ Component, pageProps }: AppProps): ReactElement {
}, [router.events]) }, [router.events])
return ( return (
<MarketMetadataProvider> <>
<Web3Provider> <WagmiConfig client={wagmiClient}>
<UrqlProvider> <ConnectKitProvider
<UserPreferencesProvider> options={{ initialChainId: 0 }}
<PricesProvider> customTheme={connectKitTheme}
<ConsentProvider> >
<OrbisProvider> <MarketMetadataProvider>
<PostHogProvider client={posthog}> <UrqlProvider>
<App> <UserPreferencesProvider>
<Component {...pageProps} /> <PricesProvider>
</App> <ConsentProvider>
</PostHogProvider> <OrbisProvider>
</OrbisProvider> <PostHogProvider client={posthog}>
</ConsentProvider> <App>
</PricesProvider> <Component {...pageProps} />
</UserPreferencesProvider> </App>
</UrqlProvider> </PostHogProvider>
</Web3Provider> </OrbisProvider>
</MarketMetadataProvider> </ConsentProvider>
</PricesProvider>
</UserPreferencesProvider>
</UrqlProvider>
</MarketMetadataProvider>
</ConnectKitProvider>
</WagmiConfig>
</>
) )
} }

View File

@ -1,19 +1,21 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import Page from '@shared/Page' import Page from '@shared/Page'
import ProfilePage from '../../components/Profile' import ProfilePage from '../../components/Profile'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/wallet'
import { useWeb3 } from '@context/Web3'
import ProfileProvider from '@context/Profile' import ProfileProvider from '@context/Profile'
import { getEnsAddress, getEnsName } from '@utils/ens' import { getEnsAddress, getEnsName } from '@utils/ens'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import web3 from 'web3' import { useAccount, useEnsName } from 'wagmi'
import { isAddress } from 'ethers/lib/utils'
export default function PageProfile(): ReactElement { export default function PageProfile(): ReactElement {
const router = useRouter() const router = useRouter()
const { accountId, accountEns } = useWeb3() const { address: accountId } = useAccount()
const { data: accountEns } = useEnsName({ address: accountId })
const [finalAccountId, setFinalAccountId] = useState<string>() const [finalAccountId, setFinalAccountId] = useState<string>()
const [finalAccountEns, setFinalAccountEns] = useState<string>() const [finalAccountEns, setFinalAccountEns] = useState<string>()
const [ownAccount, setOwnAccount] = useState(false) const [ownAccount, setOwnAccount] = useState(false)
// Have accountId in path take over, if not present fall back to web3 // Have accountId in path take over, if not present fall back to web3
useEffect(() => { useEffect(() => {
async function init() { async function init() {
@ -30,7 +32,7 @@ export default function PageProfile(): ReactElement {
const pathAccount = router.query.account as string const pathAccount = router.query.account as string
// Path has ETH address // Path has ETH address
if (web3.utils.isAddress(pathAccount)) { if (isAddress(pathAccount)) {
setOwnAccount(pathAccount === accountId) setOwnAccount(pathAccount === accountId)
const finalAccountId = pathAccount || accountId const finalAccountId = pathAccount || accountId
setFinalAccountId(finalAccountId) setFinalAccountId(finalAccountId)

View File

@ -1,10 +1,10 @@
import React, { ReactElement, useState } from 'react' import React, { ReactElement, useState } from 'react'
import Search from '../components/Search' import Search from '../components/Search'
import Page from '@shared/Page' import Page from '@shared/Page'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/wallet'
import { MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS } from '@utils/aquarius' import { MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS } from '@utils/aquarius'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import web3 from 'web3' import { isAddress } from 'ethers/lib/utils'
export default function PageSearch(): ReactElement { export default function PageSearch(): ReactElement {
const router = useRouter() const router = useRouter()
@ -13,7 +13,7 @@ export default function PageSearch(): ReactElement {
const [totalResults, setTotalResults] = useState<number>() const [totalResults, setTotalResults] = useState<number>()
const [totalPagesNumber, setTotalPagesNumber] = useState<number>() const [totalPagesNumber, setTotalPagesNumber] = useState<number>()
const isETHAddress = web3.utils.isAddress(text as string) const isETHAddress = isAddress(text as string)
const searchValue = const searchValue =
(isETHAddress ? accountTruncate(text as string) : text) || (isETHAddress ? accountTruncate(text as string) : text) ||
tags || tags ||

View File

@ -1,151 +0,0 @@
div.web3modal-modal-lightbox,
div.walletconnect-qrcode__base {
background: var(--background-body-transparent);
backdrop-filter: blur(3px);
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
animation: fadeIn 0.2s ease-out backwards;
}
div.web3modal-modal-card {
border-radius: var(--border-radius);
padding: var(--spacer);
margin: var(--spacer) auto;
max-width: 100%;
border: 1px solid var(--border-color);
box-shadow: 0 6px 15px 0 var(--box-shadow-color);
animation: moveUp 0.2s ease-out backwards;
grid-template-columns: 1fr;
}
div.web3modal-provider-wrapper {
border: 0;
border-bottom: 1px solid var(--border-color);
padding: 0;
}
div.web3modal-provider-wrapper:last-child {
border-bottom: 0;
}
div.web3modal-provider-container {
border-radius: 0;
padding: var(--spacer);
}
@media (min-width: 40rem) {
div.web3modal-modal-card {
grid-template-columns: 1fr 1fr;
max-width: var(--break-point--small);
}
div.web3modal-provider-wrapper {
border-bottom: 0;
}
div.web3modal-provider-wrapper:nth-child(1),
div.web3modal-provider-wrapper:nth-child(2) {
border-bottom: 1px solid var(--border-color);
}
div.web3modal-provider-wrapper:nth-child(2n + 1) {
border-right: 1px solid var(--border-color);
}
}
div.web3modal-provider-icon {
filter: grayscale(1) contrast(150%);
transition: filter 0.2s ease-out;
}
div.web3modal-provider-wrapper:hover div.web3modal-provider-icon {
filter: none;
}
div.web3modal-provider-name {
font-size: var(--font-size-large);
font-weight: var(--font-weight-bold);
font-family: var(--font-family-heading);
}
div.web3modal-provider-description {
font-size: var(--font-size-base);
margin-top: 0;
}
div.walletconnect-modal__base {
background: var(--background-body);
border-radius: var(--border-radius);
border: 1px solid var(--border-color);
box-shadow: 0 6px 17px 0 var(--box-shadow-color);
}
div.walletconnect-modal__mobile__toggle {
width: 95%;
text-transform: uppercase;
cursor: pointer;
background: var(--background-body);
border: 1px solid var(--border-color);
}
div.walletconnect-modal__mobile__toggle a {
color: var(--color-secondary);
font-weight: var(--font-weight-bold);
font-size: var(--font-size-small);
padding: calc(var(--spacer) / 12) var(--spacer);
white-space: nowrap;
}
div.walletconnect-modal__mobile__toggle_selector {
background: var(--font-color-heading);
color: var(--background-body);
border-color: var(--font-color-heading);
height: calc(100% - calc(var(--spacer) / 12));
top: calc(var(--spacer) / 24);
}
div.walletconnect-modal__header p {
color: var(--font-color-heading);
}
p.walletconnect-qrcode__text {
color: var(--color-secondary);
}
h3.walletconnect-modal__base__row__h3 {
font-size: var(--font-size-base);
color: var(--font-color-text);
}
svg.walletconnect-qrcode__image path:first-child {
fill: var(--background-body);
}
svg.walletconnect-qrcode__image path:last-child {
stroke: var(--font-color-heading);
}
#torusIframe {
z-index: 3;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes moveUp {
from {
transform: translate3d(0, 1rem, 0);
}
to {
transform: translate3d(0, 0, 0);
}
}

View File

@ -162,7 +162,6 @@ table th {
@import '_code.css'; @import '_code.css';
@import '_toast.css'; @import '_toast.css';
@import '_web3modal.css';
@import '_emojipicker.css'; @import '_emojipicker.css';
/* prevent background scrolling */ /* prevent background scrolling */