@effectstream/wallets 0.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +30 -0
- package/src/IProvider.ts +62 -0
- package/src/algorand/algorand.ts +168 -0
- package/src/algorand/wrapper.ts +22 -0
- package/src/avail/avail.ts +81 -0
- package/src/avail/wrapper.ts +44 -0
- package/src/cardano/cardano.ts +194 -0
- package/src/cardano/wrapper.ts +34 -0
- package/src/effectstream.ts +382 -0
- package/src/evm/ethers.ts +104 -0
- package/src/evm/injected.ts +429 -0
- package/src/evm/types.ts +2 -0
- package/src/evm/wrapper-ethers.ts +49 -0
- package/src/evm/wrapper-injected.ts +103 -0
- package/src/midnight/midnight.ts +196 -0
- package/src/midnight/wrapper.ts +36 -0
- package/src/mina/mina.ts +175 -0
- package/src/mina/wrapper.ts +22 -0
- package/src/mod.ts +10 -0
- package/src/polkadot/polkadot.ts +166 -0
- package/src/polkadot/wrapper.ts +30 -0
- package/src/types.ts +61 -0
- package/src/utils.test.ts +64 -0
- package/src/utils.ts +133 -0
- package/src/wallet-modes.ts +124 -0
- package/src/wallets.ts +62 -0
- package/src/windows.ts +10 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { test, expect } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
connectInjectedWallet,
|
|
4
|
+
} from "./utils.ts";
|
|
5
|
+
import type { IInjectedConnector, IProvider } from "./IProvider.ts";
|
|
6
|
+
import { AddressType } from "@effectstream/utils";
|
|
7
|
+
|
|
8
|
+
const MOCK_ADDRESS = "0xmock";
|
|
9
|
+
const MOCK_METADATA = { name: "MockWallet", displayName: "Mock Wallet", icon: "", version: "1.0" };
|
|
10
|
+
|
|
11
|
+
// Mock provider
|
|
12
|
+
const createMockProvider = (): IProvider<unknown> => ({
|
|
13
|
+
getConnection: () => ({ metadata: MOCK_METADATA, api: {} }),
|
|
14
|
+
getAddress: () => ({ type: AddressType.EVM, address: MOCK_ADDRESS }),
|
|
15
|
+
signMessage: async () => "0xsig",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Mock connector
|
|
19
|
+
const createMockConnector = (shouldFail = false): IInjectedConnector<unknown> => ({
|
|
20
|
+
connectSimple: async () => {
|
|
21
|
+
if (shouldFail) throw new Error("Simple connect failed");
|
|
22
|
+
return createMockProvider();
|
|
23
|
+
},
|
|
24
|
+
connectNamed: async (name: string) => {
|
|
25
|
+
if (shouldFail) throw new Error(`Named connect to ${name} failed`);
|
|
26
|
+
return createMockProvider();
|
|
27
|
+
},
|
|
28
|
+
connectExternal: async () => {
|
|
29
|
+
if (shouldFail) throw new Error("External connect failed");
|
|
30
|
+
return createMockProvider();
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("connectInjectedWallet - simple login success", async () => {
|
|
35
|
+
const connector = createMockConnector();
|
|
36
|
+
const provider = await connectInjectedWallet("Test", undefined, connector);
|
|
37
|
+
expect(provider.getAddress().address).toEqual(MOCK_ADDRESS);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("connectInjectedWallet - named login success", async () => {
|
|
41
|
+
const connector = createMockConnector();
|
|
42
|
+
const preference = { name: "MockWallet" };
|
|
43
|
+
const provider = await connectInjectedWallet("Test", preference, connector);
|
|
44
|
+
expect(provider.getAddress().address).toEqual(MOCK_ADDRESS);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("connectInjectedWallet - external connection success", async () => {
|
|
48
|
+
const connector = createMockConnector();
|
|
49
|
+
const preference = {
|
|
50
|
+
connection: {
|
|
51
|
+
api: {},
|
|
52
|
+
metadata: MOCK_METADATA
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const provider = await connectInjectedWallet("Test", preference, connector);
|
|
56
|
+
expect(provider.getAddress().address).toEqual(MOCK_ADDRESS);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("connectInjectedWallet - handles failure", async () => {
|
|
60
|
+
const connector = createMockConnector(true);
|
|
61
|
+
expect(
|
|
62
|
+
connectInjectedWallet("Test", undefined, connector),
|
|
63
|
+
).rejects.toThrow("Simple connect failed");
|
|
64
|
+
});
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ActiveConnection,
|
|
3
|
+
IConnector,
|
|
4
|
+
IInjectedConnector,
|
|
5
|
+
IProvider,
|
|
6
|
+
} from "./IProvider.ts";
|
|
7
|
+
|
|
8
|
+
import { AlgorandConnector } from "./algorand/algorand.ts";
|
|
9
|
+
import { EthersConnector } from "./evm/ethers.ts";
|
|
10
|
+
import { EvmInjectedConnector } from "./evm/injected.ts";
|
|
11
|
+
import { CardanoConnector } from "./cardano/cardano.ts";
|
|
12
|
+
import { PolkadotConnector } from "./polkadot/polkadot.ts";
|
|
13
|
+
import { MinaConnector } from "./mina/mina.ts";
|
|
14
|
+
import { AvailConnector } from "./avail/avail.ts";
|
|
15
|
+
import { MidnightConnector } from "./midnight/midnight.ts";
|
|
16
|
+
|
|
17
|
+
export const enum WalletMode {
|
|
18
|
+
EvmInjected,
|
|
19
|
+
EvmEthers,
|
|
20
|
+
Midnight,
|
|
21
|
+
Cardano,
|
|
22
|
+
Polkadot,
|
|
23
|
+
Algorand,
|
|
24
|
+
Mina,
|
|
25
|
+
AvailJs,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const WalletNameMap: Record<WalletMode, string> = {
|
|
29
|
+
[WalletMode.EvmInjected]: "EVM",
|
|
30
|
+
[WalletMode.EvmEthers]: "EVM",
|
|
31
|
+
[WalletMode.Midnight]: "Midnight",
|
|
32
|
+
[WalletMode.Cardano]: "Cardano",
|
|
33
|
+
[WalletMode.Polkadot]: 'Polkadot',
|
|
34
|
+
[WalletMode.Algorand]: 'Algorand',
|
|
35
|
+
[WalletMode.Mina]: "Mina",
|
|
36
|
+
[WalletMode.AvailJs]: "Avail",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const WalletModeMap = {
|
|
40
|
+
[WalletMode.EvmInjected]: EvmInjectedConnector.instance(),
|
|
41
|
+
[WalletMode.EvmEthers]: EthersConnector.instance(),
|
|
42
|
+
[WalletMode.Midnight]: MidnightConnector.instance(),
|
|
43
|
+
[WalletMode.Cardano]: CardanoConnector.instance(),
|
|
44
|
+
[WalletMode.Polkadot]: PolkadotConnector.instance(),
|
|
45
|
+
[WalletMode.Algorand]: AlgorandConnector.instance(),
|
|
46
|
+
[WalletMode.Mina]: MinaConnector.instance(),
|
|
47
|
+
[WalletMode.AvailJs]: AvailConnector.instance(),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type ExtractGeneric<T> = T extends IConnector<infer U> ? U : never;
|
|
51
|
+
export type ApiForMode<Mode extends WalletMode> = ExtractGeneric<
|
|
52
|
+
(typeof WalletModeMap)[Mode]
|
|
53
|
+
>;
|
|
54
|
+
|
|
55
|
+
export type InjectionPreference<T> =
|
|
56
|
+
| {
|
|
57
|
+
name: string;
|
|
58
|
+
}
|
|
59
|
+
| {
|
|
60
|
+
connection: ActiveConnection<T>;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export async function allInjectedWallets(config: {
|
|
64
|
+
signatureSupport: boolean,
|
|
65
|
+
transactionSupport: boolean,
|
|
66
|
+
} = {
|
|
67
|
+
signatureSupport: true,
|
|
68
|
+
transactionSupport: true,
|
|
69
|
+
}): Promise<{
|
|
70
|
+
[WalletMode.EvmInjected]: ReturnType<
|
|
71
|
+
typeof EvmInjectedConnector.getWalletOptions
|
|
72
|
+
>;
|
|
73
|
+
[WalletMode.Cardano]: ReturnType<typeof CardanoConnector.getWalletOptions>;
|
|
74
|
+
[WalletMode.Polkadot]: Awaited<
|
|
75
|
+
ReturnType<typeof PolkadotConnector.getWalletOptions>
|
|
76
|
+
>;
|
|
77
|
+
[WalletMode.Algorand]: ReturnType<typeof AlgorandConnector.getWalletOptions>;
|
|
78
|
+
[WalletMode.Mina]: ReturnType<typeof MinaConnector.getWalletOptions>;
|
|
79
|
+
[WalletMode.Midnight]: ReturnType<typeof MidnightConnector.getWalletOptions>;
|
|
80
|
+
}> {
|
|
81
|
+
const signatureSupport = config.signatureSupport;
|
|
82
|
+
const transactionSupport = config.transactionSupport;
|
|
83
|
+
const wallets = {
|
|
84
|
+
// EVM, CARDANO, MINA, POLKADOR Wallets have full support for signatures and transactions.
|
|
85
|
+
[WalletMode.EvmInjected]: EvmInjectedConnector.getWalletOptions(),
|
|
86
|
+
[WalletMode.Cardano]: CardanoConnector.getWalletOptions(),
|
|
87
|
+
[WalletMode.Polkadot]: await PolkadotConnector.getWalletOptions(),
|
|
88
|
+
[WalletMode.Mina]: MinaConnector.getWalletOptions(),
|
|
89
|
+
// TODO: Algorand signature support is not implemented yet.
|
|
90
|
+
// NOTE: Midnight Do not support signature yet.
|
|
91
|
+
[WalletMode.Algorand]: signatureSupport? [] : AlgorandConnector.getWalletOptions(),
|
|
92
|
+
[WalletMode.Midnight]: signatureSupport? [] : MidnightConnector.getWalletOptions(),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return wallets;
|
|
96
|
+
}
|
|
97
|
+
export async function connectInjectedWallet<Api>(
|
|
98
|
+
typeName: string,
|
|
99
|
+
preference: undefined | InjectionPreference<Api>,
|
|
100
|
+
connector: IInjectedConnector<Api>,
|
|
101
|
+
): Promise<IProvider<Api>> {
|
|
102
|
+
if (preference == null) {
|
|
103
|
+
console.log(`${typeName} Attempting simple login`);
|
|
104
|
+
const provider = await connector.connectSimple();
|
|
105
|
+
return provider;
|
|
106
|
+
} else if ("name" in preference) {
|
|
107
|
+
const walletName = preference.name;
|
|
108
|
+
console.log(`${typeName} Attempting to log into ${walletName}`);
|
|
109
|
+
const provider = await connector.connectNamed(walletName);
|
|
110
|
+
return provider;
|
|
111
|
+
} else if ("connection" in preference) {
|
|
112
|
+
const walletName = preference.connection.metadata.name;
|
|
113
|
+
console.log(`${typeName} Attempting to log into ${walletName}`);
|
|
114
|
+
const provider = await connector.connectExternal(preference.connection);
|
|
115
|
+
return provider;
|
|
116
|
+
}
|
|
117
|
+
throw new Error("Invalid preference");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function callProvider<
|
|
121
|
+
Mode extends WalletMode,
|
|
122
|
+
Api extends ApiForMode<Mode>,
|
|
123
|
+
Func extends keyof IProvider<Api>,
|
|
124
|
+
>(
|
|
125
|
+
mode: Mode,
|
|
126
|
+
funcName: Func,
|
|
127
|
+
...args: Parameters<IProvider<Api>[Func]>
|
|
128
|
+
): ReturnType<IProvider<Api>[Func]> {
|
|
129
|
+
const provider = WalletModeMap[mode].getOrThrowProvider();
|
|
130
|
+
const func = provider[funcName];
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
132
|
+
return (func as any)(...args);
|
|
133
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { ApiPromise } from "avail-js-sdk";
|
|
2
|
+
import type { Result } from "@effectstream/utils";
|
|
3
|
+
import type { AlgorandApi } from "./algorand/algorand.ts";
|
|
4
|
+
import type { CardanoApi } from "./cardano/cardano.ts";
|
|
5
|
+
import type { EthersApi } from "./evm/ethers.ts";
|
|
6
|
+
import type { EvmApi } from "./evm/injected.ts";
|
|
7
|
+
import type {
|
|
8
|
+
ActiveConnection,
|
|
9
|
+
IInjectedConnector,
|
|
10
|
+
IProvider,
|
|
11
|
+
} from "./IProvider.ts";
|
|
12
|
+
import type { MinaApi } from "./mina/mina.ts";
|
|
13
|
+
import type { PolkadotApi } from "./polkadot/polkadot.ts";
|
|
14
|
+
import {
|
|
15
|
+
connectInjectedWallet,
|
|
16
|
+
type InjectionPreference,
|
|
17
|
+
WalletMode,
|
|
18
|
+
} from "./utils.ts";
|
|
19
|
+
import { AddressType } from "@effectstream/utils";
|
|
20
|
+
import type { MidnightApi } from "./midnight/midnight.ts";
|
|
21
|
+
import type { Chain } from "viem/chains";
|
|
22
|
+
import { Wallet } from "ethers";
|
|
23
|
+
|
|
24
|
+
export type BaseLoginInfo<Api> = {
|
|
25
|
+
preference?: InjectionPreference<Api>;
|
|
26
|
+
};
|
|
27
|
+
export type LoginInfoMap = {
|
|
28
|
+
[WalletMode.EvmInjected]: BaseLoginInfo<EvmApi> & {
|
|
29
|
+
/** If true even EVM wallet inputs will be batched (sign data and send to the batcher) */
|
|
30
|
+
preferBatchedMode: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* By default, Paima will try and switch the wallet's network to the one used for the game
|
|
33
|
+
* This uses EIP3326 (https://eips.ethereum.org/EIPS/eip-3326)
|
|
34
|
+
* This may not be desired, since not all wallets support switching to an arbitrary network
|
|
35
|
+
* Set to false if you only need to sign data. Otherwise, keep as true
|
|
36
|
+
* @default true
|
|
37
|
+
*/
|
|
38
|
+
checkChainId?: boolean;
|
|
39
|
+
chain?: Chain;
|
|
40
|
+
};
|
|
41
|
+
[WalletMode.EvmEthers]: {
|
|
42
|
+
connection: ActiveConnection<EthersApi>;
|
|
43
|
+
preferBatchedMode: boolean;
|
|
44
|
+
};
|
|
45
|
+
[WalletMode.Cardano]: BaseLoginInfo<CardanoApi>;
|
|
46
|
+
[WalletMode.Polkadot]: BaseLoginInfo<PolkadotApi>;
|
|
47
|
+
[WalletMode.Algorand]: BaseLoginInfo<AlgorandApi>;
|
|
48
|
+
[WalletMode.Mina]: BaseLoginInfo<MinaApi>;
|
|
49
|
+
[WalletMode.AvailJs]: {
|
|
50
|
+
connection: ActiveConnection<ApiPromise>;
|
|
51
|
+
preferBatchedMode: boolean;
|
|
52
|
+
seed: string;
|
|
53
|
+
};
|
|
54
|
+
[WalletMode.Midnight]: BaseLoginInfo<MidnightApi> & {
|
|
55
|
+
networkId?: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type ToUnion<T> = {
|
|
60
|
+
[K in keyof T]: { mode: K } & T[K];
|
|
61
|
+
}[keyof T];
|
|
62
|
+
|
|
63
|
+
export type LoginInfo = ToUnion<LoginInfoMap>;
|
|
64
|
+
|
|
65
|
+
function getWalletName(info: BaseLoginInfo<unknown>): undefined | string {
|
|
66
|
+
if (info.preference == null) return undefined;
|
|
67
|
+
if ("name" in info.preference) {
|
|
68
|
+
return info.preference.name;
|
|
69
|
+
}
|
|
70
|
+
return info.preference.connection.metadata.name;
|
|
71
|
+
}
|
|
72
|
+
export async function connectInjected<Api>(
|
|
73
|
+
typeName: string,
|
|
74
|
+
loginInfo: BaseLoginInfo<Api>,
|
|
75
|
+
connector: IInjectedConnector<Api>,
|
|
76
|
+
): Promise<Result<IProvider<Api>>> {
|
|
77
|
+
try {
|
|
78
|
+
const provider = await connectInjectedWallet(
|
|
79
|
+
typeName,
|
|
80
|
+
loginInfo.preference,
|
|
81
|
+
connector,
|
|
82
|
+
);
|
|
83
|
+
return {
|
|
84
|
+
success: true,
|
|
85
|
+
result: provider,
|
|
86
|
+
};
|
|
87
|
+
} catch (err) {
|
|
88
|
+
console.log(
|
|
89
|
+
`${typeName} Error while logging into wallet ${
|
|
90
|
+
getWalletName(loginInfo) ?? "simple"
|
|
91
|
+
}`,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
success: false,
|
|
96
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getAddressType(mode: WalletMode): AddressType {
|
|
102
|
+
switch (mode) {
|
|
103
|
+
|
|
104
|
+
case WalletMode.EvmInjected:
|
|
105
|
+
case WalletMode.EvmEthers:
|
|
106
|
+
return AddressType.EVM;
|
|
107
|
+
case WalletMode.Cardano:
|
|
108
|
+
return AddressType.CARDANO;
|
|
109
|
+
case WalletMode.Polkadot:
|
|
110
|
+
return AddressType.POLKADOT;
|
|
111
|
+
case WalletMode.Algorand:
|
|
112
|
+
return AddressType.ALGORAND;
|
|
113
|
+
case WalletMode.Mina:
|
|
114
|
+
return AddressType.MINA;
|
|
115
|
+
case WalletMode.Midnight:
|
|
116
|
+
return AddressType.MIDNIGHT;
|
|
117
|
+
case WalletMode.AvailJs:
|
|
118
|
+
return AddressType.AVAIL;
|
|
119
|
+
case WalletMode.Polkadot:
|
|
120
|
+
return AddressType.POLKADOT;
|
|
121
|
+
default:
|
|
122
|
+
throw new Error(`Unsupported wallet mode: ${mode}`);
|
|
123
|
+
}
|
|
124
|
+
};
|
package/src/wallets.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { IProvider } from "./IProvider.ts";
|
|
2
|
+
import { algorandLoginWrapper } from "./algorand/wrapper.ts";
|
|
3
|
+
import { cardanoLoginWrapper } from "./cardano/wrapper.ts";
|
|
4
|
+
import { evmLoginWrapper } from "./evm/wrapper-injected.ts";
|
|
5
|
+
import { polkadotLoginWrapper } from "./polkadot/wrapper.ts";
|
|
6
|
+
import { ethersLoginWrapper } from "./evm/wrapper-ethers.ts";
|
|
7
|
+
import { minaLoginWrapper } from "./mina/wrapper.ts";
|
|
8
|
+
import { availJsLoginWrapper } from "./avail/wrapper.ts";
|
|
9
|
+
import { WalletMode } from "./utils.ts";
|
|
10
|
+
import type { Result } from "@effectstream/utils";
|
|
11
|
+
import type { Wallet } from "./types.ts";
|
|
12
|
+
import type { LoginInfo } from "./wallet-modes.ts";
|
|
13
|
+
// import { assertNever } from "assert-never";
|
|
14
|
+
import { midnightLoginWrapper } from "./midnight/wrapper.ts";
|
|
15
|
+
|
|
16
|
+
export async function walletLogin(
|
|
17
|
+
loginInfo: LoginInfo
|
|
18
|
+
): Promise<Result<Wallet>> {
|
|
19
|
+
const provider = await login(loginInfo);
|
|
20
|
+
if (provider.success === false) return provider;
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
success: true,
|
|
24
|
+
result: {
|
|
25
|
+
provider: provider.result,
|
|
26
|
+
walletAddress: provider.result.getAddress().address,
|
|
27
|
+
metadata: provider.result.getConnection().metadata,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async function login(loginInfo: LoginInfo): Promise<Result<IProvider<unknown>>> {
|
|
34
|
+
switch (loginInfo.mode) {
|
|
35
|
+
case WalletMode.EvmInjected: {
|
|
36
|
+
return await evmLoginWrapper(loginInfo);
|
|
37
|
+
}
|
|
38
|
+
case WalletMode.EvmEthers: {
|
|
39
|
+
return await ethersLoginWrapper(loginInfo);
|
|
40
|
+
}
|
|
41
|
+
case WalletMode.Cardano: {
|
|
42
|
+
return await cardanoLoginWrapper(loginInfo);
|
|
43
|
+
}
|
|
44
|
+
case WalletMode.Polkadot: {
|
|
45
|
+
return await polkadotLoginWrapper(loginInfo);
|
|
46
|
+
}
|
|
47
|
+
case WalletMode.Algorand: {
|
|
48
|
+
return await algorandLoginWrapper(loginInfo);
|
|
49
|
+
}
|
|
50
|
+
case WalletMode.Mina: {
|
|
51
|
+
return await minaLoginWrapper(loginInfo);
|
|
52
|
+
}
|
|
53
|
+
case WalletMode.AvailJs: {
|
|
54
|
+
return await availJsLoginWrapper(loginInfo);
|
|
55
|
+
}
|
|
56
|
+
case WalletMode.Midnight: {
|
|
57
|
+
return await midnightLoginWrapper(loginInfo);
|
|
58
|
+
}
|
|
59
|
+
default:
|
|
60
|
+
throw new Error(`Unsupported wallet mode: ${(loginInfo as any).mode}`);
|
|
61
|
+
}
|
|
62
|
+
};
|
package/src/windows.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paima might be used in non-browser environments where window isn't defined
|
|
3
|
+
*/
|
|
4
|
+
export function getWindow() /*: (Window & typeof globalThis) | undefined*/ {
|
|
5
|
+
// recall: this is different semantically to window?.foo
|
|
6
|
+
// since window?.foo can still give ReferenceError: window is not defined
|
|
7
|
+
// dnt-shim-ignore
|
|
8
|
+
return typeof window === 'undefined' ? undefined : window;
|
|
9
|
+
}
|
|
10
|
+
|