@effectstream/wallets 0.100.17 → 0.100.19
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/package.json +52 -6
- package/src/avail/wrapper.ts +2 -1
- package/src/cardano/local.test.ts +31 -0
- package/src/cardano/local.ts +159 -0
- package/src/cardano/wrapper-local.ts +31 -0
- package/src/effectstream.ts +3 -1
- package/src/evm/viem.test.ts +37 -0
- package/src/evm/viem.ts +195 -0
- package/src/evm/wrapper-ethers.ts +2 -1
- package/src/evm/wrapper-viem.ts +31 -0
- package/src/helpers/format-error.ts +31 -0
- package/src/helpers/local-icons.ts +35 -0
- package/src/helpers/pick-mode.ts +89 -0
- package/src/midnight/local.test.ts +157 -0
- package/src/midnight/local.ts +375 -0
- package/src/midnight/midnight.ts +57 -11
- package/src/midnight/wrapper-local.ts +30 -0
- package/src/mod.ts +19 -0
- package/src/utils.ts +17 -2
- package/src/wallet-modes.ts +33 -1
- package/src/wallets.ts +12 -0
package/src/midnight/midnight.ts
CHANGED
|
@@ -132,11 +132,15 @@ export class MidnightProvider implements IProvider<MidnightApi> {
|
|
|
132
132
|
static init = async (
|
|
133
133
|
conn: ActiveConnection<MidnightApi>
|
|
134
134
|
): Promise<MidnightProvider> => {
|
|
135
|
-
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
|
|
135
|
+
// The IProvider's primary address must be the UNSHIELDED one — that's
|
|
136
|
+
// the address `addressFromKey(verifyingKey)` resolves to for the
|
|
137
|
+
// `signData({keyType: "unshielded"})` signatures we produce in
|
|
138
|
+
// `signMessage`, which is what `CryptoManager.Midnight().verifySignature`
|
|
139
|
+
// (and therefore the batcher) cross-checks. The shielded and dust
|
|
140
|
+
// addresses remain reachable via `fetchAddress(conn, { type })` or
|
|
141
|
+
// directly through `conn.api.getShieldedAddresses()` /
|
|
142
|
+
// `getDustAddress()`.
|
|
143
|
+
const hexAddress = await MidnightProvider.fetchAddress(conn, { type: "unshielded" });
|
|
140
144
|
return new MidnightProvider(conn, hexAddress as MidnightAddress);
|
|
141
145
|
};
|
|
142
146
|
|
|
@@ -152,7 +156,12 @@ export class MidnightProvider implements IProvider<MidnightApi> {
|
|
|
152
156
|
encoding: "text",
|
|
153
157
|
keyType,
|
|
154
158
|
})) as Signature;
|
|
155
|
-
|
|
159
|
+
// Format: "signature|verifyingKey". Midnight unshielded signatures are
|
|
160
|
+
// not self-recovering, so `@effectstream/crypto`'s verifier needs the
|
|
161
|
+
// public key alongside the signature (matches the local-seed wallet
|
|
162
|
+
// and mirrors Cardano's "sig+key" convention with a different
|
|
163
|
+
// separator).
|
|
164
|
+
return `${signature.signature}|${signature.verifyingKey}`;
|
|
156
165
|
};
|
|
157
166
|
|
|
158
167
|
getAddress(): AddressAndType {
|
|
@@ -162,12 +171,49 @@ export class MidnightProvider implements IProvider<MidnightApi> {
|
|
|
162
171
|
}
|
|
163
172
|
}
|
|
164
173
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Fetch a specific address type from a connected Midnight wallet. Defaults
|
|
176
|
+
* to the **shielded** address to keep existing callers backwards-compatible
|
|
177
|
+
* with the pre-multi-address behaviour. The IProvider primary address
|
|
178
|
+
* (`getAddress()`) is the **unshielded** one — that's the address
|
|
179
|
+
* `addressFromKey(verifyingKey)` resolves to and what
|
|
180
|
+
* `CryptoManager.Midnight().verifySignature` needs to cross-check.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```ts
|
|
184
|
+
* const shielded = await MidnightProvider.fetchAddress(conn);
|
|
185
|
+
* const unshielded = await MidnightProvider.fetchAddress(conn, { type: "unshielded" });
|
|
186
|
+
* const dust = await MidnightProvider.fetchAddress(conn, { type: "dust" });
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
static fetchAddress = async (
|
|
190
|
+
conn: ActiveConnection<MidnightApi>,
|
|
191
|
+
options: { type?: "shielded" | "unshielded" | "dust" } = {},
|
|
192
|
+
): Promise<string> => {
|
|
193
|
+
const type = options.type ?? "shielded";
|
|
194
|
+
switch (type) {
|
|
195
|
+
case "shielded": {
|
|
196
|
+
const res = await conn.api.getShieldedAddresses();
|
|
197
|
+
if (!res?.shieldedAddress) {
|
|
198
|
+
throw new Error("Midnight wallet did not return a shielded address");
|
|
199
|
+
}
|
|
200
|
+
return res.shieldedAddress;
|
|
201
|
+
}
|
|
202
|
+
case "unshielded": {
|
|
203
|
+
const res = await conn.api.getUnshieldedAddress();
|
|
204
|
+
if (!res?.unshieldedAddress) {
|
|
205
|
+
throw new Error("Midnight wallet did not return an unshielded address");
|
|
206
|
+
}
|
|
207
|
+
return res.unshieldedAddress;
|
|
208
|
+
}
|
|
209
|
+
case "dust": {
|
|
210
|
+
const res = await conn.api.getDustAddress();
|
|
211
|
+
if (!res?.dustAddress) {
|
|
212
|
+
throw new Error("Midnight wallet did not return a dust address");
|
|
213
|
+
}
|
|
214
|
+
return res.dustAddress;
|
|
215
|
+
}
|
|
169
216
|
}
|
|
170
|
-
return addresses.shieldedAddress;
|
|
171
217
|
};
|
|
172
218
|
}
|
|
173
219
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Result } from "@effectstream/utils";
|
|
2
|
+
import type { IProvider } from "../IProvider.ts";
|
|
3
|
+
import type { WalletMode, ApiForMode } from "../utils.ts";
|
|
4
|
+
import type { LoginInfoMap } from "../wallet-modes.ts";
|
|
5
|
+
import { MidnightLocalConnector } from "./local.ts";
|
|
6
|
+
import { formatError } from "../helpers/format-error.ts";
|
|
7
|
+
|
|
8
|
+
export async function midnightLocalLoginWrapper(
|
|
9
|
+
loginInfo: LoginInfoMap[WalletMode.MidnightLocal],
|
|
10
|
+
): Promise<Result<IProvider<ApiForMode<WalletMode.MidnightLocal>>>> {
|
|
11
|
+
try {
|
|
12
|
+
console.log("midnightLocalLoginWrapper: deriving unshielded keystore from seed");
|
|
13
|
+
const provider = await MidnightLocalConnector.instance().connectFromSeed({
|
|
14
|
+
seed: loginInfo.seed,
|
|
15
|
+
networkId: loginInfo.networkId,
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
success: true,
|
|
19
|
+
result: provider as unknown as IProvider<
|
|
20
|
+
ApiForMode<WalletMode.MidnightLocal>
|
|
21
|
+
>,
|
|
22
|
+
};
|
|
23
|
+
} catch (err) {
|
|
24
|
+
console.log("midnightLocalLoginWrapper: error building local Midnight wallet");
|
|
25
|
+
return {
|
|
26
|
+
success: false,
|
|
27
|
+
errorMessage: formatError(err),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/mod.ts
CHANGED
|
@@ -7,4 +7,23 @@ export { WalletMode, WalletNameMap } from "./utils.ts";
|
|
|
7
7
|
export { walletLogin } from "./wallets.ts";
|
|
8
8
|
export { allInjectedWallets } from "./utils.ts";
|
|
9
9
|
export { getAddressType } from "./wallet-modes.ts";
|
|
10
|
+
export type { LoginInfo, LoginInfoMap } from "./wallet-modes.ts";
|
|
11
|
+
// Local-wallet mode helper (env-driven injected↔local swap).
|
|
12
|
+
export { pickWalletMode } from "./helpers/pick-mode.ts";
|
|
13
|
+
export type {
|
|
14
|
+
ChainKey,
|
|
15
|
+
PickWalletModeArgs,
|
|
16
|
+
LocalOptionsForChain,
|
|
17
|
+
InjectedOptionsForChain,
|
|
18
|
+
} from "./helpers/pick-mode.ts";
|
|
19
|
+
// Inline data-URI icons for the three local-JS wallet modes (orange/blue/black
|
|
20
|
+
// JS circles), suitable for use as `WalletOption.icon`.
|
|
21
|
+
export {
|
|
22
|
+
evmViemIcon,
|
|
23
|
+
cardanoLocalIcon,
|
|
24
|
+
midnightLocalIcon,
|
|
25
|
+
} from "./helpers/local-icons.ts";
|
|
26
|
+
// Coerces wallet/SDK rejects (including CIP-30-style `{code, info}` objects)
|
|
27
|
+
// to a readable string.
|
|
28
|
+
export { formatError } from "./helpers/format-error.ts";
|
|
10
29
|
export * from "./effectstream.ts";
|
package/src/utils.ts
CHANGED
|
@@ -7,18 +7,24 @@ import type {
|
|
|
7
7
|
|
|
8
8
|
import { AlgorandConnector } from "./algorand/algorand.ts";
|
|
9
9
|
import { EthersConnector } from "./evm/ethers.ts";
|
|
10
|
+
import { ViemConnector } from "./evm/viem.ts";
|
|
10
11
|
import { EvmInjectedConnector } from "./evm/injected.ts";
|
|
11
12
|
import { CardanoConnector } from "./cardano/cardano.ts";
|
|
13
|
+
import { CardanoLocalConnector } from "./cardano/local.ts";
|
|
12
14
|
import { PolkadotConnector } from "./polkadot/polkadot.ts";
|
|
13
15
|
import { MinaConnector } from "./mina/mina.ts";
|
|
14
16
|
import { AvailConnector } from "./avail/avail.ts";
|
|
15
17
|
import { MidnightConnector } from "./midnight/midnight.ts";
|
|
18
|
+
import { MidnightLocalConnector } from "./midnight/local.ts";
|
|
16
19
|
|
|
17
20
|
export const enum WalletMode {
|
|
18
21
|
EvmInjected,
|
|
19
22
|
EvmEthers,
|
|
23
|
+
EvmViem,
|
|
20
24
|
Midnight,
|
|
25
|
+
MidnightLocal,
|
|
21
26
|
Cardano,
|
|
27
|
+
CardanoLocal,
|
|
22
28
|
Polkadot,
|
|
23
29
|
Algorand,
|
|
24
30
|
Mina,
|
|
@@ -28,8 +34,11 @@ export const enum WalletMode {
|
|
|
28
34
|
export const WalletNameMap: Record<WalletMode, string> = {
|
|
29
35
|
[WalletMode.EvmInjected]: "EVM",
|
|
30
36
|
[WalletMode.EvmEthers]: "EVM",
|
|
37
|
+
[WalletMode.EvmViem]: "EVM",
|
|
31
38
|
[WalletMode.Midnight]: "Midnight",
|
|
39
|
+
[WalletMode.MidnightLocal]: "Midnight",
|
|
32
40
|
[WalletMode.Cardano]: "Cardano",
|
|
41
|
+
[WalletMode.CardanoLocal]: "Cardano",
|
|
33
42
|
[WalletMode.Polkadot]: 'Polkadot',
|
|
34
43
|
[WalletMode.Algorand]: 'Algorand',
|
|
35
44
|
[WalletMode.Mina]: "Mina",
|
|
@@ -39,8 +48,11 @@ export const WalletNameMap: Record<WalletMode, string> = {
|
|
|
39
48
|
export const WalletModeMap = {
|
|
40
49
|
[WalletMode.EvmInjected]: EvmInjectedConnector.instance(),
|
|
41
50
|
[WalletMode.EvmEthers]: EthersConnector.instance(),
|
|
51
|
+
[WalletMode.EvmViem]: ViemConnector.instance(),
|
|
42
52
|
[WalletMode.Midnight]: MidnightConnector.instance(),
|
|
53
|
+
[WalletMode.MidnightLocal]: MidnightLocalConnector.instance(),
|
|
43
54
|
[WalletMode.Cardano]: CardanoConnector.instance(),
|
|
55
|
+
[WalletMode.CardanoLocal]: CardanoLocalConnector.instance(),
|
|
44
56
|
[WalletMode.Polkadot]: PolkadotConnector.instance(),
|
|
45
57
|
[WalletMode.Algorand]: AlgorandConnector.instance(),
|
|
46
58
|
[WalletMode.Mina]: MinaConnector.instance(),
|
|
@@ -87,9 +99,12 @@ export async function allInjectedWallets(config: {
|
|
|
87
99
|
[WalletMode.Polkadot]: await PolkadotConnector.getWalletOptions(),
|
|
88
100
|
[WalletMode.Mina]: MinaConnector.getWalletOptions(),
|
|
89
101
|
// TODO: Algorand signature support is not implemented yet.
|
|
90
|
-
// NOTE: Midnight Do not support signature yet.
|
|
91
102
|
[WalletMode.Algorand]: signatureSupport? [] : AlgorandConnector.getWalletOptions(),
|
|
92
|
-
|
|
103
|
+
// Midnight signing via ConnectedAPI.signData(message, {keyType: "unshielded"})
|
|
104
|
+
// works as of @effectstream/crypto's MidnightCrypto.verifySignature
|
|
105
|
+
// implementation, so it now surfaces in the injected-wallet list even when
|
|
106
|
+
// signature support is requested.
|
|
107
|
+
[WalletMode.Midnight]: MidnightConnector.getWalletOptions(),
|
|
93
108
|
};
|
|
94
109
|
|
|
95
110
|
return wallets;
|
package/src/wallet-modes.ts
CHANGED
|
@@ -2,8 +2,11 @@ import type { ApiPromise } from "avail-js-sdk";
|
|
|
2
2
|
import type { Result } from "@effectstream/utils";
|
|
3
3
|
import type { AlgorandApi } from "./algorand/algorand.ts";
|
|
4
4
|
import type { CardanoApi } from "./cardano/cardano.ts";
|
|
5
|
+
import type { CardanoLocalNetwork } from "./cardano/local.ts";
|
|
5
6
|
import type { EthersApi } from "./evm/ethers.ts";
|
|
7
|
+
import type { ViemApi } from "./evm/viem.ts";
|
|
6
8
|
import type { EvmApi } from "./evm/injected.ts";
|
|
9
|
+
import type { Hex } from "viem";
|
|
7
10
|
import type {
|
|
8
11
|
ActiveConnection,
|
|
9
12
|
IInjectedConnector,
|
|
@@ -17,7 +20,9 @@ import {
|
|
|
17
20
|
WalletMode,
|
|
18
21
|
} from "./utils.ts";
|
|
19
22
|
import { AddressType } from "@effectstream/utils";
|
|
23
|
+
import { formatError } from "./helpers/format-error.ts";
|
|
20
24
|
import type { MidnightApi } from "./midnight/midnight.ts";
|
|
25
|
+
import type {} from "./midnight/local.ts";
|
|
21
26
|
import type { Chain } from "viem/chains";
|
|
22
27
|
import { Wallet } from "ethers";
|
|
23
28
|
|
|
@@ -42,7 +47,25 @@ export type LoginInfoMap = {
|
|
|
42
47
|
connection: ActiveConnection<EthersApi>;
|
|
43
48
|
preferBatchedMode: boolean;
|
|
44
49
|
};
|
|
50
|
+
[WalletMode.EvmViem]: {
|
|
51
|
+
/** 0x-prefixed 32-byte hex private key. */
|
|
52
|
+
privateKey: Hex;
|
|
53
|
+
/** RPC URL the viem WalletClient should target. */
|
|
54
|
+
rpcUrl: string;
|
|
55
|
+
/** Optional viem Chain — pass to enable chain-aware tx fields (chainId etc). */
|
|
56
|
+
chain?: Chain;
|
|
57
|
+
/** If true, even EVM inputs are batched (sign + send to batcher). */
|
|
58
|
+
preferBatchedMode?: boolean;
|
|
59
|
+
};
|
|
45
60
|
[WalletMode.Cardano]: BaseLoginInfo<CardanoApi>;
|
|
61
|
+
[WalletMode.CardanoLocal]: {
|
|
62
|
+
/** BIP-39 mnemonic. Generated when omitted. */
|
|
63
|
+
seedPhrase?: string;
|
|
64
|
+
/** Cardano network — sets the bech32 prefix. */
|
|
65
|
+
network: CardanoLocalNetwork;
|
|
66
|
+
/** Optional Lucid Provider; only needed for on-chain ops, not pure signing. */
|
|
67
|
+
provider?: unknown;
|
|
68
|
+
};
|
|
46
69
|
[WalletMode.Polkadot]: BaseLoginInfo<PolkadotApi>;
|
|
47
70
|
[WalletMode.Algorand]: BaseLoginInfo<AlgorandApi>;
|
|
48
71
|
[WalletMode.Mina]: BaseLoginInfo<MinaApi>;
|
|
@@ -54,6 +77,12 @@ export type LoginInfoMap = {
|
|
|
54
77
|
[WalletMode.Midnight]: BaseLoginInfo<MidnightApi> & {
|
|
55
78
|
networkId?: string;
|
|
56
79
|
};
|
|
80
|
+
[WalletMode.MidnightLocal]: {
|
|
81
|
+
/** 64-char hex seed. Generated when omitted. */
|
|
82
|
+
seed?: string;
|
|
83
|
+
/** Midnight network id ("undeployed" | "testnet" | …) — sets the bech32 prefix. */
|
|
84
|
+
networkId: string;
|
|
85
|
+
};
|
|
57
86
|
};
|
|
58
87
|
|
|
59
88
|
type ToUnion<T> = {
|
|
@@ -93,7 +122,7 @@ export async function connectInjected<Api>(
|
|
|
93
122
|
|
|
94
123
|
return {
|
|
95
124
|
success: false,
|
|
96
|
-
errorMessage:
|
|
125
|
+
errorMessage: formatError(err),
|
|
97
126
|
};
|
|
98
127
|
}
|
|
99
128
|
}
|
|
@@ -103,8 +132,10 @@ export function getAddressType(mode: WalletMode): AddressType {
|
|
|
103
132
|
|
|
104
133
|
case WalletMode.EvmInjected:
|
|
105
134
|
case WalletMode.EvmEthers:
|
|
135
|
+
case WalletMode.EvmViem:
|
|
106
136
|
return AddressType.EVM;
|
|
107
137
|
case WalletMode.Cardano:
|
|
138
|
+
case WalletMode.CardanoLocal:
|
|
108
139
|
return AddressType.CARDANO;
|
|
109
140
|
case WalletMode.Polkadot:
|
|
110
141
|
return AddressType.POLKADOT;
|
|
@@ -113,6 +144,7 @@ export function getAddressType(mode: WalletMode): AddressType {
|
|
|
113
144
|
case WalletMode.Mina:
|
|
114
145
|
return AddressType.MINA;
|
|
115
146
|
case WalletMode.Midnight:
|
|
147
|
+
case WalletMode.MidnightLocal:
|
|
116
148
|
return AddressType.MIDNIGHT;
|
|
117
149
|
case WalletMode.AvailJs:
|
|
118
150
|
return AddressType.AVAIL;
|
package/src/wallets.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { IProvider } from "./IProvider.ts";
|
|
2
2
|
import { algorandLoginWrapper } from "./algorand/wrapper.ts";
|
|
3
3
|
import { cardanoLoginWrapper } from "./cardano/wrapper.ts";
|
|
4
|
+
import { cardanoLocalLoginWrapper } from "./cardano/wrapper-local.ts";
|
|
4
5
|
import { evmLoginWrapper } from "./evm/wrapper-injected.ts";
|
|
5
6
|
import { polkadotLoginWrapper } from "./polkadot/wrapper.ts";
|
|
6
7
|
import { ethersLoginWrapper } from "./evm/wrapper-ethers.ts";
|
|
8
|
+
import { viemLoginWrapper } from "./evm/wrapper-viem.ts";
|
|
7
9
|
import { minaLoginWrapper } from "./mina/wrapper.ts";
|
|
8
10
|
import { availJsLoginWrapper } from "./avail/wrapper.ts";
|
|
9
11
|
import { WalletMode } from "./utils.ts";
|
|
@@ -12,6 +14,7 @@ import type { Wallet } from "./types.ts";
|
|
|
12
14
|
import type { LoginInfo } from "./wallet-modes.ts";
|
|
13
15
|
// import { assertNever } from "assert-never";
|
|
14
16
|
import { midnightLoginWrapper } from "./midnight/wrapper.ts";
|
|
17
|
+
import { midnightLocalLoginWrapper } from "./midnight/wrapper-local.ts";
|
|
15
18
|
|
|
16
19
|
export async function walletLogin(
|
|
17
20
|
loginInfo: LoginInfo
|
|
@@ -38,9 +41,15 @@ async function login(loginInfo: LoginInfo): Promise<Result<IProvider<unknown>>>
|
|
|
38
41
|
case WalletMode.EvmEthers: {
|
|
39
42
|
return await ethersLoginWrapper(loginInfo);
|
|
40
43
|
}
|
|
44
|
+
case WalletMode.EvmViem: {
|
|
45
|
+
return await viemLoginWrapper(loginInfo);
|
|
46
|
+
}
|
|
41
47
|
case WalletMode.Cardano: {
|
|
42
48
|
return await cardanoLoginWrapper(loginInfo);
|
|
43
49
|
}
|
|
50
|
+
case WalletMode.CardanoLocal: {
|
|
51
|
+
return await cardanoLocalLoginWrapper(loginInfo);
|
|
52
|
+
}
|
|
44
53
|
case WalletMode.Polkadot: {
|
|
45
54
|
return await polkadotLoginWrapper(loginInfo);
|
|
46
55
|
}
|
|
@@ -56,6 +65,9 @@ async function login(loginInfo: LoginInfo): Promise<Result<IProvider<unknown>>>
|
|
|
56
65
|
case WalletMode.Midnight: {
|
|
57
66
|
return await midnightLoginWrapper(loginInfo);
|
|
58
67
|
}
|
|
68
|
+
case WalletMode.MidnightLocal: {
|
|
69
|
+
return await midnightLocalLoginWrapper(loginInfo);
|
|
70
|
+
}
|
|
59
71
|
default:
|
|
60
72
|
throw new Error(`Unsupported wallet mode: ${(loginInfo as any).mode}`);
|
|
61
73
|
}
|