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

Merge branch 'main' into odc_demo

This commit is contained in:
mihaisc 2023-06-19 13:04:53 +03:00
commit da9a355632
90 changed files with 12290 additions and 5223 deletions

View File

@ -1,4 +1,5 @@
#NEXT_PUBLIC_INFURA_PROJECT_ID="xxx"
#NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID="xxx"
#NEXT_PUBLIC_MARKET_FEE_ADDRESS="0xxx"
#NEXT_PUBLIC_PUBLISHER_MARKET_ORDER_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 userPreferences from '../__fixtures__/userPreferences'
import web3 from '../__fixtures__/web3'
import { network } from '../__fixtures__/wagni'
import { asset } from '../__fixtures__/datasetWithAccessDetails'
jest.mock('../../src/@context/MarketMetadata', () => ({
@ -11,10 +11,13 @@ jest.mock('../../src/@context/UserPreferences', () => ({
useUserPreferences: () => userPreferences
}))
jest.mock('../../src/@context/Web3', () => ({
useWeb3: () => web3
}))
jest.mock('../../../@context/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 './__mocks__/matchMedia'
import './__mocks__/hooksMocks'
import './__mocks__/connectkit'
jest.mock('next/router', () => ({
useRouter: jest.fn().mockImplementation(() => ({

View File

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

View File

@ -238,12 +238,12 @@ function Component() {
For account purgatory:
```tsx
import { useWeb3 } from '@context/Web3'
import { useAccount } from 'wagmi'
import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
function Component() {
const { accountId } = useWeb3()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
const { address } = useAccount()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(address)
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).
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
export default function NetworkName(): ReactElement {
const { networkId, isTestnet } = useWeb3()
const { networksList } = useNetworkMetadata()
const networkData = getNetworkDataById(networksList, networkId)
const networkName = getNetworkDisplayName(networkData)
const { isTestnet } = useNetworkMetadata()
const { networkData, networkName } = useNetworkMetadata()
return (
<>

View File

@ -11,12 +11,10 @@ module.exports = {
// List of chainIds which metadata cache queries will return by default.
// This preselects the Chains user preferences.
chainIds: [1, 137, 56, 246, 1285],
chainIds: [1, 137],
// List of all supported chainIds. Used to populate the Chains user preferences list.
chainIdsSupported: [1, 137, 56, 246, 1285, 5, 80001],
infuraProjectId: process.env.NEXT_PUBLIC_INFURA_PROJECT_ID || 'xxx',
chainIdsSupported: [1, 137, 5, 80001],
defaultDatatokenTemplateIndex: 2,
// The ETH address the marketplace fee will be sent to.

View File

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

15473
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",
"@loadable/component": "^5.15.2",
"@oceanprotocol/art": "^3.2.0",
"@oceanprotocol/lib": "^2.7.0",
"@oceanprotocol/lib": "^3.0.1",
"@oceanprotocol/typographies": "^0.1.0",
"@oceanprotocol/use-dark-mode": "^2.4.3",
"@orbisclub/orbis-sdk": "^0.4.40",
"@tippyjs/react": "^4.2.6",
"@uiw/react-codemirror": "^4.19.5",
"@urql/exchange-refocus": "^1.0.0",
"@walletconnect/web3-provider": "^1.8.0",
"axios": "^1.2.0",
"classnames": "^2.3.2",
"connectkit": "^1.2.3",
"date-fns": "^2.29.3",
"decimal.js": "^10.4.2",
"dom-confetti": "^0.2.2",
"dotenv": "^16.0.3",
"ethers": "^5.7.2",
"filesize": "^10.0.7",
"formik": "^2.2.9",
"gray-matter": "^4.0.3",
@ -52,7 +52,8 @@
"match-sorter": "^6.3.1",
"myetherwallet-blockies": "^0.1.1",
"next": "13.0.5",
"posthog-js": "^1.51.4",
"npm": "^9.6.5",
"posthog-js": "^1.63.1",
"query-string": "^8.1.0",
"react": "^18.2.0",
"react-clipboard.js": "^2.0.16",
@ -62,10 +63,10 @@
"react-modal": "^3.16.1",
"react-paginate": "^8.1.4",
"react-select": "^5.7.0",
"react-spring": "^9.5.5",
"react-spring": "^9.7.1",
"react-string-replace": "^1.1.0",
"react-tabs": "^6.0.0",
"react-toastify": "^9.1.1",
"react-toastify": "^9.1.2",
"remark": "^14.0.2",
"remark-gfm": "^3.0.1",
"remark-html": "^15.0.1",
@ -73,8 +74,7 @@
"slugify": "^1.6.5",
"swr": "^1.3.0",
"urql": "^3.0.3",
"web3": "^1.8.1",
"web3modal": "^1.9.12",
"wagmi": "^0.12.12",
"yup": "^0.32.11"
},
"devDependencies": {
@ -90,7 +90,7 @@
"@types/loadable__component": "^5.13.4",
"@types/node": "^18.14.2",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.10",
"@types/react-dom": "^18.2.1",
"@types/react-modal": "^3.13.1",
"@types/react-paginate": "^7.1.1",
"@types/remove-markdown": "^0.3.1",
@ -99,9 +99,9 @@
"@uiw/codemirror-themes": "^4.19.1",
"apollo": "^2.34.0",
"cross-env": "^7.0.3",
"eslint": "^8.35.0",
"eslint": "^8.41.0",
"eslint-config-oceanprotocol": "^2.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-jest-dom": "^4.0.3",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",

View File

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

View File

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

View File

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

View File

@ -13,8 +13,13 @@ import { opcQuery } from './_queries'
import { MarketMetadataProviderValue, OpcFee } from './_types'
import siteContent from '../../../content/site.json'
import appConfig from '../../../app.config'
import { fetchData, getQueryContext } from '@utils/subgraph'
import {
fetchData,
getQueryContext,
getOpcsApprovedTokens
} from '@utils/subgraph'
import { LoggerInstance } from '@oceanprotocol/lib'
import { useNetwork, useConnect } from 'wagmi'
const MarketMetadataContext = createContext({} as MarketMetadataProviderValue)
@ -23,7 +28,11 @@ function MarketMetadataProvider({
}: {
children: ReactNode
}): ReactElement {
const { isLoading } = useConnect()
const { chain } = useNetwork()
const [opcFees, setOpcFees] = useState<OpcFee[]>()
const [approvedBaseTokens, setApprovedBaseTokens] = useState<TokenInfo[]>()
useEffect(() => {
async function getOpcData() {
@ -64,6 +73,28 @@ function MarketMetadataProvider({
},
[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 (
<MarketMetadataContext.Provider
value={
@ -71,7 +102,8 @@ function MarketMetadataProvider({
opcFees,
siteContent,
appConfig,
getOpcFeeForToken
getOpcFeeForToken,
approvedBaseTokens
} as MarketMetadataProviderValue
}
>

View File

@ -16,9 +16,9 @@ import {
getUserSales
} from '@utils/aquarius'
import axios, { CancelToken } from 'axios'
import web3 from 'web3'
import { useMarketMetadata } from '../MarketMetadata'
import { getEnsProfile } from '@utils/ens'
import { isAddress } from 'ethers/lib/utils'
interface ProfileProviderValue {
profile: Profile
@ -64,7 +64,7 @@ function ProfileProvider({
// when accountId is no ETH address
//
useEffect(() => {
const isEthAddress = web3.utils.isAddress(accountId)
const isEthAddress = isAddress(accountId)
setIsEthAddress(isEthAddress)
}, [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 { useWeb3 } from '@context/Web3'
import { Config, LoggerInstance } from '@oceanprotocol/lib'
import Web3 from 'web3'
import axios, { AxiosResponse } from 'axios'
import { getOceanConfig } from '@utils/ocean'
import { useBlockNumber } from 'wagmi'
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 =
'{"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) {
const response: any = await fetchGraph(
`${subgraphUri}/subgraphs/name/oceanprotocol/ocean-subgraph`,
@ -55,11 +36,10 @@ async function getBlockSubgraph(subgraphUri: string) {
}
export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus {
const { block, web3Loading } = useWeb3()
const { data: blockHead, isLoading } = useBlockNumber()
const [blockGraph, setBlockGraph] = useState<number>()
const [blockHead, setBlockHead] = useState<number>()
const [isGraphSynced, setIsGraphSynced] = useState(true)
const [subgraphLoading, setSubgraphLoading] = useState(false)
const [isSubgraphLoading, setIsSubgraphLoading] = useState(false)
const [oceanConfig, setOceanConfig] = useState<Config>()
// Grab ocean config based on passed networkId
@ -70,27 +50,21 @@ export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus {
setOceanConfig(oceanConfig)
}, [networkId])
// Get and set head block
// Log head block
useEffect(() => {
if (!oceanConfig?.nodeUri || web3Loading) return
async function initBlockHead() {
const blockHead = block || (await getBlockHead(oceanConfig))
setBlockHead(blockHead)
LoggerInstance.log('[GraphStatus] Head block: ', blockHead)
}
initBlockHead()
}, [web3Loading, block, oceanConfig])
if (!blockHead) return
LoggerInstance.log('[GraphStatus] Head block: ', blockHead)
}, [blockHead])
// Get and set subgraph block
useEffect(() => {
if (!oceanConfig?.subgraphUri) return
async function initBlockSubgraph() {
setSubgraphLoading(true)
setIsSubgraphLoading(true)
const blockGraph = await getBlockSubgraph(oceanConfig.subgraphUri)
setBlockGraph(blockGraph)
setSubgraphLoading(false)
setIsSubgraphLoading(false)
LoggerInstance.log(
'[GraphStatus] Latest block from subgraph: ',
blockGraph
@ -101,7 +75,7 @@ export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus {
// Set sync status
useEffect(() => {
if ((!blockGraph && !blockHead) || web3Loading || subgraphLoading) return
if ((!blockGraph && !blockHead) || isLoading || isSubgraphLoading) return
const difference = blockHead - blockGraph
@ -110,7 +84,7 @@ export function useGraphSyncStatus(networkId: number): UseGraphSyncStatus {
return
}
setIsGraphSynced(true)
}, [blockGraph, blockHead, web3Loading, subgraphLoading])
}, [blockGraph, blockHead, isLoading, isSubgraphLoading])
return { blockHead, blockGraph, isGraphSynced }
}

View File

@ -1,9 +1,57 @@
import { UseNetworkMetadata } from './types'
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 {
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
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'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,35 +1,38 @@
import { FixedRateExchange, PriceAndFees } from '@oceanprotocol/lib'
import { consumeMarketFixedSwapFee } from '../../app.config'
import Web3 from 'web3'
import { getOceanConfig } from './ocean'
import { getDummyWeb3 } from './web3'
import {
amountToUnits,
FixedRateExchange,
PriceAndFees,
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'
import { getDummySigner } from '@utils/wallet'
/**
* 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(
accessDetails: AccessDetails,
chainId?: number,
web3?: Web3
signer?: Signer
): 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 fixed = new FixedRateExchange(config.fixedRateExchangeAddress, web3)
if (!signer && !chainId)
throw new Error("web3 and chainId can't be undefined at the same time!")
if (!signer) {
signer = await getDummySigner(chainId)
}
const fixed = new FixedRateExchange(config.fixedRateExchangeAddress, signer)
const estimatedPrice = await fixed.calcBaseInGivenDatatokensOut(
accessDetails.addressOrId,
'1',
consumeMarketFixedSwapFee
)
return estimatedPrice
}

View File

@ -1,5 +1,7 @@
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 {
const config = new ConfigHelper().getConfig(
@ -28,3 +30,18 @@ export function getDevelopmentConfig(): Config {
subgraphUri: 'https://v4.subgraph.goerli.oceanprotocol.com'
} 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,
ProviderInitialize
} from '@oceanprotocol/lib'
import Web3 from 'web3'
import { Signer, ethers } from 'ethers'
import { getOceanConfig } from './ocean'
import { TransactionReceipt } from 'web3-eth'
import {
marketFeeAddress,
consumeMarketOrderFee,
@ -44,23 +43,24 @@ async function initializeProvider(
}
/**
* @param web3
* @param signer
* @param asset
* @param orderPriceAndFees
* @param accountId
* @param providerFees
* @param computeConsumerAddress
* @returns {TransactionReceipt} receipt of the order
* @returns {ethers.providers.TransactionResponse | BigNumber} receipt of the order
*/
export async function order(
web3: Web3,
signer: Signer,
asset: AssetExtended,
orderPriceAndFees: OrderPriceAndFees,
accountId: string,
hasDatatoken: boolean,
providerFees?: ProviderFees,
computeConsumerAddress?: string
): Promise<TransactionReceipt> {
const datatoken = new Datatoken(web3)
): Promise<ethers.providers.TransactionResponse> {
const datatoken = new Datatoken(signer)
const config = getOceanConfig(asset.chainId)
const initializeData = await initializeProvider(
@ -97,36 +97,38 @@ export async function order(
} as FreOrderParams
if (asset.accessDetails.templateId === 1) {
// buy datatoken
const txApprove = await approve(
web3,
config,
accountId,
asset.accessDetails.baseToken.address,
config.fixedRateExchangeAddress,
await amountToUnits(
web3,
asset?.accessDetails?.baseToken?.address,
orderPriceAndFees.price
),
false
)
if (!txApprove) {
return
if (!hasDatatoken) {
// buy datatoken
const txApprove = await approve(
signer,
config,
accountId,
asset.accessDetails.baseToken.address,
config.fixedRateExchangeAddress,
await amountToUnits(
signer,
asset?.accessDetails?.baseToken?.address,
orderPriceAndFees.price
),
false
)
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(
asset.accessDetails.datatoken.address,
accountId,
orderParams.consumer,
orderParams.serviceIndex,
orderParams._providerFee,
@ -135,13 +137,13 @@ export async function order(
}
if (asset.accessDetails.templateId === 2) {
const txApprove = await approve(
web3,
signer,
config,
accountId,
asset.accessDetails.baseToken.address,
asset.accessDetails.datatoken.address,
await amountToUnits(
web3,
signer,
asset?.accessDetails?.baseToken?.address,
orderPriceAndFees.price
),
@ -152,7 +154,6 @@ export async function order(
}
return await datatoken.buyFromFreAndOrder(
asset.accessDetails.datatoken.address,
accountId,
orderParams,
freParams
)
@ -161,16 +162,14 @@ export async function order(
}
case 'free': {
if (asset.accessDetails.templateId === 1) {
const dispenser = new Dispenser(config.dispenserAddress, web3)
const dispenser = new Dispenser(config.dispenserAddress, signer)
const dispenserTx = await dispenser.dispense(
asset.accessDetails?.datatoken.address,
accountId,
'1',
accountId
)
return await datatoken.startOrder(
asset.accessDetails.datatoken.address,
accountId,
orderParams.consumer,
orderParams.serviceIndex,
orderParams._providerFee,
@ -180,7 +179,6 @@ export async function order(
if (asset.accessDetails.templateId === 2) {
return await datatoken.buyFromDispenserAndOrder(
asset.services[0].datatokenAddress,
accountId,
orderParams,
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
* @param web3
* @param signer
* @param asset
* @param accountId
* @param validOrderTx
@ -199,13 +197,13 @@ export async function order(
* @returns {TransactionReceipt} receipt of the order
*/
export async function reuseOrder(
web3: Web3,
signer: Signer,
asset: AssetExtended,
accountId: string,
validOrderTx: string,
providerFees?: ProviderFees
): Promise<TransactionReceipt> {
const datatoken = new Datatoken(web3)
): Promise<ethers.providers.TransactionResponse> {
const datatoken = new Datatoken(signer)
const initializeData = await initializeProvider(
asset,
accountId,
@ -214,7 +212,6 @@ export async function reuseOrder(
const tx = await datatoken.reuseOrder(
asset.accessDetails.datatoken.address,
accountId,
validOrderTx,
providerFees || initializeData.providerFee
)
@ -225,16 +222,16 @@ export async function reuseOrder(
async function approveProviderFee(
asset: AssetExtended,
accountId: string,
web3: Web3,
signer: Signer,
providerFeeAmount: string
): Promise<TransactionReceipt> {
): Promise<ethers.providers.TransactionResponse> {
const config = getOceanConfig(asset.chainId)
const baseToken =
asset?.accessDetails?.type === 'free'
? getOceanConfig(asset.chainId).oceanTokenAddress
: asset?.accessDetails?.baseToken?.address
const txApproveWei = await approveWei(
web3,
signer,
config,
accountId,
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 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
* @param web3
* @param signer
* @param asset
* @param orderPriceAndFees
* @param accountId
@ -259,11 +256,12 @@ async function approveProviderFee(
* @returns {Promise<string>} tx id
*/
export async function handleComputeOrder(
web3: Web3,
signer: Signer,
asset: AssetExtended,
orderPriceAndFees: OrderPriceAndFees,
accountId: string,
initializeData: ProviderComputeInitialize,
hasDatatoken,
computeConsumerAddress?: string
): Promise<string> {
LoggerInstance.log(
@ -288,7 +286,7 @@ export async function handleComputeOrder(
const txApproveProvider = await approveProviderFee(
asset,
accountId,
web3,
signer,
initializeData.providerFee.providerFeeAmount
)
@ -301,30 +299,33 @@ export async function handleComputeOrder(
if (initializeData?.validOrder) {
LoggerInstance.log('[compute] Calling reuseOrder ...', initializeData)
const txReuseOrder = await reuseOrder(
web3,
signer,
asset,
accountId,
initializeData.validOrder,
initializeData.providerFee
)
if (!txReuseOrder) throw new Error('Failed to reuse order!')
LoggerInstance.log('[compute] Reused order:', txReuseOrder)
return txReuseOrder?.transactionHash
const tx = await txReuseOrder.wait()
LoggerInstance.log('[compute] Reused order:', tx)
return tx?.transactionHash
}
LoggerInstance.log('[compute] Calling order ...', initializeData)
const txStartOrder = await order(
web3,
signer,
asset,
orderPriceAndFees,
accountId,
hasDatatoken,
initializeData.providerFee,
computeConsumerAddress
)
LoggerInstance.log('[compute] Order succeeded', txStartOrder)
return txStartOrder?.transactionHash
const tx = await txStartOrder.wait()
LoggerInstance.log('[compute] Order succeeded', tx)
return tx?.transactionHash
} catch (error) {
toast.error(error.message)
LoggerInstance.error(`[compute] ${error.message}`)

View File

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

View File

@ -1,8 +1,53 @@
import { getNetworkDisplayName } from '@hooks/useNetworkMetadata'
import { LoggerInstance } from '@oceanprotocol/lib'
import Web3 from 'web3'
import { getOceanConfig } from './ocean'
import { AbiItem } from 'web3-utils/types'
import { createClient, erc20ABI } from 'wagmi'
import { mainnet, polygon, bsc, goerli, polygonMumbai } from 'wagmi/chains'
import { ethers, Contract, Signer, providers } from 'ethers'
import { formatEther } from 'ethers/lib/utils'
import { getDefaultClient } from 'connectkit'
import { getNetworkDisplayName } from '@hooks/useNetworkMetadata'
import { getOceanConfig } from '../ocean'
export async function getDummySigner(chainId: number): Promise<Signer> {
if (typeof chainId !== 'number') {
throw new Error('Chain ID must be a number')
}
// Get config from ocean lib
const config = getOceanConfig(chainId)
try {
const privateKey =
'0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
const provider = new ethers.providers.JsonRpcProvider(config.nodeUri)
return new ethers.Wallet(privateKey, provider)
} catch (error) {
throw new Error(`Failed to create dummy signer: ${error.message}`)
}
}
// 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, 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 {
if (!account || account === '') return
@ -10,14 +55,41 @@ export function accountTruncate(account: string): string {
const truncated = account.replace(middle, '…')
return truncated
}
/**
* returns a dummy web3 instance, only usable to get info from the chain
* @param chainId
* @returns Web3 instance
*/
export async function getDummyWeb3(chainId: number): Promise<Web3> {
const config = getOceanConfig(chainId)
return new Web3(config.nodeUri)
export async function addTokenToWallet(
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 }
}
;(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(
@ -75,78 +147,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(
accountId: string,
decimals: number,
tokenAddress: string,
web3: Web3
web3Provider: ethers.providers.Provider
): Promise<string> {
const minABI = [
{
constant: true,
inputs: [
{
name: '_owner',
type: 'address'
}
],
name: 'balanceOf',
outputs: [
{
name: 'balance',
type: 'uint256'
}
],
payable: false,
stateMutability: 'view',
type: 'function'
}
] as AbiItem[]
if (!web3Provider || !accountId || !tokenAddress) return
try {
const token = new web3.eth.Contract(minABI, tokenAddress, {
from: accountId
})
const balance = await token.methods.balanceOf(accountId).call()
const token = new Contract(tokenAddress, erc20ABI, web3Provider)
const balance = await token.balanceOf(accountId)
const adjustedDecimalsBalance = `${balance}${'0'.repeat(18 - decimals)}`
return web3.utils.fromWei(adjustedDecimalsBalance)
return formatEther(adjustedDecimalsBalance)
} catch (e) {
LoggerInstance.error(`ERROR: Failed to get the balance: ${e.message}`)
}
@ -157,6 +170,7 @@ export function getTokenBalanceFromSymbol(
symbol: string
): string {
if (!symbol) return
const baseTokenBalance = balance?.[symbol.toLocaleLowerCase()]
return baseTokenBalance || '0'
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,12 +8,12 @@ import Button from '@shared/atoms/Button'
import { LoggerInstance, ProviderInstance } from '@oceanprotocol/lib'
import { FormPublishData } from '@components/Publish/_types'
import { getOceanConfig } from '@utils/ocean'
import { useWeb3 } from '@context/Web3'
import axios from 'axios'
import { useCancelToken } from '@hooks/useCancelToken'
import { useNetwork } from 'wagmi'
export default function CustomProvider(props: InputProps): ReactElement {
const { chainId } = useWeb3()
const { chain } = useNetwork()
const newCancelToken = useCancelToken()
const { initialValues, setFieldError } = useFormikContext<FormPublishData>()
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, {
cancelToken: newCancelToken()
})
const userChainId = chainId || 1
const userChainId = chain?.id || 1
const providerChain =
providerResponse?.data?.chainId || providerResponse?.data?.chainIds
@ -71,7 +71,7 @@ export default function CustomProvider(props: InputProps): ReactElement {
function handleDefault(e: React.SyntheticEvent) {
e.preventDefault()
const oceanConfig = getOceanConfig(chainId)
const oceanConfig = getOceanConfig(chain?.id)
const providerUrl =
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 isUrl from 'is-url-superb'
import { isCID } from '@utils/ipfs'
import web3 from 'web3'
export interface URLInputProps {
submitText: string
handleButtonClick(e: React.SyntheticEvent, data: string): void

View File

@ -15,18 +15,6 @@ describe('@shared/NetworkName', () => {
render(<NetworkName networkId={137} />)
})
it('renders BSC', () => {
render(<NetworkName networkId={56} />)
})
it('renders Energy Web', () => {
render(<NetworkName networkId={246} />)
})
it('renders Moonriver', () => {
render(<NetworkName networkId={1285} />)
})
it('renders icon fallback', () => {
render(<NetworkName networkId={99999} />)
})

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,8 @@ const downloadProps: ButtonBuyProps = {
priceType: 'fixed',
isConsumable: true,
isBalanceSufficient: true,
consumableFeedback: 'TEST: consumableFeedback'
consumableFeedback: 'TEST: consumableFeedback',
isAccountConnected: true
}
const computeProps: ButtonBuyProps = {
@ -114,7 +115,7 @@ describe('Asset/AssetActions/ButtonBuy', () => {
render(<ButtonBuy {...computeProps} />)
expect(
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()
})
@ -123,7 +124,7 @@ describe('Asset/AssetActions/ButtonBuy', () => {
render(<ButtonBuy {...computeProps} priceType="free" />)
expect(
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()
})
@ -132,7 +133,7 @@ describe('Asset/AssetActions/ButtonBuy', () => {
render(<ButtonBuy {...computeProps} algorithmPriceType="fixed" />)
expect(
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()
})

View File

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

View File

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

View File

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

View File

@ -20,7 +20,6 @@ import { toast } from 'react-toastify'
import Price from '@shared/Price'
import FileIcon from '@shared/FileIcon'
import Alert from '@shared/atoms/Alert'
import { useWeb3 } from '@context/Web3'
import { Formik } from 'formik'
import { getInitialValues, validationSchema } from './_constants'
import FormStartComputeDataset from './FormComputeDataset'
@ -44,12 +43,15 @@ import { useAbortController } from '@hooks/useAbortController'
import { getOrderPriceAndFees } from '@utils/accessDetailsAndPricing'
import { handleComputeOrder } from '@utils/order'
import { getComputeFeedback } from '@utils/feedback'
import { getDummyWeb3 } from '@utils/web3'
import { initializeProviderForCompute } from '@utils/provider'
import { useUserPreferences } from '@context/UserPreferences'
import { useAccount, useSigner } from 'wagmi'
import { getDummySigner } from '@utils/wallet'
import useNetworkMetadata from '@hooks/useNetworkMetadata'
import { useAsset } from '@context/Asset'
const refreshInterval = 10000 // 10 sec.
export default function Compute({
asset,
dtBalance,
@ -63,9 +65,9 @@ export default function Compute({
fileIsLoading?: boolean
consumableFeedback?: string
}): ReactElement {
const { accountId, web3, isSupportedOceanNetwork, networkId } = useWeb3()
const { address: accountId } = useAccount()
const { chainIds } = useUserPreferences()
const { isAssetNetwork } = useAsset()
const { data: signer } = useSigner()
const newAbortController = useAbortController()
const newCancelToken = useCancelToken()
@ -104,6 +106,8 @@ export default function Compute({
const [isLoadingJobs, setIsLoadingJobs] = useState(false)
const [jobs, setJobs] = useState<ComputeJobMetaData[]>([])
const [retry, setRetry] = useState<boolean>(false)
const { isSupportedOceanNetwork } = useNetworkMetadata()
const { isAssetNetwork } = useAsset()
const hasDatatoken = Number(dtBalance) >= 1
const isComputeButtonDisabled =
@ -116,10 +120,10 @@ export default function Compute({
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
const web3 = await getDummyWeb3(asset?.chainId)
const datatokenInstance = new Datatoken(web3)
const dummySigner = await getDummySigner(asset?.chainId)
const datatokenInstance = new Datatoken(dummySigner)
const dtBalance = await datatokenInstance.balance(
asset?.services[0].datatokenAddress,
accountId || ZERO_ADDRESS // if the user is not connected, we use ZERO_ADDRESS as accountId
@ -127,7 +131,6 @@ export default function Compute({
setAlgorithmDTBalance(new Decimal(dtBalance).toString())
const hasAlgoDt = Number(dtBalance) >= 1
setHasAlgoAssetDatatoken(hasAlgoDt)
return hasAlgoDt
}
async function setComputeFees(
@ -146,20 +149,14 @@ export default function Compute({
const feeAmount = await unitsToAmount(
!isSupportedOceanNetwork || !isAssetNetwork
? await getDummyWeb3(asset?.chainId)
: web3,
? await getDummySigner(asset?.chainId)
: signer,
providerFeeToken,
providerFeeAmount
)
setProviderFeeAmount(feeAmount)
const datatoken = new Datatoken(
await getDummyWeb3(asset?.chainId),
null,
null,
minAbi
)
const datatoken = new Datatoken(await getDummySigner(asset?.chainId))
setProviderFeesSymbol(await datatoken.getSymbol(providerFeeToken))
const computeDuration = asset.accessDetails.validProviderFees
@ -179,6 +176,7 @@ export default function Compute({
const algorithmOrderPriceAndFees = await getOrderPriceAndFees(
selectedAlgorithmAsset,
ZERO_ADDRESS,
signer,
algoProviderFees
)
if (!algorithmOrderPriceAndFees)
@ -197,6 +195,7 @@ export default function Compute({
const datasetPriceAndFees = await getOrderPriceAndFees(
asset,
ZERO_ADDRESS,
signer,
datasetProviderFees
)
if (!datasetPriceAndFees)
@ -373,11 +372,12 @@ export default function Compute({
)
const algorithmOrderTx = await handleComputeOrder(
web3,
signer,
selectedAlgorithmAsset,
algoOrderPriceAndFees,
accountId,
initializedProviderResponse.algorithm,
hasAlgoAssetDatatoken,
computeEnv.consumerAddress
)
if (!algorithmOrderTx) throw new Error('Failed to order algorithm.')
@ -391,11 +391,12 @@ export default function Compute({
)
const datasetOrderTx = await handleComputeOrder(
web3,
signer,
asset,
datasetOrderPriceAndFees,
accountId,
initializedProviderResponse.datasets[0],
hasDatatoken,
computeEnv.consumerAddress
)
if (!datasetOrderTx) throw new Error('Failed to order dataset.')
@ -414,8 +415,7 @@ export default function Compute({
setComputeStatusText(getComputeFeedback()[4])
const response = await ProviderInstance.computeStart(
asset.services[0].serviceEndpoint,
web3,
accountId,
signer,
computeEnv?.id,
computeAsset,
computeAlgorithm,

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@ import { NftMetadata } from '@utils/nft'
import React, { ReactElement } from 'react'
import styles from './NftTooltip.module.css'
import explorerLinkStyles from '@shared/ExplorerLink/index.module.css'
import { accountTruncate } from '@utils/web3'
import { accountTruncate } from '@utils/wallet'
// Supported OpenSea networks:
// 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 NetworkName from '@shared/NetworkName'
import content from '../../../../content/purgatory.json'
import Web3 from 'web3'
import Button from '@shared/atoms/Button'
import RelatedAssets from '../RelatedAssets'
import DmButton from '@shared/DirectMessages/DmButton'
import Web3Feedback from '@components/@shared/Web3Feedback'
import { useWeb3 } from '@context/Web3'
import { useAccount } from 'wagmi'
export default function AssetContent({
asset
@ -26,17 +25,17 @@ export default function AssetContent({
asset: AssetExtended
}): ReactElement {
const { isInPurgatory, purgatoryData, isOwner, isAssetNetwork } = useAsset()
const { accountId } = useWeb3()
const { address: accountId } = useAccount()
const { debug } = useUserPreferences()
const [receipts, setReceipts] = useState([])
const [nftPublisher, setNftPublisher] = useState<string>()
useEffect(() => {
setNftPublisher(
Web3.utils.toChecksumAddress(
receipts?.find((e) => e.type === 'METADATA_CREATED')?.nft?.owner
)
)
if (!receipts.length) return
const publisher = receipts?.find((e) => e.type === 'METADATA_CREATED')?.nft
?.owner
setNftPublisher(publisher)
}, [receipts])
return (

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,13 +2,13 @@ import React, { ReactElement, useState } from 'react'
import Time from '@shared/atoms/Time'
import Table, { TableOceanColumn } from '@shared/atoms/Table'
import Button from '@shared/atoms/Button'
import { useWeb3 } from '@context/Web3'
import Details from './Details'
import Refresh from '@images/refresh.svg'
import { useUserPreferences } from '@context/UserPreferences'
import NetworkName from '@shared/NetworkName'
import styles from './index.module.css'
import AssetListTitle from '@shared/AssetListTitle'
import { useAccount } from 'wagmi'
export function Status({ children }: { children: string }): ReactElement {
return <div className={styles.status}>{children}</div>
@ -55,7 +55,7 @@ export default function ComputeJobs({
isLoading?: boolean
refetchJobs?: any
}): ReactElement {
const { accountId } = useWeb3()
const { address: accountId } = useAccount()
const { chainIds } = useUserPreferences()
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}
/>
) : (
<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 ComputeJobs from './ComputeJobs'
import styles from './index.module.css'
import { useWeb3 } from '@context/Web3'
import { getComputeJobs } from '@utils/compute'
import { useUserPreferences } from '@context/UserPreferences'
import { useCancelToken } from '@hooks/useCancelToken'
import { LoggerInstance } from '@oceanprotocol/lib'
import { useAccount } from 'wagmi'
interface HistoryTab {
title: string
@ -56,7 +56,7 @@ export default function HistoryPage({
}: {
accountIdentifier: string
}): ReactElement {
const { accountId } = useWeb3()
const { address: accountId } = useAccount()
const { chainIds } = useUserPreferences()
const newCancelToken = useCancelToken()

View File

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

View File

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

View File

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

View File

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

View File

@ -7,11 +7,13 @@ import Free from './Free'
import content from '../../../../content/price.json'
import styles from './index.module.css'
import { useMarketMetadata } from '@context/MarketMetadata'
import { useWeb3 } from '@context/Web3'
import { useNetwork } from 'wagmi'
export default function PricingFields(): ReactElement {
const { appConfig } = useMarketMetadata()
const { approvedBaseTokens, chainId } = useWeb3()
const { chain } = useNetwork()
const { approvedBaseTokens } = useMarketMetadata()
// Connect with main publish form
const { values, setFieldValue } = useFormikContext<FormPublishData>()
const { pricing } = values
@ -22,6 +24,23 @@ export default function PricingFields(): ReactElement {
token.name.toLowerCase().includes('ocean')
) || 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
function handleTabChange(tabName: string) {
const type = tabName.toLowerCase()

View File

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

View File

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

View File

@ -11,13 +11,13 @@ import {
NftCreateData,
NftFactory,
Service,
ZERO_ADDRESS
ZERO_ADDRESS,
getEventFromTx
} from '@oceanprotocol/lib'
import { mapTimeoutStringToSeconds, normalizeFile } from '@utils/ddo'
import { generateNftCreateData } from '@utils/nft'
import { getEncryptedFiles } from '@utils/provider'
import slugify from 'slugify'
import Web3 from 'web3'
import { algorithmContainerPresets } from './_constants'
import { FormPublishData, MetadataAlgorithmContainer } from './_types'
import {
@ -28,6 +28,7 @@ import {
} from '../../../app.config'
import { sanitizeUrl } from '@utils/url'
import { getContainerChecksum } from '@utils/docker'
import { parseEther } from 'ethers/lib/utils'
function getUrlFileExtension(fileUrl: string): string {
const splittedFileUrl = fileUrl.split('.')
@ -193,8 +194,7 @@ export async function createTokensAndPricing(
values: FormPublishData,
accountId: string,
config: Config,
nftFactory: NftFactory,
web3: Web3
nftFactory: NftFactory
) {
const nftCreateData: NftCreateData = generateNftCreateData(
values.metadata.nft,
@ -241,15 +241,18 @@ export async function createTokensAndPricing(
)
const result = await nftFactory.createNftWithDatatokenWithFixedRate(
accountId,
nftCreateData,
ercParams,
freParams
)
erc721Address = result.events.NFTCreated.returnValues[0]
datatokenAddress = result.events.TokenCreated.returnValues[0]
txHash = result.transactionHash
const trxReceipt = await result.wait()
const nftCreatedEvent = getEventFromTx(trxReceipt, 'NFTCreated')
const tokenCreatedEvent = getEventFromTx(trxReceipt, 'TokenCreated')
erc721Address = nftCreatedEvent.args.newTokenAddress
datatokenAddress = tokenCreatedEvent.args.newTokenAddress
txHash = trxReceipt.transactionHash
LoggerInstance.log('[publish] createNftErcWithFixedRate tx', txHash)
@ -261,8 +264,8 @@ export async function createTokensAndPricing(
// both will be just 1 for the market
const dispenserParams: DispenserCreationParams = {
dispenserAddress: config.dispenserAddress,
maxTokens: web3.utils.toWei('1'),
maxBalance: web3.utils.toWei('1'),
maxTokens: parseEther('1').toString(),
maxBalance: parseEther('1').toString(),
withMint: true,
allowedSwapper: ZERO_ADDRESS
}
@ -273,14 +276,17 @@ export async function createTokensAndPricing(
)
const result = await nftFactory.createNftWithDatatokenWithDispenser(
accountId,
nftCreateData,
ercParams,
dispenserParams
)
erc721Address = result.events.NFTCreated.returnValues[0]
datatokenAddress = result.events.TokenCreated.returnValues[0]
txHash = result.transactionHash
const trxReceipt = await result.wait()
const nftCreatedEvent = getEventFromTx(trxReceipt, 'NFTCreated')
const tokenCreatedEvent = getEventFromTx(trxReceipt, 'TokenCreated')
erc721Address = nftCreatedEvent.args.newTokenAddress
datatokenAddress = tokenCreatedEvent.args.newTokenAddress
txHash = trxReceipt.transactionHash
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 { initialPublishFeedback, initialValues } from './_constants'
import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
import { useWeb3 } from '@context/Web3'
import { createTokensAndPricing, transformPublishFormToDdo } from './_utils'
import PageHeader from '@shared/Page/PageHeader'
import Title from './Title'
@ -19,6 +18,7 @@ import { getOceanConfig } from '@utils/ocean'
import { validationSchema } from './_validation'
import { useAbortController } from '@hooks/useAbortController'
import { setNFTMetadataAndTokenURI } from '@utils/nft'
import { useAccount, useNetwork, useSigner } from 'wagmi'
export default function PublishPage({
content
@ -26,7 +26,9 @@ export default function PublishPage({
content: { title: string; description: string; warning: string }
}): ReactElement {
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 scrollToRef = useRef()
const nftFactory = useNftFactory()
@ -60,17 +62,11 @@ export default function PublishPage({
}))
try {
const config = getOceanConfig(chainId)
const config = getOceanConfig(chain?.id)
LoggerInstance.log('[publish] using config: ', config)
const { erc721Address, datatokenAddress, txHash } =
await createTokensAndPricing(
values,
accountId,
config,
nftFactory,
web3
)
await createTokensAndPricing(values, accountId, config, nftFactory)
const isSuccess = Boolean(erc721Address && datatokenAddress && txHash)
if (!isSuccess) throw new Error('No Token created. Please try again.')
@ -197,23 +193,24 @@ export default function PublishPage({
const res = await setNFTMetadataAndTokenURI(
ddo,
accountId,
web3,
signer,
values.metadata.nft,
newAbortController()
)
if (!res?.transactionHash)
const tx = await res.wait()
if (!tx?.transactionHash)
throw new Error(
'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) => ({
...prevState,
'3': {
...prevState['3'],
status: res ? 'success' : 'error',
txHash: res?.transactionHash
status: tx ? 'success' : 'error',
txHash: tx?.transactionHash
}
}))

View File

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

View File

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

View File

@ -1,10 +1,10 @@
import React, { ReactElement, useState } from 'react'
import Search from '../components/Search'
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 { useRouter } from 'next/router'
import web3 from 'web3'
import { isAddress } from 'ethers/lib/utils'
export default function PageSearch(): ReactElement {
const router = useRouter()
@ -13,7 +13,7 @@ export default function PageSearch(): ReactElement {
const [totalResults, setTotalResults] = useState<number>()
const [totalPagesNumber, setTotalPagesNumber] = useState<number>()
const isETHAddress = web3.utils.isAddress(text as string)
const isETHAddress = isAddress(text as string)
const searchValue =
(isETHAddress ? accountTruncate(text as string) : text) ||
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 '_toast.css';
@import '_web3modal.css';
@import '_emojipicker.css';
/* prevent background scrolling */