Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: hub adapter and refactor wallets store #852

Open
wants to merge 1 commit into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion queue-manager/rango-preset/src/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export type WalletBalance = {
};

export type Account = {
balances: WalletBalance[] | null;
address: string;
loading: boolean;
walletType: WalletType;
Expand Down
6 changes: 1 addition & 5 deletions queue-manager/rango-preset/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,8 @@ export interface SwapQueueContext extends QueueContext {
switchNetwork: (
wallet: WalletType,
network: Network
) => Promise<ConnectResult | undefined> | undefined;
) => Promise<ConnectResult | ConnectResult[] | undefined> | undefined;
canSwitchNetworkTo: (type: WalletType, network: Network) => boolean;
connect: (
wallet: WalletType,
network: Network
) => Promise<ConnectResult> | undefined;
state: (type: WalletType) => WalletState;
isMobileWallet: (type: WalletType) => boolean;

Expand Down
3 changes: 3 additions & 0 deletions wallets/core/src/hub/mod.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export { Namespace } from './namespaces/mod.js';

export { Provider } from './provider/mod.js';
export type { CommonNamespaces, CommonNamespaceKeys } from './provider/mod.js';

export { Hub } from './hub.js';
export type { Store, State, ProviderInfo } from './store/mod.js';
export {
Expand Down
5 changes: 4 additions & 1 deletion wallets/core/src/hub/namespaces/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,10 @@ class Namespace<T extends Actions<T>> {
return orAction(context, prev);
}, actionError);
} catch (orError) {
throw new Error(OR_ELSE_ACTION_FAILED_ERROR(actionName.toString()), {
const errorMessage = OR_ELSE_ACTION_FAILED_ERROR(
`${actionName.toString()} for ${this.namespaceId} namespace.`
);
throw new Error(errorMessage, {
cause: actionError,
});
}
Expand Down
1 change: 1 addition & 0 deletions wallets/core/src/hub/provider/mod.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type {
ExtendableInternalActions,
CommonNamespaces,
CommonNamespaceKeys,
State,
Context,
ProviderBuilderOptions,
Expand Down
8 changes: 6 additions & 2 deletions wallets/core/src/hub/provider/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { FindProxiedNamespace } from '../../builders/mod.js';
import type { Store } from '../../hub/mod.js';
import type { LegacyState } from '../../legacy/mod.js';
import type { NamespaceInterface, Store } from '../../mod.js';
import type { CosmosActions } from '../../namespaces/cosmos/mod.js';
import type { EvmActions } from '../../namespaces/evm/mod.js';
import type { SolanaActions } from '../../namespaces/solana/mod.js';
import type { AnyFunction, FunctionWithContext } from '../../types/actions.js';
import type { Prettify } from '../../types/utils.js';

export type Context = {
state: () => [GetState, SetState];
Expand All @@ -25,13 +27,15 @@ export interface CommonNamespaces {
cosmos: CosmosActions;
}

export type CommonNamespaceKeys = Prettify<keyof CommonNamespaces>;

export interface ExtendableInternalActions {
init?: FunctionWithContext<AnyFunction, Context>;
}

export type RegisteredNamespaces<K extends keyof T, T> = Map<
K,
NamespaceInterface<K, T>
FindProxiedNamespace<K, T>
>;

export type ProviderBuilderOptions = { store?: Store };
12 changes: 3 additions & 9 deletions wallets/core/src/hub/store/providers.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import type {
CommonNamespaces,
State as InternalProviderState,
} from '../provider/mod.js';
import type { State as InternalProviderState } from '../provider/mod.js';
import type { CommonNamespaceKeys } from '../provider/types.js';
import type { StateCreator } from 'zustand';

import { produce } from 'immer';

import { guessProviderStateSelector, type State } from './mod.js';

type NamespaceName =
| keyof CommonNamespaces
| Omit<string, keyof CommonNamespaces>;

type Browsers = 'firefox' | 'chrome' | 'edge' | 'brave' | 'homepage';
type Property<N extends string, V> = { name: N; value: V };
type DetachedInstances = Property<'detached', NamespaceName[]>;
type DetachedInstances = Property<'detached', CommonNamespaceKeys[]>;

export type ProviderInfo = {
name: string;
Expand Down
9 changes: 9 additions & 0 deletions wallets/core/src/legacy/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export type {
InstallObjects as LegacyInstallObjects,
WalletInfo as LegacyWalletInfo,
ConnectResult as LegacyConnectResult,
NamespaceInputForConnect as LegacyNamespaceInputForConnect,
NamespaceInputWithDiscoverMode as LegacyNamespaceInputWithDiscoverMode,
} from './types.js';

export {
Expand All @@ -35,5 +37,12 @@ export { Persistor } from './persistor.js';
export {
readAccountAddress as legacyReadAccountAddress,
getBlockChainNameFromId as legacyGetBlockChainNameFromId,
formatAddressWithNetwork as legacyFormatAddressWithNetwork,
} from './helpers.js';
export { default as LegacyWallet } from './wallet.js';

export {
eagerConnectHandler as legacyEagerConnectHandler,
isNamespaceDiscoverMode as legacyIsNamespaceDiscoverMode,
isEvmNamespace as legacyIsEvmNamespace,
} from './utils.js';
42 changes: 42 additions & 0 deletions wallets/core/src/legacy/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ export type WalletInfo = {
name: string;
img: string;
installLink: InstallObjects | string;
/**
* @deprecated we don't use this value anymore.
*/
color: string;
supportedChains: BlockchainMeta[];
showOnMobile?: boolean;
Expand Down Expand Up @@ -202,6 +205,12 @@ export type CanEagerConnect = (options: {
meta: BlockchainMeta[];
}) => Promise<boolean>;

export type EagerConnectResult<I = unknown> = {
accounts: string[] | null;
network: string | null;
provider: I | null;
};

export interface WalletActions {
connect: Connect;
getInstance: any;
Expand Down Expand Up @@ -235,3 +244,36 @@ export type WalletProviders = Map<
>;

export type ProviderInterface = { config: WalletConfig } & WalletActions;

// it comes from wallets.ts and `connect`
type NetworkTypeFromLegacyConnect = Network | undefined;

export type NetworkTypeForNamespace<T extends NamespacesWithDiscoverMode> =
T extends 'DISCOVER_MODE'
? string
: T extends Namespace
? NetworkTypeFromLegacyConnect
: never;

export type NamespacesWithDiscoverMode = Namespace | 'DISCOVER_MODE';

export type NamespaceInputWithDiscoverMode = {
namespace: 'DISCOVER_MODE';
network: string;
derivationPath?: string;
};

export type NamespaceInputForConnect<T extends Namespace = Namespace> =
| {
/**
* By default, you should specify namespace (e.g. evm).
* For backward compatibility with legacy implementation, DISCOVER_MODE will try to map a list of known (and hardcoded) networks to a namespace.
*/
namespace: T;
/**
* In some cases, we need to connect a specific network on a namespace. e.g. Polygon on EVM.
*/
network: NetworkTypeForNamespace<T>;
derivationPath?: string;
}
| NamespaceInputWithDiscoverMode;
31 changes: 31 additions & 0 deletions wallets/core/src/legacy/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type {
NamespaceInputForConnect,
NamespaceInputWithDiscoverMode,
} from './types.js';

import { Namespace } from './types.js';

export async function eagerConnectHandler<R = unknown>(params: {
canEagerConnect: () => Promise<boolean>;
connectHandler: () => Promise<R>;
providerName: string;
}) {
// Check if we can eagerly connect to the wallet
if (await params.canEagerConnect()) {
// Connect to wallet as usual
return await params.connectHandler();
}
throw new Error(`can't restore connection for ${params.providerName}.`);
}

export function isNamespaceDiscoverMode(
namespace: NamespaceInputForConnect
): namespace is NamespaceInputWithDiscoverMode {
return namespace.namespace === 'DISCOVER_MODE';
}

export function isEvmNamespace(
namespace: NamespaceInputForConnect
): namespace is NamespaceInputForConnect<Namespace.Evm> {
return namespace.namespace === Namespace.Evm;
}
45 changes: 29 additions & 16 deletions wallets/core/src/legacy/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
EagerConnectResult,
GetInstanceOptions,
NamespaceData,
Network,
Expand All @@ -14,6 +15,7 @@ import {
needsCheckInstallation,
} from './helpers.js';
import { Events, Networks } from './types.js';
import { eagerConnectHandler } from './utils.js';

export type EventHandler = (
type: WalletType,
Expand All @@ -26,11 +28,16 @@ export type EventHandler = (
export type EventInfo = {
supportedBlockchains: BlockchainMeta[];
isContractWallet: boolean;
// This is for Hub and be able to make it compatible with legacy behavior.
isHub: boolean;
};

export interface State {
connected: boolean;
connecting: boolean;
/**
* @depreacted it always returns `false`. don't use it.
*/
reachable: boolean;
installed: boolean;
accounts: string[] | null;
Expand All @@ -57,6 +64,7 @@ class Wallet<InstanceType = any> {
this.info = {
supportedBlockchains: [],
isContractWallet: false,
isHub: false,
};
this.state = {
connected: false,
Expand Down Expand Up @@ -264,26 +272,30 @@ class Wallet<InstanceType = any> {
}

// This method is only used for auto connection
async eagerConnect() {
async eagerConnect(): Promise<EagerConnectResult<InstanceType>> {
const instance = await this.tryGetInstance({ network: undefined });
const { canEagerConnect } = this.actions;
const error_message = `can't restore connection for ${this.options.config.type} .`;
const providerName = this.options.config.type;

if (canEagerConnect) {
// Check if we can eagerly connect to the wallet
const eagerConnection = await canEagerConnect({
instance: instance,
meta: this.info.supportedBlockchains,
});
return await eagerConnectHandler({
canEagerConnect: async () => {
if (!canEagerConnect) {
throw new Error(
`${providerName} provider hasn't implemented canEagerConnect.`
);
}

if (eagerConnection) {
// Connect to wallet as usual
return this.connect();
}
throw new Error(error_message);
} else {
throw new Error(error_message);
}
return await canEagerConnect({
instance: instance,
meta: this.info.supportedBlockchains,
});
},
connectHandler: async () => {
const result = await this.connect();
return result;
},
providerName,
});
}

async getSigners(provider: any) {
Expand Down Expand Up @@ -408,6 +420,7 @@ class Wallet<InstanceType = any> {
const eventInfo: EventInfo = {
supportedBlockchains: this.info.supportedBlockchains,
isContractWallet: this.info.isContractWallet,
isHub: false,
};
this.options.handler(
this.options.config.type,
Expand Down
16 changes: 10 additions & 6 deletions wallets/core/src/mod.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
export type { Store, State, ProviderInfo } from './hub/mod.js';
export type {
Store,
State,
ProviderInfo,
CommonNamespaces,
CommonNamespaceKeys,
} from './hub/mod.js';
export {
Hub,
Provider,
Expand All @@ -7,10 +13,8 @@ export {
guessProviderStateSelector,
namespaceStateSelector,
} from './hub/mod.js';
export type {
ProxiedNamespace,
FindProxiedNamespace as NamespaceInterface,
} from './builders/mod.js';

export type { ProxiedNamespace, FindProxiedNamespace } from './builders/mod.js';
export {
NamespaceBuilder,
ProviderBuilder,
Expand All @@ -31,5 +35,5 @@ export {
* To make it work for Parcel, we should go with second mentioned option.
*
*/
export type { Versions } from './utils/mod.js';
export type { VersionedProviders } from './utils/mod.js';
export { defineVersions, pickVersion } from './utils/mod.js';
6 changes: 6 additions & 0 deletions wallets/core/src/namespaces/common/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ export {
recommended as andRecommended,
} from './and.js';
export { intoConnecting, recommended as beforeRecommended } from './before.js';

export type {
CaipAccount,
Accounts,
AccountsWithActiveChain,
} from '../../types/accounts.js';
1 change: 1 addition & 0 deletions wallets/core/src/namespaces/cosmos/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export interface CosmosActions
extends AutoImplementedActionsByRecommended,
CommonActions {
// TODO
connect: () => Promise<string>;
}
Loading