Skip to content

Commit

Permalink
fix: certificate persistance and react hook (#172)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidecarpini authored Jan 12, 2024
1 parent 099e540 commit 6c5072d
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 15 deletions.
22 changes: 21 additions & 1 deletion packages/dapp-kit-react/src/DAppKitProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { WalletSource } from '@vechain/dapp-kit';
import { DAppKitUI } from '@vechain/dapp-kit-ui';
import { subscribeKey } from 'valtio/vanilla/utils';
import type { DAppKitProviderOptions, DAppKitContext } from './types';
import { Certificate } from 'thor-devkit';

/**
* Context
Expand Down Expand Up @@ -69,6 +70,8 @@ export const DAppKitProvider: React.FC<DAppKitProviderOptions> = ({
const [source, setSource] = useState<WalletSource | null>(
connex.wallet.state.source,
);
const [connectionCertificate, setConnectionCertificate] =
useState<Certificate | null>(connex.wallet.state.connectionCertificate);

useEffect(() => {
const addressSub = subscribeKey(connex.wallet.state, 'address', (v) => {
Expand All @@ -77,10 +80,18 @@ export const DAppKitProvider: React.FC<DAppKitProviderOptions> = ({
const sourceSub = subscribeKey(connex.wallet.state, 'source', (v) => {
setSource(v);
});
const certificateSub = subscribeKey(
connex.wallet.state,
'connectionCertificate',
(v) => {
setConnectionCertificate(v);
},
);

return () => {
addressSub();
sourceSub();
certificateSub();
};
}, [connex.wallet.state]);

Expand Down Expand Up @@ -110,14 +121,23 @@ export const DAppKitProvider: React.FC<DAppKitProviderOptions> = ({
availableWallets: connex.wallet.state.availableSources,
account,
source,
connectionCertificate,
},
modal: {
open: openModal,
close: closeModal,
onConnectionStatusChange: onModalConnected,
},
};
}, [connex, account, source, closeModal, openModal, onModalConnected]);
}, [
connex,
account,
source,
closeModal,
openModal,
onModalConnected,
connectionCertificate,
]);

return <Context.Provider value={context}>{children}</Context.Provider>;
};
Expand Down
2 changes: 2 additions & 0 deletions packages/dapp-kit-react/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="@vechain/connex" />
import type React from 'react';
import type { Certificate } from 'thor-devkit';
import type { ConnectResponse, WalletSource } from '@vechain/dapp-kit';
import { type DAppKitUIOptions } from '@vechain/dapp-kit-ui';

Expand Down Expand Up @@ -34,6 +35,7 @@ export interface DAppKitContext {
connect: () => Promise<ConnectResponse>;
account: string | null;
source: WalletSource | null;
connectionCertificate: Certificate | null;
};
modal: {
open: () => void;
Expand Down
7 changes: 3 additions & 4 deletions packages/dapp-kit/src/classes/certificate-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { DEFAULT_CONNECT_CERT_MESSAGE } from '../constants';
* A `ConnexWallet` for wallet's that use a certificate connection
*/
class CertificateBasedWallet implements ConnexWallet {
connectionCertificate?: Certificate;
constructor(private readonly wallet: BaseWallet) {}

connect = async (): Promise<ConnectResponse> => {
Expand All @@ -16,7 +15,7 @@ class CertificateBasedWallet implements ConnexWallet {
signature,
} = await this.signCert(cert, {});

this.connectionCertificate = {
const connectionCertificate = {
...cert,
signature,
signer,
Expand All @@ -25,12 +24,12 @@ class CertificateBasedWallet implements ConnexWallet {
};

try {
Certificate.verify(this.connectionCertificate);
Certificate.verify(connectionCertificate);

return {
account: signer,
verified: true,
connectionCertificate: this.connectionCertificate,
connectionCertificate,
};
} catch (e) {
return {
Expand Down
24 changes: 17 additions & 7 deletions packages/dapp-kit/src/classes/wallet-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ class WalletManager {
return wallet;
}

get connectionCertificate(): Certificate | undefined {
return this.wallet.connectionCertificate;
}

// this is needed for wallet connect connections when a connection certificate is required
signConnectionCertificate = async (): Promise<ConnectResponse> => {
const cert = DEFAULT_CONNECT_CERT_MESSAGE;
Expand All @@ -78,7 +74,7 @@ class WalletManager {
signature,
} = await this.wallet.signCert(cert, {});

this.wallet.connectionCertificate = {
const connectionCertificate = {
...cert,
signature,
signer,
Expand All @@ -87,12 +83,13 @@ class WalletManager {
};

try {
Certificate.verify(this.wallet.connectionCertificate);
Certificate.verify(connectionCertificate);
this.state.address = signer;
this.state.connectionCertificate = connectionCertificate;
return {
account: signer,
verified: true,
connectionCertificate: this.connectionCertificate,
connectionCertificate,
};
} catch (e) {
return {
Expand All @@ -117,6 +114,8 @@ class WalletManager {
this.options.walletConnectOptions.modal.askForConnectionCertificate();
} else {
this.state.address = res.account;
this.state.connectionCertificate =
res.connectionCertificate ?? null;
}
return res;
})
Expand All @@ -129,6 +128,7 @@ class WalletManager {
if (!this.state.source) {
this.state.source = null;
this.state.address = null;
this.state.connectionCertificate = null;
return;
}

Expand All @@ -153,6 +153,7 @@ class WalletManager {

this.state.source = null;
this.state.address = null;
this.state.connectionCertificate = null;
};

signTx = (
Expand All @@ -162,6 +163,7 @@ class WalletManager {
this.wallet
.signTx(msg, options)
.then((res) => {
// TODO: we should probably remove these assignment, because the user should be already logged in, and the address should be already defined, test it after e2e with transactions
this.state.address = res.signer;
return res;
})
Expand All @@ -177,6 +179,7 @@ class WalletManager {
this.wallet
.signCert(msg, options)
.then((res) => {
// TODO: we should probably remove these assignment, because the user should be already logged in, and the address should be already defined, test it after e2e with transactions
this.state.address = res.annex.signer;
return res;
})
Expand Down Expand Up @@ -237,16 +240,19 @@ class WalletManager {
source: null,
address: null,
availableSources,
connectionCertificate: null,
});
}

const address = Storage.getAccount();
const source = Storage.getSource();
const connectionCertificate = Storage.getConnectionCertificate();

return proxy({
source,
address,
availableSources,
connectionCertificate,
});
};

Expand All @@ -256,6 +262,10 @@ class WalletManager {
}
this.subscribeToKey('address', Storage.setAccount);
this.subscribeToKey('source', Storage.setSource);
this.subscribeToKey(
'connectionCertificate',
Storage.setConnectionCertificate,
);
};

private getAvailableSources = (): WalletSource[] => {
Expand Down
2 changes: 1 addition & 1 deletion packages/dapp-kit/src/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ type BaseWallet = Connex.Signer & {
*/
type ConnexWallet = BaseWallet & {
connect: () => Promise<ConnectResponse>;
connectionCertificate?: Certificate;
};

interface ConnectResponse {
Expand All @@ -61,6 +60,7 @@ interface WalletManagerState {
source: WalletSource | null;
address: string | null;
availableSources: WalletSource[];
connectionCertificate: Certificate | null;
}

export type {
Expand Down
31 changes: 29 additions & 2 deletions packages/dapp-kit/src/utils/local-storage.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { Certificate } from 'thor-devkit';
import type { WalletSource } from '../types';
import { DAppKitLogger } from './logger';

const STORAGE_PREFIX = 'dappkit@vechain';
const WALLET_SOURCE_KEY = `${STORAGE_PREFIX}/source`;
const ACCOUNT_KEY = `${STORAGE_PREFIX}/account`;
const CERTIFICATE_KEY = `${STORAGE_PREFIX}/connectionCertificate`;

const setSource = (source: WalletSource | null): void => {
DAppKitLogger.debug('LocalStorage', 'setSource', source);
Expand All @@ -24,6 +26,19 @@ const setAccount = (account: string | null): void => {
}
};

const setConnectionCertificate = (certificate: Certificate | null): void => {
DAppKitLogger.debug(
'LocalStorage',
'setConnectionCertificate',
certificate,
);
if (!certificate) {
localStorage.removeItem(CERTIFICATE_KEY);
} else {
localStorage.setItem(CERTIFICATE_KEY, JSON.stringify(certificate));
}
};

const getSource = (): WalletSource | null => {
const source = localStorage.getItem(WALLET_SOURCE_KEY);

Expand All @@ -44,9 +59,21 @@ const getAccount = (): string | null => {
return account;
};

const getConnectionCertificate = (): Certificate | null => {
const connectionCertificate = localStorage.getItem(CERTIFICATE_KEY);

if (!connectionCertificate) {
return null;
}

return JSON.parse(connectionCertificate) as Certificate;
};

export const Storage = {
getAccount,
getSource,
setAccount,
setSource,
setConnectionCertificate,
getAccount,
getSource,
getConnectionCertificate,
};

0 comments on commit 6c5072d

Please sign in to comment.