Skip to content

Commit

Permalink
Merge pull request #24 from vechainfoundation/remove-common-logic-fro…
Browse files Browse the repository at this point in the history
…m-react

Remove common logic from react
  • Loading branch information
davidecarpini authored Oct 26, 2023
2 parents ba76aa1 + 9c9a9eb commit e4986b4
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 304 deletions.
2 changes: 1 addition & 1 deletion apps/sample-react-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const nodeOptions: Omit<Options, 'signer'> = {
};

const walletConnectOptions: WalletConnectOptions = {
projectId: '8dfc5cac972ee656e6edeb8309ab30ec',
projectId: 'a0b855ceaf109dbc8426479a4c3d38d8',
metadata: {
name: 'Sample VeChain dApp',
description: 'A sample VeChain dApp',
Expand Down
2 changes: 2 additions & 0 deletions apps/sample-react-app/src/Components/ConnectWalletModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ const ConnectedWalletBody: React.FC<ConnectedWalletBodyProps> = ({
},
};

if (!vendor) throw new Error('Vendor not available');

const certResponse = await vendor.sign('cert', message).request();

const cert: Certificate = {
Expand Down
11 changes: 5 additions & 6 deletions apps/sample-react-app/src/Hooks/useCounter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ interface UseCounter {
}

export const useCounter = (): UseCounter => {
const { vendor, thor } = useConnex();
const { thor } = useConnex();

const [count, setCount] = useState<number>(0);
const [status, setStatus] = useState<IncrementStatus>('idle');
Expand All @@ -55,12 +55,11 @@ export const useCounter = (): UseCounter => {
}, [setValue]);

const increment = useCallback(async (): Promise<void> => {
const clause = contract.method(_increment).asClause();

setStatus('in-wallet');

await vendor
.sign('tx', [clause])
await contract
.method(_increment)
.transact()
.delegate('https://sponsor-testnet.vechain.energy/by/90')
.request();

Expand All @@ -71,7 +70,7 @@ export const useCounter = (): UseCounter => {
await setValue()
.then(() => setStatus('idle'))
.catch(() => setStatus('error'));
}, [thor, vendor, contract, setValue]);
}, [thor, contract, setValue]);

return { count, increment, status, address: contract.address };
};
199 changes: 44 additions & 155 deletions packages/react-wallet-kit/src/ConnexProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,11 @@ import React, {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useReducer,
useRef,
} from 'react';
import { Connex } from '@vechain/connex';
import { newVendor } from '@vechain/connex-framework';
import type { WalletConnectOptions, WCSigner } from '@vechain/wallet-connect';
import {
newWcClient,
newWcSigner,
newWeb3Modal,
} from '@vechain/wallet-connect';
import { WalletSource } from '@vechain/wallet-kit';
import type { ConnexInstance } from '@vechain/wallet-kit';
import { createConnexInstance, WalletSource } from '@vechain/wallet-kit';
import { accountReducer, defaultAccountState } from './AccountReducer';
import type {
ConnexContext,
Expand All @@ -40,18 +31,35 @@ export const ConnexProvider: React.FC<ConnexProviderOptions> = ({
defaultAccountState,
);

const wcSignerRef = useRef<WCSigner | undefined>();
const onDisconnected = useCallback((): void => {
dispatch({ type: 'clear' });
}, []);

const disconnectMobile = useCallback(() => {
const client = wcSignerRef.current;
const connexInstance: ConnexInstance = useMemo(
() =>
createConnexInstance({
nodeUrl: nodeOptions.node,
genesis: nodeOptions.network,
source: accountState.source ?? undefined,
walletConnectOptions,
onDisconnected,
}),
//eslint-disable-next-line react-hooks/exhaustive-deps
[
nodeOptions.node,
nodeOptions.network,
walletConnectOptions,
onDisconnected,
],
);

if (client) {
client.disconnect().catch((err) => {
throw err;
});
wcSignerRef.current = undefined;
}
}, []);
const disconnect = useCallback((): void => {
dispatch({ type: 'clear' });

connexInstance.disconnect().catch(() => {
// do nothing
});
}, [connexInstance]);

const availableWallets = useMemo(() => {
const wallets: WalletSource[] = [WalletSource.Sync2];
Expand All @@ -71,132 +79,19 @@ export const ConnexProvider: React.FC<ConnexProviderOptions> = ({
return wallets;
}, [walletConnectOptions]);

const onDisconnected = useCallback((): void => {
if (accountState.source === WalletSource.WalletConnect) {
disconnectMobile();
}

dispatch({ type: 'clear' });
}, [disconnectMobile, accountState]);

useEffect(() => {
if (
accountState.source === WalletSource.WalletConnect &&
!walletConnectOptions
) {
onDisconnected();
}

if (
accountState.source === WalletSource.VeWorldExtension &&
!window.vechain
) {
onDisconnected();
}
}, [accountState, walletConnectOptions, onDisconnected]);

const updateSource: SetSource = useCallback(
const setSource: SetSource = useCallback(
(wallet: WalletSource): void => {
// We can't set VeWorld Mobile if there is no Wallet Connect config
if (
wallet === WalletSource.WalletConnect &&
!walletConnectOptions
) {
throw new Error('Wallet Connect config not found');
}

// We can't set VeWorld Extension if there is no VeChain extension
if (wallet === WalletSource.VeWorldExtension && !window.vechain) {
throw new Error('VeWorld extension not found');
}
connexInstance.setSource(wallet);

dispatch({
type: 'set-wallet-source',
payload: { source: wallet, persist: persistState },
});
},
[walletConnectOptions, persistState],
);

const thor: Connex.Thor = useMemo(
() => new Connex.Thor(nodeOptions),
[nodeOptions],
[connexInstance, persistState],
);

const createWalletConnectVendor = useCallback(
(options: WalletConnectOptions) => {
const { projectId, metadata } = options;

const wcClient = newWcClient({
projectId,
metadata,
});

const web3Modal = newWeb3Modal(projectId);

const wcSigner: WCSigner = newWcSigner({
genesisId: thor.genesis.id,
wcClient,
web3Modal,
onDisconnected,
});

wcSignerRef.current = wcSigner;

return newVendor(wcSigner);
},
[onDisconnected, thor.genesis.id],
);

/**
* Create the vendor
* Create a vendor for the provided options. If that vendor is not available, the priority is:
* 1. Wallet Connect - If the options are provided
* 2. VeWorld Extension - If the extension is available
* 3. Sync2 - As a fallback, as it is always available
*/
const vendor: Connex.Vendor = useMemo(() => {
const { source } = accountState;

if (source === WalletSource.WalletConnect && walletConnectOptions) {
return createWalletConnectVendor(walletConnectOptions);
}

if (source === WalletSource.Sync2 || source === WalletSource.Sync) {
return new Connex.Vendor(thor.genesis.id, source);
}

if (source === WalletSource.VeWorldExtension && window.vechain) {
const extensionSigner = window.vechain.newConnexSigner(
thor.genesis.id,
);

return newVendor(extensionSigner);
}

// We've exhausted all options, so default to Wallet Connect if the options are provided
if (walletConnectOptions) {
return createWalletConnectVendor(walletConnectOptions);
}

// No wallet connect options, so use the extension if it's available
if (window.vechain) {
const extensionSigner: Connex.Signer =
window.vechain.newConnexSigner(thor.genesis.id);

return newVendor(extensionSigner);
}

// Default to Sync2
return new Connex.Vendor(thor.genesis.id, WalletSource.Sync2);
}, [
createWalletConnectVendor,
thor.genesis.id,
walletConnectOptions,
accountState,
]);

const updateAccount: SetAccount = useCallback(
const setAccount: SetAccount = useCallback(
(address: string) => {
dispatch({
type: 'set-address',
Expand All @@ -206,40 +101,34 @@ export const ConnexProvider: React.FC<ConnexProviderOptions> = ({
[persistState],
);

const wallets: WalletSource[] = useMemo(() => {
return Object.values(WalletSource);
}, []);

const context: ConnexContext = useMemo(() => {
return {
connex: {
thor,
vendor,
thor: connexInstance.thor,
vendor: connexInstance.vendor,
},
wallet: {
setSource: updateSource,
setAccount: updateAccount,
setSource,
setAccount,
availableWallets,
wallets,
wallets: Object.values(WalletSource),
accountState,
disconnect: onDisconnected,
disconnect,
},
};
}, [
onDisconnected,
updateAccount,
accountState,
thor,
vendor,
updateSource,
wallets,
connexInstance,
setAccount,
setSource,
availableWallets,
disconnect,
]);

return <Context.Provider value={context}>{children}</Context.Provider>;
};

export const useConnex = (): Connex => {
export const useConnex = (): ConnexContext['connex'] => {
const context = useContext(Context);
return context.connex;
};
Expand Down
12 changes: 4 additions & 8 deletions packages/react-wallet-kit/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,13 @@ export interface ConnexProviderOptions {
* Connex Context
* This context is used to provide the Connex instance and the Connex Vendor instance
* to the application.
*
* @param thor - {@link Connex.Thor}: used to interact with the blockchain
* @param vendor - {@link Connex.Vendor}: used to interact with the wallet
* @param setWallet - used to set the wallet source
* @param availableWallets - list of available wallets
* @param accountState - current account state
* @param dispatch - used to dispatch account actions
*/

export interface ConnexContext {
connex: Connex;
connex: {
thor: Connex.Thor;
vendor?: Connex.Vendor;
};
wallet: {
setSource: SetSource;
setAccount: SetAccount;
Expand Down
4 changes: 2 additions & 2 deletions packages/wallet-connect/src/signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { EngineTypes } from '@walletconnect/types/dist/types/sign-client/en
import { getSdkError } from '@walletconnect/utils';
import type { SignClient } from '@walletconnect/sign-client/dist/types/client';
import type { WCSigner, WCSignerOptions } from './types';
import { DefaultEvents, DefaultMethods } from './constants';
import { DefaultMethods } from './constants';

interface SessionAccount {
networkIdentifier: string;
Expand Down Expand Up @@ -136,7 +136,7 @@ export const newWcSigner = ({
const namespace: ProposalTypes.RequiredNamespace = {
methods: Object.values(DefaultMethods),
chains: [chainId],
events: Object.values(DefaultEvents),
events: [],
};

try {
Expand Down
Loading

0 comments on commit e4986b4

Please sign in to comment.