update eager connect hook and make app concerned with selected pubkey, refactor token to be stored as object
This commit is contained in:
parent
1e6900d147
commit
84af6177ad
@ -1,14 +1,16 @@
|
||||
import { Callout, Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { useVegaWallet } from '@vegaprotocol/react-helpers';
|
||||
import { useEffect } from 'react';
|
||||
import { rest } from '../lib/connectors';
|
||||
import { useVegaWallet, VegaKeyExtended } from '@vegaprotocol/react-helpers';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Connectors, rest } from '../lib/connectors';
|
||||
import { LocalStorage } from '@vegaprotocol/storage';
|
||||
|
||||
export function Index() {
|
||||
// Get keys from vega wallet immediately
|
||||
useEagerConnect();
|
||||
|
||||
const { publicKey, publicKeys, selectPublicKey } = useVegaWallet();
|
||||
const { publicKeys } = useVegaWallet();
|
||||
const { publicKey, onSelect } = useCurrentVegaKey();
|
||||
|
||||
return (
|
||||
<div className="m-24 ">
|
||||
@ -31,7 +33,7 @@ export function Index() {
|
||||
<select
|
||||
name="change-key"
|
||||
value={publicKey?.pub}
|
||||
onChange={(e) => selectPublicKey(e.target.value)}
|
||||
onChange={(e) => onSelect(e.target.value)}
|
||||
>
|
||||
{publicKeys.map((pk) => (
|
||||
<option key={pk.pub} value={pk.pub}>
|
||||
@ -53,9 +55,53 @@ function useEagerConnect() {
|
||||
const { connect } = useVegaWallet();
|
||||
|
||||
useEffect(() => {
|
||||
// Might be safer to store connector name and eager connect using that
|
||||
if (LocalStorage.getItem('vega_wallet_token')) {
|
||||
connect(rest);
|
||||
const cfg = LocalStorage.getItem('vega_wallet');
|
||||
const cfgObj = JSON.parse(cfg);
|
||||
|
||||
// No stored config, user has never connected or manually cleared storage
|
||||
if (!cfgObj || !cfgObj.connector) {
|
||||
return;
|
||||
}
|
||||
|
||||
const connector = Connectors[cfgObj.connector];
|
||||
|
||||
// Developer hasn't provided this connector
|
||||
if (!connector) {
|
||||
throw new Error(`Connector ${cfgObj?.connector} not configured`);
|
||||
}
|
||||
|
||||
connect(Connectors[cfgObj.connector]);
|
||||
}, [connect]);
|
||||
}
|
||||
|
||||
function useCurrentVegaKey(): {
|
||||
publicKey: VegaKeyExtended | null;
|
||||
onSelect: (pk: string) => void;
|
||||
} {
|
||||
const { publicKeys } = useVegaWallet();
|
||||
const [pk, setPk] = useState<string | null>(() =>
|
||||
LocalStorage.getItem('vega_selected_publickey')
|
||||
);
|
||||
|
||||
const publicKey = useMemo(() => {
|
||||
if (!publicKeys?.length) return null;
|
||||
|
||||
const found = publicKeys.find((x) => x.pub === pk);
|
||||
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [pk, publicKeys]);
|
||||
|
||||
// on public key change set to localStorage
|
||||
useEffect(() => {
|
||||
LocalStorage.setItem('vega_selected_publickey', pk);
|
||||
}, [pk]);
|
||||
|
||||
return {
|
||||
publicKey,
|
||||
onSelect: setPk,
|
||||
};
|
||||
}
|
||||
|
@ -17,9 +17,13 @@ export function VegaConnectDialog({
|
||||
setDialogOpen,
|
||||
}: VegaConnectDialogProps) {
|
||||
const { connect } = useVegaWallet();
|
||||
|
||||
// Selected connector, we need to show the auth form if the rest connector (which is
|
||||
// currently the only way to connect) is selected.
|
||||
const [selectedConnector, setSelectedConnector] =
|
||||
useState<VegaConnector | null>(null);
|
||||
|
||||
// Connects with the provided connector instance and closes the modal
|
||||
const connectAndClose = useCallback(
|
||||
(connector: VegaConnector) => {
|
||||
connect(connector);
|
||||
@ -28,6 +32,8 @@ export function VegaConnectDialog({
|
||||
[connect, setDialogOpen]
|
||||
);
|
||||
|
||||
// Effect to immediately connect if the selected connector is NOT a
|
||||
// rest connector
|
||||
useEffect(() => {
|
||||
if (
|
||||
selectedConnector !== null &&
|
||||
|
@ -7,37 +7,58 @@ import {
|
||||
import { LocalStorage } from '@vegaprotocol/storage';
|
||||
|
||||
export interface VegaConnector {
|
||||
/** Connect to wallet and return keys */
|
||||
connect(): Promise<VegaKey[] | null>;
|
||||
/** Disconnect from wallet */
|
||||
disconnect(): Promise<void>;
|
||||
}
|
||||
|
||||
// Perhaps there should be a default ConnectorConfig that others can extend off. Do all connectors
|
||||
// need to use local storage, I don't think so...
|
||||
interface RestConnectorConfig {
|
||||
token: string | null;
|
||||
connector: 'rest';
|
||||
}
|
||||
|
||||
/**
|
||||
* Connector for using the Vega Wallet Service rest api, requires authentication to get a session token
|
||||
*/
|
||||
export class RestConnector implements VegaConnector {
|
||||
static storageKey = 'vega_wallet';
|
||||
apiConfig: Configuration;
|
||||
service: DefaultApi;
|
||||
|
||||
constructor() {
|
||||
this.apiConfig = createConfiguration({
|
||||
authMethods: {
|
||||
bearer: `Bearer ${LocalStorage.getItem('vega_wallet_token')}`,
|
||||
},
|
||||
});
|
||||
const cfg = this.getConfig();
|
||||
|
||||
// If theres a stored auth token create api config with bearer authMethod
|
||||
this.apiConfig = cfg?.token
|
||||
? createConfiguration({
|
||||
authMethods: {
|
||||
bearer: `Bearer ${cfg.token}`,
|
||||
},
|
||||
})
|
||||
: createConfiguration();
|
||||
|
||||
this.service = new DefaultApi(this.apiConfig);
|
||||
}
|
||||
|
||||
async authenticate(params: { wallet: string; passphrase: string }) {
|
||||
try {
|
||||
const tokenRes = await this.service.authTokenPost(params);
|
||||
const res = await this.service.authTokenPost(params);
|
||||
|
||||
// Renew DefaultApi now we have the token
|
||||
// Renew service instance with default bearer authMethod now that we have the token
|
||||
this.service = new DefaultApi(
|
||||
createConfiguration({
|
||||
authMethods: {
|
||||
bearer: `Bearer ${tokenRes.token}`,
|
||||
bearer: `Bearer ${res.token}`,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
LocalStorage.setItem('vega_wallet_token', tokenRes.token);
|
||||
// Store the token, and other things for later
|
||||
this.setConfig({ connector: 'rest', token: res.token });
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@ -52,7 +73,7 @@ export class RestConnector implements VegaConnector {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// keysGet failed, its likely that the session has expired so remove the token from storage
|
||||
LocalStorage.removeItem('vega_wallet_token');
|
||||
this.clearConfig();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -63,12 +84,38 @@ export class RestConnector implements VegaConnector {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
// Always clear the tokens
|
||||
LocalStorage.removeItem('vega_wallet_token');
|
||||
// Always clear config, if authTokenDelete fails the user still tried to
|
||||
// connect so clear the config (and containing token) from storage
|
||||
this.clearConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private setConfig(cfg: RestConnectorConfig) {
|
||||
LocalStorage.setItem(RestConnector.storageKey, JSON.stringify(cfg));
|
||||
}
|
||||
|
||||
private getConfig(): RestConnectorConfig | null {
|
||||
const cfg = LocalStorage.getItem(RestConnector.storageKey);
|
||||
if (cfg) {
|
||||
try {
|
||||
const obj = JSON.parse(cfg);
|
||||
return obj;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private clearConfig() {
|
||||
LocalStorage.removeItem(RestConnector.storageKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy injected connector that we may use when browser wallet is implemented
|
||||
*/
|
||||
export class InjectedConnector implements VegaConnector {
|
||||
async connect() {
|
||||
return [
|
||||
|
@ -7,9 +7,6 @@ export interface VegaKeyExtended extends VegaKey {
|
||||
}
|
||||
|
||||
export interface VegaWalletContextShape {
|
||||
/** The current select public key */
|
||||
publicKey: VegaKeyExtended | null;
|
||||
|
||||
/** Public keys stored in users wallet */
|
||||
publicKeys: VegaKeyExtended[] | null;
|
||||
|
||||
@ -19,9 +16,6 @@ export interface VegaWalletContextShape {
|
||||
/** Disconnects from the connector and clears public key state */
|
||||
disconnect: () => Promise<void>;
|
||||
|
||||
/** Sets the current selected public key */
|
||||
selectPublicKey: (publicKey: string) => void;
|
||||
|
||||
/** Reference to the connector */
|
||||
connector: VegaConnector | null;
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ interface VegaWalletProviderProps {
|
||||
}
|
||||
|
||||
export const VegaWalletProvider = ({ children }: VegaWalletProviderProps) => {
|
||||
const [publicKey, setPublicKey] = useState<VegaKeyExtended | null>(null);
|
||||
const [publicKeys, setPublicKeys] = useState<VegaKeyExtended[] | null>(null);
|
||||
const connector = useRef<VegaConnector | null>(null);
|
||||
|
||||
@ -16,6 +15,12 @@ export const VegaWalletProvider = ({ children }: VegaWalletProviderProps) => {
|
||||
connector.current = c;
|
||||
try {
|
||||
const res = await connector.current.connect();
|
||||
|
||||
if (!res) {
|
||||
console.log('connect failed', res);
|
||||
return;
|
||||
}
|
||||
|
||||
const publicKeysWithName = res.map((pk) => {
|
||||
const nameMeta = pk.meta?.find((m) => m.key === 'name');
|
||||
return {
|
||||
@ -24,7 +29,6 @@ export const VegaWalletProvider = ({ children }: VegaWalletProviderProps) => {
|
||||
};
|
||||
});
|
||||
setPublicKeys(publicKeysWithName);
|
||||
setPublicKey(publicKeysWithName[0]);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
@ -34,40 +38,20 @@ export const VegaWalletProvider = ({ children }: VegaWalletProviderProps) => {
|
||||
try {
|
||||
await connector.current?.disconnect();
|
||||
setPublicKeys(null);
|
||||
setPublicKey(null);
|
||||
connector.current = null;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const selectPublicKey = useCallback(
|
||||
(key: string) => {
|
||||
if (!publicKeys || !publicKeys.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedKey = publicKeys.find((k) => k.pub === key);
|
||||
|
||||
if (!selectedKey) {
|
||||
throw new Error('Public key doesnt exist');
|
||||
}
|
||||
|
||||
setPublicKey(selectedKey);
|
||||
},
|
||||
[publicKeys]
|
||||
);
|
||||
|
||||
const contextValue = useMemo<VegaWalletContextShape>(() => {
|
||||
return {
|
||||
publicKey,
|
||||
publicKeys,
|
||||
selectPublicKey,
|
||||
connect,
|
||||
disconnect,
|
||||
connector: connector.current,
|
||||
};
|
||||
}, [publicKey, publicKeys, selectPublicKey, connect, disconnect, connector]);
|
||||
}, [publicKeys, connect, disconnect, connector]);
|
||||
|
||||
return (
|
||||
<VegaWalletContext.Provider value={contextValue}>
|
||||
|
@ -20,6 +20,7 @@ export function RestConnectorForm({
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<FormFields>({
|
||||
// TODO: Remove default values
|
||||
defaultValues: {
|
||||
wallet: 'test6',
|
||||
passphrase: '123',
|
||||
|
Loading…
Reference in New Issue
Block a user