From cdcf9ce9f3d9ebf5012d1e2f29928fd006e2dc1a Mon Sep 17 00:00:00 2001 From: Moritz Kirstein Date: Mon, 29 Apr 2024 13:10:25 +0200 Subject: [PATCH 1/5] feat: auto wallet for publish and edit functionality --- src/@context/Asset.tsx | 31 ++++--- src/@hooks/useNftFactory.ts | 25 +++++- src/components/Asset/Edit/EditMetadata.tsx | 95 ++++++++++++---------- src/components/Publish/index.tsx | 23 +++++- 4 files changed, 107 insertions(+), 67 deletions(-) diff --git a/src/@context/Asset.tsx b/src/@context/Asset.tsx index 1f7b4a71..a353c461 100644 --- a/src/@context/Asset.tsx +++ b/src/@context/Asset.tsx @@ -86,6 +86,15 @@ function AssetProvider({ const newCancelToken = useCancelToken() const isMounted = useIsMounted() + const [accountIdToCheck, setAccountIdToCheck] = useState(accountId) + useEffect(() => { + if (isAutomationEnabled && autoWallet?.address) { + setAccountIdToCheck(autoWallet.address) + } else { + setAccountIdToCheck(accountId) + } + }, [accountId, autoWallet, isAutomationEnabled]) + // ----------------------------------- // Helper: Get and set asset based on passed DID // ----------------------------------- @@ -155,11 +164,6 @@ function AssetProvider({ const fetchAccessDetails = useCallback(async (): Promise => { if (!asset?.chainId || !asset?.services?.length) return - const accountIdToCheck = - isAutomationEnabled && autoWallet?.address - ? autoWallet.address - : accountId - const accessDetails = await getAccessDetails( asset.chainId, asset.services[0].datatokenAddress, @@ -171,14 +175,7 @@ function AssetProvider({ accessDetails })) LoggerInstance.log(`[asset] Got access details for ${did}`, accessDetails) - }, [ - asset?.chainId, - asset?.services, - accountId, - did, - autoWallet?.address, - isAutomationEnabled - ]) + }, [asset?.chainId, asset?.services, accountIdToCheck, did]) // ----------------------------------- // Helper: Get and set asset Service Credential state @@ -246,7 +243,7 @@ function AssetProvider({ if (!isMounted) return fetchAccessDetails() - }, [accountId, fetchAccessDetails, isMounted]) + }, [accountIdToCheck, fetchAccessDetails, isMounted]) // ----------------------------------- // Check user network against asset network @@ -262,11 +259,11 @@ function AssetProvider({ // Asset owner check against wallet user // ----------------------------------- useEffect(() => { - if (!accountId || !owner) return + if (!accountIdToCheck || !owner) return - const isOwner = accountId?.toLowerCase() === owner.toLowerCase() + const isOwner = accountIdToCheck?.toLowerCase() === owner.toLowerCase() setIsOwner(isOwner) - }, [accountId, owner]) + }, [accountIdToCheck, owner]) // ----------------------------------- // Load ocean config based on asset network diff --git a/src/@hooks/useNftFactory.ts b/src/@hooks/useNftFactory.ts index 560abdef..16526c52 100644 --- a/src/@hooks/useNftFactory.ts +++ b/src/@hooks/useNftFactory.ts @@ -1,20 +1,37 @@ import { useEffect, useState } from 'react' -import { NftFactory } from '@oceanprotocol/lib' +import { LoggerInstance, NftFactory } from '@oceanprotocol/lib' import { getOceanConfig } from '@utils/ocean' import { useNetwork, useSigner } from 'wagmi' +import { useAutomation } from '../@context/Automation/AutomationProvider' +import { sign } from 'crypto' function useNftFactory(): NftFactory { const { chain } = useNetwork() const { data: signer } = useSigner() + const { autoWallet, isAutomationEnabled } = useAutomation() + const [signerToUse, setSignerToUse] = useState(signer) const [nftFactory, setNftFactory] = useState() useEffect(() => { - if (!signer || !chain?.id) return + if (isAutomationEnabled && autoWallet?.address) { + setSignerToUse(autoWallet) + } else { + setSignerToUse(signer) + } + }, [isAutomationEnabled, autoWallet, signer]) + + useEffect(() => { + if (!signerToUse || !chain?.id) return const config = getOceanConfig(chain.id) - const factory = new NftFactory(config?.nftFactoryAddress, signer) + const factory = new NftFactory(config?.nftFactoryAddress, signerToUse) + LoggerInstance.log('[NftFactory] instantiated:', { + chain: chain.id, + factory: factory.address, + signer: signerToUse + }) setNftFactory(factory) - }, [signer, chain?.id]) + }, [signerToUse, chain?.id]) return nftFactory } diff --git a/src/components/Asset/Edit/EditMetadata.tsx b/src/components/Asset/Edit/EditMetadata.tsx index c78cb97e..0b1a3b03 100644 --- a/src/components/Asset/Edit/EditMetadata.tsx +++ b/src/components/Asset/Edit/EditMetadata.tsx @@ -1,42 +1,39 @@ -import { ReactElement, useState, useEffect } from 'react' -import { Formik } from 'formik' import { - LoggerInstance, - FixedRateExchange, + generateCredentials, + transformConsumerParameters +} from '@components/Publish/_utils' +import { useAsset } from '@context/Asset' +import { useUserPreferences } from '@context/UserPreferences' +import { useAbortController } from '@hooks/useAbortController' +import { Asset, Datatoken, - Nft, + FixedRateExchange, + LoggerInstance, Metadata, + Nft, Service } from '@oceanprotocol/lib' -import { validationSchema } from './_validation' -import { getInitialValues } from './_constants' -import { MetadataEditForm } from './_types' -import { useUserPreferences } from '@context/UserPreferences' import Web3Feedback from '@shared/Web3Feedback' -import FormEditMetadata from './FormEditMetadata' +import { assetStateToNumber } from '@utils/assetState' import { mapTimeoutStringToSeconds, normalizeFile } from '@utils/ddo' -import styles from './index.module.css' +import { setMinterToDispenser, setMinterToPublisher } from '@utils/dispenser' +import { decodeTokenURI, setNFTMetadataAndTokenURI } from '@utils/nft' +import { getOceanConfig, getPaymentCollector } from '@utils/ocean' +import { getEncryptedFiles } from '@utils/provider' +import { sanitizeUrl } from '@utils/url' +import { Formik } from 'formik' +import { ReactElement, useEffect, useState } from 'react' +import { useAccount, useNetwork, useProvider, useSigner } from 'wagmi' import content from '../../../../content/pages/editMetadata.json' -import { useAbortController } from '@hooks/useAbortController' +import { useAutomation } from '../../../@context/Automation/AutomationProvider' import DebugEditMetadata from './DebugEditMetadata' -import { getOceanConfig, getPaymentCollector } from '@utils/ocean' import EditFeedback from './EditFeedback' -import { useAsset } from '@context/Asset' -import { - decodeTokenURI, - setNftMetadata, - setNFTMetadataAndTokenURI -} from '@utils/nft' -import { sanitizeUrl } from '@utils/url' -import { getEncryptedFiles } from '@utils/provider' -import { assetStateToNumber } from '@utils/assetState' -import { setMinterToPublisher, setMinterToDispenser } from '@utils/dispenser' -import { useAccount, useProvider, useNetwork, useSigner } from 'wagmi' -import { - transformConsumerParameters, - generateCredentials -} from '@components/Publish/_utils' +import FormEditMetadata from './FormEditMetadata' +import { getInitialValues } from './_constants' +import { MetadataEditForm } from './_types' +import { validationSchema } from './_validation' +import styles from './index.module.css' export default function Edit({ asset @@ -57,6 +54,20 @@ export default function Edit({ const isComputeType = asset?.services[0]?.type === 'compute' const hasFeedback = error || success + const { autoWallet, isAutomationEnabled } = useAutomation() + const [signerToUse, setSignerToUse] = useState(signer) + const [accountIdToUse, setAccountIdToUse] = useState(accountId) + + useEffect(() => { + if (isAutomationEnabled && autoWallet?.address) { + setAccountIdToUse(autoWallet.address) + setSignerToUse(autoWallet) + } else { + setAccountIdToUse(accountId) + setSignerToUse(signer) + } + }, [isAutomationEnabled, autoWallet, signer, accountId]) + useEffect(() => { if (!asset || !provider) return @@ -82,7 +93,7 @@ export default function Edit({ const fixedRateInstance = new FixedRateExchange( config.fixedRateExchangeAddress, - signer + signerToUse ) const setPriceResp = await fixedRateInstance.setRate( @@ -130,10 +141,10 @@ export default function Edit({ (await updateFixedPrice(values.price)) if (values.paymentCollector !== paymentCollector) { - const datatoken = new Datatoken(signer) + const datatoken = new Datatoken(signerToUse) await datatoken.setPaymentCollector( asset?.datatokens[0].address, - accountId, + accountIdToUse, values.paymentCollector ) } @@ -185,9 +196,9 @@ export default function Edit({ asset?.accessDetails?.isPurchasable ) { const tx = await setMinterToPublisher( - signer, + signerToUse, asset?.accessDetails?.datatoken?.address, - accountId, + accountIdToUse, setError ) if (!tx) return @@ -200,15 +211,15 @@ export default function Edit({ // TODO: revert to setMetadata function const setMetadataTx = await setNFTMetadataAndTokenURI( updatedAsset, - accountId, - signer, + accountIdToUse, + signerToUse, decodeTokenURI(asset.nft.tokenURI), newAbortController() ) // const setMetadataTx = await setNftMetadata( // updatedAsset, - // accountId, - // signer, + // accountIdToUse, + // signerToUse, // newAbortController() // ) @@ -224,11 +235,11 @@ export default function Edit({ assetState }) if (values.assetState !== assetState) { - const nft = new Nft(signer) + const nft = new Nft(signerToUse) const setMetadataStateTx = await nft.setMetadataState( asset?.nftAddress, - accountId, + accountIdToUse, assetStateToNumber(values.assetState) ) if (!setMetadataStateTx) { @@ -243,9 +254,9 @@ export default function Edit({ if (asset.accessDetails.type === 'free') { const tx = await setMinterToDispenser( - signer, + signerToUse, asset?.accessDetails?.datatoken?.address, - accountId, + accountIdToUse, setError ) if (!tx) return @@ -304,7 +315,7 @@ export default function Edit({ diff --git a/src/components/Publish/index.tsx b/src/components/Publish/index.tsx index b6f48319..c89c2963 100644 --- a/src/components/Publish/index.tsx +++ b/src/components/Publish/index.tsx @@ -1,4 +1,4 @@ -import { ReactElement, useState, useRef } from 'react' +import { ReactElement, useState, useRef, useEffect } from 'react' import { Form, Formik } from 'formik' import { initialPublishFeedback, initialValues } from './_constants' import { useAccountPurgatory } from '@hooks/useAccountPurgatory' @@ -25,6 +25,7 @@ import { useAbortController } from '@hooks/useAbortController' import { setNFTMetadataAndTokenURI } from '@utils/nft' import { customProviderUrl } from '../../../app.config' import { useAccount, useNetwork, useSigner } from 'wagmi' +import { useAutomation } from '../../@context/Automation/AutomationProvider' export default function PublishPage({ content @@ -51,6 +52,20 @@ export default function PublishPage({ const [ddoEncrypted, setDdoEncrypted] = useState() const [did, setDid] = useState() + const { autoWallet, isAutomationEnabled } = useAutomation() + const [accountIdToUse, setAccountIdToUse] = useState(accountId) + const [signerToUse, setSignerToUse] = useState(signer) + + useEffect(() => { + if (isAutomationEnabled && autoWallet?.address) { + setAccountIdToUse(autoWallet.address) + setSignerToUse(autoWallet) + } else { + setAccountIdToUse(accountId) + setSignerToUse(signer) + } + }, [isAutomationEnabled, autoWallet, accountId, signer]) + // -------------------------------------------------- // 1. Create NFT & datatokens & create pricing schema // -------------------------------------------------- @@ -72,7 +87,7 @@ export default function PublishPage({ LoggerInstance.log('[publish] using config: ', config) const { erc721Address, datatokenAddress, txHash } = - await createTokensAndPricing(values, accountId, config, nftFactory) + await createTokensAndPricing(values, accountIdToUse, config, nftFactory) const isSuccess = Boolean(erc721Address && datatokenAddress && txHash) if (!isSuccess) throw new Error('No Token created. Please try again.') @@ -203,8 +218,8 @@ export default function PublishPage({ const res = await setNFTMetadataAndTokenURI( ddo, - accountId, - signer, + accountIdToUse, + signerToUse, values.metadata.nft, newAbortController() ) From 384a46f1d04eb813a3475eda8b66a268afa42d5d Mon Sep 17 00:00:00 2001 From: Moritz Kirstein Date: Tue, 30 Apr 2024 12:04:58 +0200 Subject: [PATCH 2/5] fix: refetch signerf --- src/components/Asset/Edit/EditMetadata.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/Asset/Edit/EditMetadata.tsx b/src/components/Asset/Edit/EditMetadata.tsx index 0b1a3b03..3179d12c 100644 --- a/src/components/Asset/Edit/EditMetadata.tsx +++ b/src/components/Asset/Edit/EditMetadata.tsx @@ -45,7 +45,7 @@ export default function Edit({ const { address: accountId } = useAccount() const { chain } = useNetwork() const provider = useProvider() - const { data: signer } = useSigner() + const { data: signer, refetch: refetchSigner } = useSigner() const newAbortController = useAbortController() const [success, setSuccess] = useState() @@ -62,11 +62,19 @@ export default function Edit({ if (isAutomationEnabled && autoWallet?.address) { setAccountIdToUse(autoWallet.address) setSignerToUse(autoWallet) - } else { + LoggerInstance.log('[edit] using autoWallet', { autoWallet }) + } else if (accountId && signer) { setAccountIdToUse(accountId) setSignerToUse(signer) + LoggerInstance.log('[edit] using web3 account', { + accountId, + signer + }) + } else { + refetchSigner() + LoggerInstance.log('[edit] refetching signer') } - }, [isAutomationEnabled, autoWallet, signer, accountId]) + }, [isAutomationEnabled, signer, autoWallet, accountId]) useEffect(() => { if (!asset || !provider) return From 924a8d0f30267640a0a75d51f373ed1a475097f6 Mon Sep 17 00:00:00 2001 From: Moritz Kirstein Date: Mon, 13 May 2024 13:28:50 +0200 Subject: [PATCH 3/5] chore: clean up logs --- src/components/Asset/Edit/EditMetadata.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/Asset/Edit/EditMetadata.tsx b/src/components/Asset/Edit/EditMetadata.tsx index 3179d12c..f5c72ad1 100644 --- a/src/components/Asset/Edit/EditMetadata.tsx +++ b/src/components/Asset/Edit/EditMetadata.tsx @@ -62,14 +62,11 @@ export default function Edit({ if (isAutomationEnabled && autoWallet?.address) { setAccountIdToUse(autoWallet.address) setSignerToUse(autoWallet) - LoggerInstance.log('[edit] using autoWallet', { autoWallet }) + LoggerInstance.log('[edit] using autoWallet to sign') } else if (accountId && signer) { setAccountIdToUse(accountId) setSignerToUse(signer) - LoggerInstance.log('[edit] using web3 account', { - accountId, - signer - }) + LoggerInstance.log('[edit] using web3 account to sign') } else { refetchSigner() LoggerInstance.log('[edit] refetching signer') From 7428be613b2bc0d74abc2f24220ede3c2ef70232 Mon Sep 17 00:00:00 2001 From: Moritz Kirstein Date: Mon, 13 May 2024 13:30:12 +0200 Subject: [PATCH 4/5] chore: remove unused import --- src/@hooks/useNftFactory.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/@hooks/useNftFactory.ts b/src/@hooks/useNftFactory.ts index 16526c52..3e8a754d 100644 --- a/src/@hooks/useNftFactory.ts +++ b/src/@hooks/useNftFactory.ts @@ -1,9 +1,8 @@ -import { useEffect, useState } from 'react' import { LoggerInstance, NftFactory } from '@oceanprotocol/lib' import { getOceanConfig } from '@utils/ocean' +import { useEffect, useState } from 'react' import { useNetwork, useSigner } from 'wagmi' import { useAutomation } from '../@context/Automation/AutomationProvider' -import { sign } from 'crypto' function useNftFactory(): NftFactory { const { chain } = useNetwork() From 08c436c2ea47beb8bbf778e57dcbd0b42cfc4550 Mon Sep 17 00:00:00 2001 From: Moritz Kirstein Date: Wed, 15 May 2024 12:13:46 +0200 Subject: [PATCH 5/5] feat: auto wallet for compute edits --- .../Asset/Edit/EditComputeDataset.tsx | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/components/Asset/Edit/EditComputeDataset.tsx b/src/components/Asset/Edit/EditComputeDataset.tsx index 63debfd5..caeaaaba 100644 --- a/src/components/Asset/Edit/EditComputeDataset.tsx +++ b/src/components/Asset/Edit/EditComputeDataset.tsx @@ -1,5 +1,5 @@ import { Formik } from 'formik' -import { ReactElement, useState } from 'react' +import { ReactElement, useEffect, useState } from 'react' import FormEditComputeDataset from './FormEditComputeDataset' import { LoggerInstance, @@ -28,6 +28,7 @@ import { } from '@utils/nft' import { ComputeEditForm } from './_types' import { useAccount, useSigner } from 'wagmi' +import { useAutomation } from '../../../@context/Automation/AutomationProvider' export default function EditComputeDataset({ asset @@ -38,6 +39,14 @@ export default function EditComputeDataset({ const { address: accountId } = useAccount() const { data: signer } = useSigner() const { fetchAsset, isAssetNetwork } = useAsset() + const { autoWallet, isAutomationEnabled } = useAutomation() + const [signerToUse, setSignerToUse] = useState(signer) + const [accountIdToUse, setAccountIdToUse] = useState(accountId) + + useEffect(() => { + setSignerToUse(isAutomationEnabled ? autoWallet : signer) + setAccountIdToUse(isAutomationEnabled ? autoWallet?.address : accountId) + }, [isAutomationEnabled, accountId, autoWallet, signer]) const [success, setSuccess] = useState() const [error, setError] = useState() @@ -52,9 +61,9 @@ export default function EditComputeDataset({ asset?.accessDetails?.isPurchasable ) { const tx = await setMinterToPublisher( - signer, + signerToUse, asset?.accessDetails?.datatoken?.address, - accountId, + accountIdToUse, setError ) if (!tx) return @@ -90,8 +99,8 @@ export default function EditComputeDataset({ // TODO: revert to setMetadata function const setMetadataTx = await setNFTMetadataAndTokenURI( updatedAsset, - accountId, - signer, + accountIdToUse, + signerToUse, decodeTokenURI(asset.nft.tokenURI), newAbortController() ) @@ -112,9 +121,9 @@ export default function EditComputeDataset({ await setMetadataTx.wait() if (asset.accessDetails.type === 'free') { const tx = await setMinterToDispenser( - signer, + signerToUse, asset?.accessDetails?.datatoken?.address, - accountId, + accountIdToUse, setError ) if (!tx) return @@ -163,7 +172,7 @@ export default function EditComputeDataset({ {debug === true && (