diff --git a/packages/apps/dev-wallet/src/modules/communication/communication.provider.tsx b/packages/apps/dev-wallet/src/modules/communication/communication.provider.tsx index d8f58cd67a..248793712a 100644 --- a/packages/apps/dev-wallet/src/modules/communication/communication.provider.tsx +++ b/packages/apps/dev-wallet/src/modules/communication/communication.provider.tsx @@ -172,6 +172,8 @@ export const CommunicationProvider: FC< requestId={requestId} plugin={plugin} onDone={() => { + const request = requests.get(requestId); + request?.reject(request.payload); setUiComponent(null); }} />, diff --git a/packages/apps/dev-wallet/src/modules/plugins/components/SignRequestDialog.tsx b/packages/apps/dev-wallet/src/modules/plugins/components/SignRequestDialog.tsx index ef8e8a4216..1d959c3a3e 100644 --- a/packages/apps/dev-wallet/src/modules/plugins/components/SignRequestDialog.tsx +++ b/packages/apps/dev-wallet/src/modules/plugins/components/SignRequestDialog.tsx @@ -22,8 +22,8 @@ export function SignRequestDialog({ return ( - - {`Sign Request from ${plugin.name}`} + + {`Sign Request from ${plugin.name}`} diff --git a/packages/apps/rwa-demo/src/app/(app)/styles.css.ts b/packages/apps/rwa-demo/src/app/(app)/styles.css.ts index 0d740f7b66..a3fa729595 100644 --- a/packages/apps/rwa-demo/src/app/(app)/styles.css.ts +++ b/packages/apps/rwa-demo/src/app/(app)/styles.css.ts @@ -18,3 +18,9 @@ export const logoClass = style({ globalStyle('body', { overflowY: 'hidden', }); + +// fix to make sure the wallet connect modal is ALWAYS on top +globalStyle('wcm-modal', { + position: 'relative', + zIndex: 99999999999, +}); diff --git a/packages/apps/rwa-demo/src/components/AssetForm/AssetStepperForm.tsx b/packages/apps/rwa-demo/src/components/AssetForm/AssetStepperForm.tsx index 1887cf66f5..38a7bd426d 100644 --- a/packages/apps/rwa-demo/src/components/AssetForm/AssetStepperForm.tsx +++ b/packages/apps/rwa-demo/src/components/AssetForm/AssetStepperForm.tsx @@ -72,14 +72,13 @@ export const AssetStepperForm: FC = ({ handleDone }) => { const tx = await submitContract(data); - setIsPending(false); - if (tx) { const createdAsset = await addAsset({ contractName: data.contractName, namespace: data.namespace, }); + setIsPending(false); setIsSuccess(true); setStep(STEPS.DONE); diff --git a/packages/apps/rwa-demo/src/components/AssetsList/AssetsList.tsx b/packages/apps/rwa-demo/src/components/AssetsList/AssetsList.tsx index 4246dc73c8..5a570ce458 100644 --- a/packages/apps/rwa-demo/src/components/AssetsList/AssetsList.tsx +++ b/packages/apps/rwa-demo/src/components/AssetsList/AssetsList.tsx @@ -46,7 +46,6 @@ export const AssetsList: FC<{ init?: boolean }> = ({ init }) => { } /> - {isAllowed.toString()} { const Component = ({ value }: ICompactTableFormatterProps) => { const [hasError, setHasError] = useState(false); + const [isCreatingContract, setIsCreatingContract] = useState(false); - const { setAsset } = useAsset(); + const { getTransactions, transactions } = useTransactions(); + const { setAsset, asset: currentAsset } = useAsset(); const { addNotification } = useNotifications(); const asset = value as unknown as IAsset | undefined; @@ -35,6 +40,17 @@ export const FormatSelectAsset = () => { }, }); + useEffect(() => { + if (!asset?.uuid || !currentAsset?.uuid) return; + if (asset.uuid !== currentAsset.uuid || transactions.length === 0) { + setIsCreatingContract(false); + return; + } + + const creatingContractTx = getTransactions(TXTYPES.CREATECONTRACT); + setIsCreatingContract(!!creatingContractTx); + }, [asset?.uuid, transactions.length, currentAsset?.uuid]); + useEffect(() => { if (loading) return; if (data?.events.edges.length === 0) { @@ -54,20 +70,24 @@ export const FormatSelectAsset = () => { window.location.href = '/'; }; - if (loading) { + if (loading || (hasError && isCreatingContract)) { return ( + startVisual={ + } + /> + } + /> ); } - if (hasError) { + if (hasError && !isCreatingContract) { return ( + startVisual={} + /> ); } diff --git a/packages/apps/rwa-demo/src/components/admin/OrganisationInfoForm/OrganisationInfoForm.tsx b/packages/apps/rwa-demo/src/components/admin/OrganisationInfoForm/OrganisationInfoForm.tsx index afceb164fe..fa0f127bdc 100644 --- a/packages/apps/rwa-demo/src/components/admin/OrganisationInfoForm/OrganisationInfoForm.tsx +++ b/packages/apps/rwa-demo/src/components/admin/OrganisationInfoForm/OrganisationInfoForm.tsx @@ -87,7 +87,6 @@ export const OrganisationInfoForm: FC = ({ organisationId }) => { if (reload === false) return; - console.log('reload'); // eslint-disable-next-line @typescript-eslint/no-floating-promises init(organisationId); }, [organisationId, reload]); diff --git a/packages/apps/rwa-demo/src/contexts/TransactionsContext/TransactionsContext.ts b/packages/apps/rwa-demo/src/contexts/TransactionsContext/TransactionsContext.ts index fed4f526b8..bf4076ee4b 100644 --- a/packages/apps/rwa-demo/src/contexts/TransactionsContext/TransactionsContext.ts +++ b/packages/apps/rwa-demo/src/contexts/TransactionsContext/TransactionsContext.ts @@ -1,3 +1,4 @@ +import type { IAddContractProps } from '@/services/createContract'; import type { ICommandResult } from '@kadena/client'; import { createContext } from 'react'; @@ -57,6 +58,7 @@ export interface ITransactionsContext { transactions: ITransaction[]; addTransaction: ( request: Omit, + newAsset?: IAddContractProps, ) => Promise; getTransactions: (type: ITxType | ITxType[]) => ITransaction[]; txsButtonRef?: HTMLButtonElement | null; @@ -65,6 +67,8 @@ export interface ITransactionsContext { setTxsAnimationRef: (value: HTMLDivElement) => void; isActiveAccountChangeTx: boolean; //checks if the agentroles for this user are being changed. if so, stop all permissions until the tx is resolved removeTransaction: (data: ITransaction) => Promise; + showTransactionDialog: () => void; + hideTransactionDialog: () => void; } export const TransactionsContext = createContext( diff --git a/packages/apps/rwa-demo/src/hooks/useSubmit2Chain.test.ts b/packages/apps/rwa-demo/src/hooks/__tests__/useSubmit2Chain.test.ts similarity index 93% rename from packages/apps/rwa-demo/src/hooks/useSubmit2Chain.test.ts rename to packages/apps/rwa-demo/src/hooks/__tests__/useSubmit2Chain.test.ts index af84279343..9e108c5338 100644 --- a/packages/apps/rwa-demo/src/hooks/useSubmit2Chain.test.ts +++ b/packages/apps/rwa-demo/src/hooks/__tests__/useSubmit2Chain.test.ts @@ -2,7 +2,7 @@ import { TXTYPES } from '@/contexts/TransactionsContext/TransactionsContext'; import { EVENT_NAMES } from '@/utils/analytics'; import { renderHook } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; -import { useSubmit2Chain } from './useSubmit2Chain'; +import { useSubmit2Chain } from './../useSubmit2Chain'; // Mock all dependencies vi.mock('./account', () => ({ @@ -109,7 +109,7 @@ describe('useSubmit2Chain', () => { const { result } = renderHook(() => useSubmit2Chain()); const chainFunction = vi.fn().mockResolvedValue(undefined); - const { useNotifications } = await import('./notifications'); + const { useNotifications } = await import('./../notifications'); const mockAddNotification = vi.mocked(useNotifications).mock.results[0].value.addNotification; @@ -160,7 +160,7 @@ describe('useSubmit2Chain', () => { hash: 'test-hash', }); - const { useAccount } = await import('./account'); + const { useAccount } = await import('./../account'); const mockSign = vi.mocked(useAccount).mock.results[0].value.sign; await result.current.submit2Chain( @@ -189,7 +189,7 @@ describe('useSubmit2Chain', () => { throw new Error('Test error message'); }); - const { useNotifications } = await import('./notifications'); + const { useNotifications } = await import('./../notifications'); const mockAddNotification = vi.mocked(useNotifications).mock.results[0].value.addNotification; @@ -233,7 +233,7 @@ describe('useSubmit2Chain', () => { hash: 'test-hash', }); - const { useTransactions } = await import('./transactions'); + const { useTransactions } = await import('./../transactions'); const mockAddTransaction = vi.mocked(useTransactions).mock.results[0].value.addTransaction; @@ -268,7 +268,7 @@ describe('useSubmit2Chain', () => { it('should send notification when asset is not found and skipAssetCheck is not true', async () => { // Override asset mock to return undefined - vi.mocked(await import('./asset')).useAsset.mockReturnValueOnce({ + vi.mocked(await import('./../asset')).useAsset.mockReturnValueOnce({ asset: undefined, assets: [], paused: false, @@ -279,17 +279,16 @@ describe('useSubmit2Chain', () => { getAsset: vi.fn(), maxCompliance: vi.fn(), investors: [], - initFetchInvestors: vi.fn(), investorsIsLoading: false, agents: [], - initFetchAgents: vi.fn(), agentsIsLoading: false, + assetStore: {}, }); const { result } = renderHook(() => useSubmit2Chain()); const chainFunction = vi.fn(); - const { useNotifications } = await import('./notifications'); + const { useNotifications } = await import('./../notifications'); const mockAddNotification = vi.mocked(useNotifications).mock.results[0].value.addNotification; @@ -327,7 +326,7 @@ describe('useSubmit2Chain', () => { it('should proceed when skipAssetCheck is true even when asset is undefined', async () => { // Override asset mock to return undefined - vi.mocked(await import('./asset')).useAsset.mockReturnValueOnce({ + vi.mocked(await import('./../asset')).useAsset.mockReturnValueOnce({ asset: undefined, assets: [], paused: false, @@ -338,11 +337,10 @@ describe('useSubmit2Chain', () => { getAsset: vi.fn(), maxCompliance: vi.fn(), investors: [], - initFetchInvestors: vi.fn(), investorsIsLoading: false, agents: [], - initFetchAgents: vi.fn(), agentsIsLoading: false, + assetStore: {}, }); const { result } = renderHook(() => useSubmit2Chain()); @@ -383,7 +381,7 @@ describe('useSubmit2Chain', () => { const chainFunction = vi.fn().mockResolvedValue(txPayload); - const { useAccount } = await import('./account'); + const { useAccount } = await import('./../account'); const mockSign = vi.mocked(useAccount).mock.results[0].value.sign; mockSign.mockResolvedValue({ ...txPayload, diff --git a/packages/apps/rwa-demo/src/hooks/createContract.ts b/packages/apps/rwa-demo/src/hooks/createContract.ts index 3ece0012c1..e7adffa561 100644 --- a/packages/apps/rwa-demo/src/hooks/createContract.ts +++ b/packages/apps/rwa-demo/src/hooks/createContract.ts @@ -15,7 +15,8 @@ export const useCreateContract = () => { const { userToken } = useUser(); const { organisation } = useOrganisation(); const [isAllowed, setIsAllowed] = useState(false); - const { addTransaction } = useTransactions(); + const { addTransaction, hideTransactionDialog, showTransactionDialog } = + useTransactions(); const { addNotification } = useNotifications(); const submit = async ( @@ -88,6 +89,7 @@ export const useCreateContract = () => { } try { + showTransactionDialog(); const signedTransaction = await sign(tx); if (!signedTransaction) { @@ -118,32 +120,35 @@ export const useCreateContract = () => { const client = getClient(); const res = await client.submit(signedTransaction); + hideTransactionDialog(); + await addTransaction( + { + ...res, + type: TXTYPES.CREATECONTRACT, + accounts: [account?.address!], + }, + data, + ); - await addTransaction({ - ...res, - type: TXTYPES.CREATECONTRACT, - accounts: [account?.address!], - }); - - const dataResult = await client.listen(res); - - // if the contract already exists, go to that contract - if (dataResult.result.status === 'failure') { - if ( - (dataResult.result.error as any)?.message?.includes( - '"PactDuplicateTableError', - ) - ) { - window.location.href = `/assets/create/${data.namespace}/${data.contractName}`; - return false; - } - return false; - } - - addNotification({ - intent: 'positive', - message: `Contract ${data.contractName} created successfully`, - }); + // const dataResult = await client.listen(res); + + // // if the contract already exists, go to that contract + // if (dataResult.result.status === 'failure') { + // if ( + // (dataResult.result.error as any)?.message?.includes( + // '"PactDuplicateTableError', + // ) + // ) { + // window.location.href = `/assets/create/${data.namespace}/${data.contractName}`; + // return false; + // } + // return false; + // } + + // addNotification({ + // intent: 'positive', + // message: `Contract ${data.contractName} created successfully`, + // }); return true; } catch (e: any) { diff --git a/packages/apps/rwa-demo/src/hooks/useSubmit2Chain.ts b/packages/apps/rwa-demo/src/hooks/useSubmit2Chain.ts index 41ee1f99ea..4086d0b9e4 100644 --- a/packages/apps/rwa-demo/src/hooks/useSubmit2Chain.ts +++ b/packages/apps/rwa-demo/src/hooks/useSubmit2Chain.ts @@ -29,7 +29,8 @@ interface IOptions { export const useSubmit2Chain = () => { const { account, sign } = useAccount(); - const { addTransaction } = useTransactions(); + const { addTransaction, showTransactionDialog, hideTransactionDialog } = + useTransactions(); const { asset } = useAsset(); const { addNotification } = useNotifications(); @@ -58,9 +59,10 @@ export const useSubmit2Chain = () => { } let res: ITransactionDescriptor | undefined = undefined; - const tx: IUnsignedCommand | undefined = undefined; + let tx: IUnsignedCommand | undefined = undefined; try { - const tx = await options.chainFunction(account!, asset!); + showTransactionDialog(); + tx = await options.chainFunction(account!, asset!); if (!tx) { addNotification( @@ -123,6 +125,8 @@ export const useSubmit2Chain = () => { }, }, ); + } finally { + hideTransactionDialog(); } }; diff --git a/packages/apps/rwa-demo/src/providers/AccountProvider/AccountProvider.tsx b/packages/apps/rwa-demo/src/providers/AccountProvider/AccountProvider.tsx index 2332fb6063..ede49848bf 100644 --- a/packages/apps/rwa-demo/src/providers/AccountProvider/AccountProvider.tsx +++ b/packages/apps/rwa-demo/src/providers/AccountProvider/AccountProvider.tsx @@ -135,6 +135,7 @@ export const AccountProvider: FC = ({ children }) => { let tempAccount: IWalletAccount | undefined; const adapter = wallet.client.getAdapter(adapterName); + if (!adapter) throw new Error(`${adapterName} adapter not detected`); switch (name) { @@ -224,7 +225,11 @@ export const AccountProvider: FC = ({ children }) => { const removeAccount = useCallback( async (accountVal: string) => { - removeAccountFromUser(accountVal); + await removeAccountFromUser(accountVal); + + const account = userData?.accounts.find((w) => w.address === accountVal); + const adapter = wallet.client.getAdapter(account?.walletName ?? ''); + await adapter?.disconnect(); }, [removeAccountFromUser], ); @@ -302,14 +307,20 @@ export const AccountProvider: FC = ({ children }) => { const adapter = wallet.client.getAdapter(adapterName); if (!adapter) throw new Error(`${adapterName} adapter not detected`); - const result = await adapter.connect(); - if (!result) throw new Error(`${adapterName} connection failed`); - console.log('signing via wallet adapter', tx); - const signed = (await adapter.signTransaction(tx)) as ICommand; - console.log('signed', signed); + try { + const result = await adapter.connect({}); + if (!result) throw new Error(`${adapterName} connection failed`); + } catch (e) { + console.log('not connected'); + } - return signed; + try { + const signed = (await adapter.signTransaction(tx)) as ICommand; + return signed; + } catch (e) { + console.log('not signed'); + } }; return ( diff --git a/packages/apps/rwa-demo/src/providers/NetworkProvider/NetworkProvider.tsx b/packages/apps/rwa-demo/src/providers/NetworkProvider/NetworkProvider.tsx index 2724444ce0..87f1dbd2ea 100644 --- a/packages/apps/rwa-demo/src/providers/NetworkProvider/NetworkProvider.tsx +++ b/packages/apps/rwa-demo/src/providers/NetworkProvider/NetworkProvider.tsx @@ -28,7 +28,7 @@ const cache = new InMemoryCache({ const getApolloClient = (network: INetwork) => { const httpLink = new YogaLink({ - endpoint: network?.graphUrl, + endpoint: '/graph', headers: { 'x-api-key': env.GRAPHAPIKEY, 'bypass-tunnel-reminder': env.GRAPHURL, diff --git a/packages/apps/rwa-demo/src/providers/TransactionsProvider/TransactionsProvider.tsx b/packages/apps/rwa-demo/src/providers/TransactionsProvider/TransactionsProvider.tsx index 210f2bff52..5f228c8085 100644 --- a/packages/apps/rwa-demo/src/providers/TransactionsProvider/TransactionsProvider.tsx +++ b/packages/apps/rwa-demo/src/providers/TransactionsProvider/TransactionsProvider.tsx @@ -12,11 +12,13 @@ import { useAsset } from '@/hooks/asset'; import { useNetwork } from '@/hooks/networks'; import { useNotifications } from '@/hooks/notifications'; import { useOrganisation } from '@/hooks/organisation'; +import type { IAddContractProps } from '@/services/createContract'; import { transactionsQuery } from '@/services/graph/transactionSubscription.graph'; import { analyticsEvent } from '@/utils/analytics'; import { interpretMessage } from '@/utils/interpretMessage'; import { RWAStore } from '@/utils/store'; import { useApolloClient } from '@apollo/client'; +import { Dialog, DialogContent } from '@kadena/kode-ui'; import type { FC, PropsWithChildren } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react'; import type { IWalletAccount } from '../AccountProvider/AccountType'; @@ -43,6 +45,7 @@ export const TransactionsProvider: FC = ({ children }) => { useState(null); const [txsButtonRef, setTxsButtonRefData] = useState(null); + const [isTransactionDialog, setIsShowTransactionDialog] = useState(false); const { activeNetwork } = useNetwork(); const store = useMemo(() => { @@ -163,11 +166,12 @@ export const TransactionsProvider: FC = ({ children }) => { type.find((t) => t.name === val.type.name), ); }, - [transactions.length], + [transactions], ); const addTransaction = async ( request: Omit, + newAsset?: IAddContractProps, ): Promise => { const foundExistingTransaction = transactions.find( (v) => v.requestKey === request.requestKey, @@ -178,7 +182,7 @@ export const TransactionsProvider: FC = ({ children }) => { } const data = { ...request, uuid: crypto.randomUUID() }; - await store?.addTransaction(data, asset); + await store?.addTransaction(data, newAsset ? newAsset : asset); return data; }; @@ -252,6 +256,13 @@ export const TransactionsProvider: FC = ({ children }) => { await store?.removeTransaction(data, asset); }; + const showTransactionDialog = () => { + setIsShowTransactionDialog(true); + }; + const hideTransactionDialog = () => { + setIsShowTransactionDialog(false); + }; + return ( = ({ children }) => { txsAnimationRef, isActiveAccountChangeTx, removeTransaction, + showTransactionDialog, + hideTransactionDialog, }} > - {children} + <> + {isTransactionDialog && ( + + + The transaction has been started. Please go to you wallet to sign. + + + )} + {children} + ); }; diff --git a/packages/apps/rwa-demo/src/providers/WalletAdapter/WalletAdapter.tsx b/packages/apps/rwa-demo/src/providers/WalletAdapter/WalletAdapter.tsx index ea29bc124b..a5e66892ff 100644 --- a/packages/apps/rwa-demo/src/providers/WalletAdapter/WalletAdapter.tsx +++ b/packages/apps/rwa-demo/src/providers/WalletAdapter/WalletAdapter.tsx @@ -1,3 +1,4 @@ +import { env } from '@/utils/env'; import { createChainweaverAdapter } from '@kadena/wallet-adapter-chainweaver'; import { createEckoAdapter } from '@kadena/wallet-adapter-ecko'; import { createMagicAdapter } from '@kadena/wallet-adapter-magic'; @@ -18,6 +19,7 @@ export const WalletAdapterProvider = ({ children }: PropsWithChildren) => { }), createChainweaverAdapter({ appName: 'RWA Demo', + walletUrl: env.WALLET_URL, }), createWalletConnectAdapter({ networkId: process.env.NEXT_PUBLIC_NETWORKID, diff --git a/packages/apps/rwa-demo/src/utils/analytics.ts b/packages/apps/rwa-demo/src/utils/analytics.ts index e3ad57d8cb..3f4c9a8e35 100644 --- a/packages/apps/rwa-demo/src/utils/analytics.ts +++ b/packages/apps/rwa-demo/src/utils/analytics.ts @@ -76,7 +76,7 @@ export const analyticsEvent = ( let explorerUrl = options.sentryData.data?.explorerUrl; if ( !explorerUrl && - options.sentryData.captureContext?.extra?.res.requestKey + options.sentryData.captureContext?.extra?.res?.requestKey ) { explorerUrl = `https://explorer.kadena.io/${options.networkId}/transaction/${options.sentryData.captureContext.extra.res.requestKey}`; } diff --git a/packages/apps/rwa-demo/src/utils/checkNetwork.ts b/packages/apps/rwa-demo/src/utils/checkNetwork.ts index 4461706473..1ea74afb44 100644 --- a/packages/apps/rwa-demo/src/utils/checkNetwork.ts +++ b/packages/apps/rwa-demo/src/utils/checkNetwork.ts @@ -1,7 +1,7 @@ import { env } from './env'; export const checkNetwork = (graphUrl: string): Promise => - fetch(graphUrl, { + fetch('/graph', { method: 'POST', headers: { 'x-api-key': env.GRAPHAPIKEY, diff --git a/packages/apps/rwa-demo/src/utils/getAsset.ts b/packages/apps/rwa-demo/src/utils/getAsset.ts index 43774981ea..6736cfcc59 100644 --- a/packages/apps/rwa-demo/src/utils/getAsset.ts +++ b/packages/apps/rwa-demo/src/utils/getAsset.ts @@ -1,6 +1,8 @@ import type { IAsset } from '@/contexts/AssetContext/AssetContext'; -export const getAsset = (asset?: IAsset): string => { +export const getAsset = ( + asset?: Pick, +): string => { // const data = localStorage.getItem( // getLocalStorageKey(LOCALSTORAGE_ASSETS_SELECTED_KEY), // ); diff --git a/packages/apps/rwa-demo/src/utils/store/index.ts b/packages/apps/rwa-demo/src/utils/store/index.ts index 82401a3620..91672ad331 100644 --- a/packages/apps/rwa-demo/src/utils/store/index.ts +++ b/packages/apps/rwa-demo/src/utils/store/index.ts @@ -11,7 +11,9 @@ import { get, off, onValue, ref, remove, set } from 'firebase/database'; import { getAsset } from '../getAsset'; import { database } from './firebase'; -export const getAssetFolder = (asset?: IAsset) => { +export const getAssetFolder = ( + asset?: Pick, +) => { if (!asset) return ''; return getAsset(asset).replace(/\./g, ''); }; @@ -30,7 +32,10 @@ export const RWAStore = (organisation: IOrganisation) => { const dbLocationString = `/organisations/${organisation.id}`; const dbLocationTxString = `/organisationsTxs/${organisation.id}`; - const addTransaction = async (data: ITransaction, asset?: IAsset) => { + const addTransaction = async ( + data: ITransaction, + asset?: Pick, + ) => { const assetFolder = getAssetFolder(asset); if (!assetFolder) return;