@0xsequence/wallet-core 3.0.0-beta.13 → 3.0.0-beta.15
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +20 -0
- package/dist/bundler/bundlers/pimlico.d.ts +2 -1
- package/dist/bundler/bundlers/pimlico.d.ts.map +1 -1
- package/dist/bundler/bundlers/pimlico.js +8 -2
- package/dist/env.d.ts +22 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +42 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/signers/passkey.d.ts +10 -2
- package/dist/signers/passkey.d.ts.map +1 -1
- package/dist/signers/passkey.js +12 -6
- package/dist/signers/pk/encrypted.d.ts +13 -2
- package/dist/signers/pk/encrypted.d.ts.map +1 -1
- package/dist/signers/pk/encrypted.js +94 -15
- package/dist/state/local/indexed-db.d.ts +4 -1
- package/dist/state/local/indexed-db.d.ts.map +1 -1
- package/dist/state/local/indexed-db.js +12 -2
- package/dist/state/remote/dev-http.d.ts +2 -1
- package/dist/state/remote/dev-http.d.ts.map +1 -1
- package/dist/state/remote/dev-http.js +8 -2
- package/dist/state/sequence/index.d.ts +2 -1
- package/dist/state/sequence/index.d.ts.map +1 -1
- package/dist/state/sequence/index.js +6 -2
- package/package.json +4 -4
- package/src/bundler/bundlers/pimlico.ts +8 -2
- package/src/env.ts +68 -0
- package/src/index.ts +1 -0
- package/src/signers/passkey.ts +20 -4
- package/src/signers/pk/encrypted.ts +103 -14
- package/src/state/local/indexed-db.ts +15 -2
- package/src/state/remote/dev-http.ts +8 -2
- package/src/state/sequence/index.ts +7 -3
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @0xsequence/wallet-core
|
|
2
2
|
|
|
3
|
+
## 3.0.0-beta.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- New chains, minor fixes
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @0xsequence/guard@3.0.0-beta.15
|
|
10
|
+
- @0xsequence/relayer@3.0.0-beta.15
|
|
11
|
+
- @0xsequence/wallet-primitives@3.0.0-beta.15
|
|
12
|
+
|
|
13
|
+
## 3.0.0-beta.14
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Relayer fee options fix
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
- @0xsequence/guard@3.0.0-beta.14
|
|
20
|
+
- @0xsequence/relayer@3.0.0-beta.14
|
|
21
|
+
- @0xsequence/wallet-primitives@3.0.0-beta.14
|
|
22
|
+
|
|
3
23
|
## 3.0.0-beta.13
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -8,7 +8,8 @@ export declare class PimlicoBundler implements Bundler {
|
|
|
8
8
|
readonly id: string;
|
|
9
9
|
readonly provider: Provider.Provider;
|
|
10
10
|
readonly bundlerRpcUrl: string;
|
|
11
|
-
|
|
11
|
+
private readonly fetcher;
|
|
12
|
+
constructor(bundlerRpcUrl: string, provider: Provider.Provider | string, fetcher?: typeof fetch);
|
|
12
13
|
isAvailable(entrypoint: Address.Address, chainId: number): Promise<boolean>;
|
|
13
14
|
relay(entrypoint: Address.Address, userOperation: UserOperation.RpcV07): Promise<{
|
|
14
15
|
opHash: Hex.Hex;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pimlico.d.ts","sourceRoot":"","sources":["../../../src/bundler/bundlers/pimlico.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAgB,MAAM,IAAI,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAa7C,qBAAa,cAAe,YAAW,OAAO;IAC5C,SAAgB,IAAI,EAAE,SAAS,CAAY;IAC3C,SAAgB,EAAE,EAAE,MAAM,CAAA;IAE1B,SAAgB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAA;IAC3C,SAAgB,aAAa,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"pimlico.d.ts","sourceRoot":"","sources":["../../../src/bundler/bundlers/pimlico.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAgB,MAAM,IAAI,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAa7C,qBAAa,cAAe,YAAW,OAAO;IAC5C,SAAgB,IAAI,EAAE,SAAS,CAAY;IAC3C,SAAgB,EAAE,EAAE,MAAM,CAAA;IAE1B,SAAgB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAA;IAC3C,SAAgB,aAAa,EAAE,MAAM,CAAA;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;gBAE1B,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK;IAWzF,WAAW,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAa3E,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAA;KAAE,CAAC;IAKrG,cAAc,CAClB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,OAAO,CAAC,YAAY,GAC5B,OAAO,CACR;QACE,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAA;QACpC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAA;KAC9B,EAAE,CACJ;IAgCD,OAAO,CAAC,4BAA4B;IAiB9B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC;YA4DnE,UAAU;CAWzB"}
|
|
@@ -6,10 +6,16 @@ export class PimlicoBundler {
|
|
|
6
6
|
id;
|
|
7
7
|
provider;
|
|
8
8
|
bundlerRpcUrl;
|
|
9
|
-
|
|
9
|
+
fetcher;
|
|
10
|
+
constructor(bundlerRpcUrl, provider, fetcher) {
|
|
10
11
|
this.id = `pimlico-erc4337-${bundlerRpcUrl}`;
|
|
11
12
|
this.provider = typeof provider === 'string' ? Provider.from(RpcTransport.fromHttp(provider)) : provider;
|
|
12
13
|
this.bundlerRpcUrl = bundlerRpcUrl;
|
|
14
|
+
const resolvedFetch = fetcher ?? globalThis.fetch;
|
|
15
|
+
if (!resolvedFetch) {
|
|
16
|
+
throw new Error('fetch is not available');
|
|
17
|
+
}
|
|
18
|
+
this.fetcher = resolvedFetch;
|
|
13
19
|
}
|
|
14
20
|
async isAvailable(entrypoint, chainId) {
|
|
15
21
|
const [bundlerChainId, supportedEntryPoints] = await Promise.all([
|
|
@@ -114,7 +120,7 @@ export class PimlicoBundler {
|
|
|
114
120
|
}
|
|
115
121
|
async bundlerRpc(method, params) {
|
|
116
122
|
const body = JSON.stringify({ jsonrpc: '2.0', id: 1, method, params });
|
|
117
|
-
const res = await
|
|
123
|
+
const res = await this.fetcher(this.bundlerRpcUrl, {
|
|
118
124
|
method: 'POST',
|
|
119
125
|
headers: { 'content-type': 'application/json' },
|
|
120
126
|
body,
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type StorageLike = {
|
|
2
|
+
getItem: (key: string) => string | null;
|
|
3
|
+
setItem: (key: string, value: string) => void;
|
|
4
|
+
removeItem: (key: string) => void;
|
|
5
|
+
};
|
|
6
|
+
export type CryptoLike = {
|
|
7
|
+
subtle: SubtleCrypto;
|
|
8
|
+
getRandomValues: <T extends ArrayBufferView>(array: T) => T;
|
|
9
|
+
};
|
|
10
|
+
export type TextEncodingLike = {
|
|
11
|
+
TextEncoder: typeof TextEncoder;
|
|
12
|
+
TextDecoder: typeof TextDecoder;
|
|
13
|
+
};
|
|
14
|
+
export type CoreEnv = {
|
|
15
|
+
fetch?: typeof fetch;
|
|
16
|
+
crypto?: CryptoLike;
|
|
17
|
+
storage?: StorageLike;
|
|
18
|
+
indexedDB?: IDBFactory;
|
|
19
|
+
text?: Partial<TextEncodingLike>;
|
|
20
|
+
};
|
|
21
|
+
export declare function resolveCoreEnv(env?: CoreEnv): CoreEnv;
|
|
22
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACvC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,YAAY,CAAA;IACpB,eAAe,EAAE,CAAC,CAAC,SAAS,eAAe,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA;CAC5D,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,OAAO,WAAW,CAAA;IAC/B,WAAW,EAAE,OAAO,WAAW,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,SAAS,CAAC,EAAE,UAAU,CAAA;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;CACjC,CAAA;AAYD,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,OAAO,CAiCrD"}
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
function isStorageLike(value) {
|
|
2
|
+
if (!value || typeof value !== 'object')
|
|
3
|
+
return false;
|
|
4
|
+
const candidate = value;
|
|
5
|
+
return (typeof candidate.getItem === 'function' &&
|
|
6
|
+
typeof candidate.setItem === 'function' &&
|
|
7
|
+
typeof candidate.removeItem === 'function');
|
|
8
|
+
}
|
|
9
|
+
export function resolveCoreEnv(env) {
|
|
10
|
+
const globalObj = globalThis;
|
|
11
|
+
const windowObj = typeof window !== 'undefined' ? window : (globalObj.window ?? {});
|
|
12
|
+
let storage;
|
|
13
|
+
let text;
|
|
14
|
+
if (isStorageLike(env?.storage)) {
|
|
15
|
+
storage = env.storage;
|
|
16
|
+
}
|
|
17
|
+
else if (isStorageLike(windowObj.localStorage)) {
|
|
18
|
+
storage = windowObj.localStorage;
|
|
19
|
+
}
|
|
20
|
+
else if (isStorageLike(globalObj.localStorage)) {
|
|
21
|
+
storage = globalObj.localStorage;
|
|
22
|
+
}
|
|
23
|
+
if (env?.text) {
|
|
24
|
+
if (!env.text.TextEncoder || !env.text.TextDecoder) {
|
|
25
|
+
throw new Error('env.text must provide both TextEncoder and TextDecoder');
|
|
26
|
+
}
|
|
27
|
+
text = env.text;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
text = {
|
|
31
|
+
TextEncoder: windowObj.TextEncoder ?? globalObj.TextEncoder,
|
|
32
|
+
TextDecoder: windowObj.TextDecoder ?? globalObj.TextDecoder,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
fetch: env?.fetch ?? windowObj.fetch ?? globalObj.fetch,
|
|
37
|
+
crypto: env?.crypto ?? windowObj.crypto ?? globalObj.crypto,
|
|
38
|
+
storage,
|
|
39
|
+
indexedDB: env?.indexedDB ?? windowObj.indexedDB ?? globalObj.indexedDB,
|
|
40
|
+
text,
|
|
41
|
+
};
|
|
42
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,6 @@ export * as State from './state/index.js';
|
|
|
4
4
|
export * as Bundler from './bundler/index.js';
|
|
5
5
|
export * as Envelope from './envelope.js';
|
|
6
6
|
export * as Utils from './utils/index.js';
|
|
7
|
+
export * from './env.js';
|
|
7
8
|
export { type ExplicitSessionConfig, type ExplicitSession, type ImplicitSession, type Session, } from './utils/session/types.js';
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAE3B,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAA;AACzC,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,OAAO,GACb,MAAM,0BAA0B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAE3B,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAA;AACzC,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAA;AACzC,cAAc,UAAU,CAAA;AACxB,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,OAAO,GACb,MAAM,0BAA0B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { Hex, Address } from 'ox';
|
|
2
2
|
import { Payload, Extensions } from '@0xsequence/wallet-primitives';
|
|
3
3
|
import type { Signature as SignatureTypes } from '@0xsequence/wallet-primitives';
|
|
4
|
+
import { WebAuthnP256 } from 'ox';
|
|
4
5
|
import { State } from '../index.js';
|
|
5
6
|
import { SapientSigner, Witnessable } from './index.js';
|
|
7
|
+
export type WebAuthnLike = Pick<typeof WebAuthnP256, 'createCredential' | 'sign'>;
|
|
6
8
|
export type PasskeyOptions = {
|
|
7
9
|
extensions: Pick<Extensions.Extensions, 'passkeys'>;
|
|
8
10
|
publicKey: Extensions.Passkeys.PublicKey;
|
|
9
11
|
credentialId: string;
|
|
10
12
|
embedMetadata?: boolean;
|
|
11
13
|
metadata?: Extensions.Passkeys.PasskeyMetadata;
|
|
14
|
+
webauthn?: WebAuthnLike;
|
|
12
15
|
};
|
|
13
16
|
export type CreatePasskeyOptions = {
|
|
14
17
|
stateProvider?: State.Provider;
|
|
15
18
|
requireUserVerification?: boolean;
|
|
16
19
|
credentialName?: string;
|
|
17
20
|
embedMetadata?: boolean;
|
|
21
|
+
webauthn?: WebAuthnLike;
|
|
22
|
+
};
|
|
23
|
+
export type FindPasskeyOptions = {
|
|
24
|
+
webauthn?: WebAuthnLike;
|
|
18
25
|
};
|
|
19
26
|
export type WitnessMessage = {
|
|
20
27
|
action: 'consent-to-be-part-of-wallet';
|
|
@@ -31,10 +38,11 @@ export declare class Passkey implements SapientSigner, Witnessable {
|
|
|
31
38
|
readonly imageHash: Hex.Hex;
|
|
32
39
|
readonly embedMetadata: boolean;
|
|
33
40
|
readonly metadata?: Extensions.Passkeys.PasskeyMetadata;
|
|
41
|
+
private readonly webauthn;
|
|
34
42
|
constructor(options: PasskeyOptions);
|
|
35
|
-
static loadFromWitness(stateReader: State.Reader, extensions: Pick<Extensions.Extensions, 'passkeys'>, wallet: Address.Address, imageHash: Hex.Hex): Promise<Passkey>;
|
|
43
|
+
static loadFromWitness(stateReader: State.Reader, extensions: Pick<Extensions.Extensions, 'passkeys'>, wallet: Address.Address, imageHash: Hex.Hex, options?: FindPasskeyOptions): Promise<Passkey>;
|
|
36
44
|
static create(extensions: Pick<Extensions.Extensions, 'passkeys'>, options?: CreatePasskeyOptions): Promise<Passkey>;
|
|
37
|
-
static find(stateReader: State.Reader, extensions: Pick<Extensions.Extensions, 'passkeys'
|
|
45
|
+
static find(stateReader: State.Reader, extensions: Pick<Extensions.Extensions, 'passkeys'>, options?: FindPasskeyOptions): Promise<Passkey | undefined>;
|
|
38
46
|
signSapient(wallet: Address.Address, chainId: number, payload: Payload.Parented, imageHash: Hex.Hex): Promise<SignatureTypes.SignatureOfSapientSignerLeaf>;
|
|
39
47
|
witness(stateWriter: State.Writer, wallet: Address.Address, extra?: Object): Promise<void>;
|
|
40
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passkey.d.ts","sourceRoot":"","sources":["../../src/signers/passkey.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAS,OAAO,EAAc,MAAM,IAAI,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,+BAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"passkey.d.ts","sourceRoot":"","sources":["../../src/signers/passkey.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAS,OAAO,EAAc,MAAM,IAAI,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAEvD,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,YAAY,EAAE,kBAAkB,GAAG,MAAM,CAAC,CAAA;AAEjF,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;IACnD,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAA;IACxC,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAA;IAC9C,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,aAAa,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAA;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,8BAA8B,CAAA;IACtC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAA;IACvB,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAA;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAA;CAC/C,CAAA;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,cAAc,CAO5E;AAED,qBAAa,OAAQ,YAAW,aAAa,EAAE,WAAW;IACxD,SAAgB,YAAY,EAAE,MAAM,CAAA;IAEpC,SAAgB,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAA;IACxD,SAAgB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IACxC,SAAgB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAA;IAClC,SAAgB,aAAa,EAAE,OAAO,CAAA;IACtC,SAAgB,QAAQ,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAA;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;gBAE3B,OAAO,EAAE,cAAc;WAUtB,eAAe,CAC1B,WAAW,EAAE,KAAK,CAAC,MAAM,EACzB,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,EACnD,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,SAAS,EAAE,GAAG,CAAC,GAAG,EAClB,OAAO,CAAC,EAAE,kBAAkB;WAmCjB,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE,oBAAoB;WAsC1F,IAAI,CACf,WAAW,EAAE,KAAK,CAAC,MAAM,EACzB,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,EACnD,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IA0FzB,WAAW,CACf,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,QAAQ,EACzB,SAAS,EAAE,GAAG,CAAC,GAAG,GACjB,OAAO,CAAC,cAAc,CAAC,4BAA4B,CAAC;IAkCjD,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAqBjG"}
|
package/dist/signers/passkey.js
CHANGED
|
@@ -14,6 +14,7 @@ export class Passkey {
|
|
|
14
14
|
imageHash;
|
|
15
15
|
embedMetadata;
|
|
16
16
|
metadata;
|
|
17
|
+
webauthn;
|
|
17
18
|
constructor(options) {
|
|
18
19
|
this.address = options.extensions.passkeys;
|
|
19
20
|
this.publicKey = options.publicKey;
|
|
@@ -21,8 +22,9 @@ export class Passkey {
|
|
|
21
22
|
this.embedMetadata = options.embedMetadata ?? false;
|
|
22
23
|
this.imageHash = Extensions.Passkeys.rootFor(options.publicKey);
|
|
23
24
|
this.metadata = options.metadata;
|
|
25
|
+
this.webauthn = options.webauthn ?? WebAuthnP256;
|
|
24
26
|
}
|
|
25
|
-
static async loadFromWitness(stateReader, extensions, wallet, imageHash) {
|
|
27
|
+
static async loadFromWitness(stateReader, extensions, wallet, imageHash, options) {
|
|
26
28
|
// In the witness we will find the public key, and may find the credential id
|
|
27
29
|
const witness = await stateReader.getWitnessForSapient(wallet, extensions.passkeys, imageHash);
|
|
28
30
|
if (!witness) {
|
|
@@ -47,11 +49,13 @@ export class Passkey {
|
|
|
47
49
|
publicKey: message.publicKey,
|
|
48
50
|
embedMetadata: decodedSignature.embedMetadata,
|
|
49
51
|
metadata,
|
|
52
|
+
webauthn: options?.webauthn,
|
|
50
53
|
});
|
|
51
54
|
}
|
|
52
55
|
static async create(extensions, options) {
|
|
56
|
+
const webauthn = options?.webauthn ?? WebAuthnP256;
|
|
53
57
|
const name = options?.credentialName ?? `Sequence (${Date.now()})`;
|
|
54
|
-
const credential = await
|
|
58
|
+
const credential = await webauthn.createCredential({
|
|
55
59
|
user: {
|
|
56
60
|
name,
|
|
57
61
|
},
|
|
@@ -72,14 +76,16 @@ export class Passkey {
|
|
|
72
76
|
},
|
|
73
77
|
embedMetadata: options?.embedMetadata,
|
|
74
78
|
metadata,
|
|
79
|
+
webauthn,
|
|
75
80
|
});
|
|
76
81
|
if (options?.stateProvider) {
|
|
77
82
|
await options.stateProvider.saveTree(Extensions.Passkeys.toTree(passkey.publicKey));
|
|
78
83
|
}
|
|
79
84
|
return passkey;
|
|
80
85
|
}
|
|
81
|
-
static async find(stateReader, extensions) {
|
|
82
|
-
const
|
|
86
|
+
static async find(stateReader, extensions, options) {
|
|
87
|
+
const webauthn = options?.webauthn ?? WebAuthnP256;
|
|
88
|
+
const response = await webauthn.sign({ challenge: Hex.random(32) });
|
|
83
89
|
if (!response.raw)
|
|
84
90
|
throw new Error('No credential returned');
|
|
85
91
|
const authenticatorDataBytes = Bytes.fromHex(response.metadata.authenticatorData);
|
|
@@ -147,7 +153,7 @@ export class Passkey {
|
|
|
147
153
|
if (flattened.length > 1) {
|
|
148
154
|
console.warn('Multiple signers found for passkey', flattened);
|
|
149
155
|
}
|
|
150
|
-
return Passkey.loadFromWitness(stateReader, extensions, flattened[0].wallet, flattened[0].imageHash);
|
|
156
|
+
return Passkey.loadFromWitness(stateReader, extensions, flattened[0].wallet, flattened[0].imageHash, options);
|
|
151
157
|
}
|
|
152
158
|
async signSapient(wallet, chainId, payload, imageHash) {
|
|
153
159
|
if (this.imageHash !== imageHash) {
|
|
@@ -155,7 +161,7 @@ export class Passkey {
|
|
|
155
161
|
throw new Error('Unexpected image hash');
|
|
156
162
|
}
|
|
157
163
|
const challenge = Hex.fromBytes(Payload.hash(wallet, chainId, payload));
|
|
158
|
-
const response = await
|
|
164
|
+
const response = await this.webauthn.sign({
|
|
159
165
|
challenge,
|
|
160
166
|
credentialId: this.credentialId,
|
|
161
167
|
userVerification: this.publicKey.requireUserVerification ? 'required' : 'discouraged',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Address, PublicKey, Bytes } from 'ox';
|
|
2
|
+
import { type CoreEnv } from '../../env.js';
|
|
2
3
|
import { PkStore } from './index.js';
|
|
3
4
|
export interface EncryptedData {
|
|
4
5
|
iv: BufferSource;
|
|
@@ -9,11 +10,17 @@ export interface EncryptedData {
|
|
|
9
10
|
}
|
|
10
11
|
export declare class EncryptedPksDb {
|
|
11
12
|
private readonly localStorageKeyPrefix;
|
|
13
|
+
private readonly env?;
|
|
12
14
|
private tableName;
|
|
13
15
|
private dbName;
|
|
14
16
|
private dbVersion;
|
|
15
|
-
constructor(localStorageKeyPrefix?: string, tableName?: string);
|
|
17
|
+
constructor(localStorageKeyPrefix?: string, tableName?: string, env?: CoreEnv | undefined);
|
|
16
18
|
private computeDbKey;
|
|
19
|
+
private getIndexedDB;
|
|
20
|
+
private getStorage;
|
|
21
|
+
private getCrypto;
|
|
22
|
+
private getTextEncoderCtor;
|
|
23
|
+
private getTextDecoderCtor;
|
|
17
24
|
private openDB;
|
|
18
25
|
private putData;
|
|
19
26
|
private getData;
|
|
@@ -26,7 +33,11 @@ export declare class EncryptedPksDb {
|
|
|
26
33
|
}
|
|
27
34
|
export declare class EncryptedPkStore implements PkStore {
|
|
28
35
|
private readonly encrypted;
|
|
29
|
-
|
|
36
|
+
private readonly env?;
|
|
37
|
+
constructor(encrypted: EncryptedData, env?: CoreEnv | undefined);
|
|
38
|
+
private getStorage;
|
|
39
|
+
private getCrypto;
|
|
40
|
+
private getTextDecoderCtor;
|
|
30
41
|
address(): Address.Address;
|
|
31
42
|
publicKey(): PublicKey.PublicKey;
|
|
32
43
|
signDigest(digest: Bytes.Bytes): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encrypted.d.ts","sourceRoot":"","sources":["../../../src/signers/pk/encrypted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,SAAS,EAAa,KAAK,EAAE,MAAM,IAAI,CAAA;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,YAAY,CAAA;IAChB,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IACxB,SAAS,EAAE,SAAS,CAAC,SAAS,CAAA;CAC/B;AAED,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;
|
|
1
|
+
{"version":3,"file":"encrypted.d.ts","sourceRoot":"","sources":["../../../src/signers/pk/encrypted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,SAAS,EAAa,KAAK,EAAE,MAAM,IAAI,CAAA;AAC9D,OAAO,EAAkB,KAAK,OAAO,EAA4D,MAAM,cAAc,CAAA;AACrH,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,YAAY,CAAA;IAChB,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IACxB,SAAS,EAAE,SAAS,CAAC,SAAS,CAAA;CAC/B;AAED,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAEtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;IAPvB,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,SAAS,CAAY;gBAGV,qBAAqB,GAAE,MAAoB,EAC5D,SAAS,GAAE,MAAe,EACT,GAAG,CAAC,EAAE,OAAO,YAAA;IAKhC,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,MAAM;YAcA,OAAO;YAWP,OAAO;YAWP,UAAU;IAWlB,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC;IAqC1C,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAK/E,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;IAMpF,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAK3C,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO;CAMtC;AAED,qBAAa,gBAAiB,YAAW,OAAO;IAE5C,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;gBADJ,SAAS,EAAE,aAAa,EACxB,GAAG,CAAC,EAAE,OAAO,YAAA;IAGhC,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,IAAI,OAAO,CAAC,OAAO;IAI1B,SAAS,IAAI,SAAS,CAAC,SAAS;IAI1B,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAkB1F"}
|
|
@@ -1,19 +1,67 @@
|
|
|
1
1
|
import { Hex, Address, Secp256k1 } from 'ox';
|
|
2
|
+
import { resolveCoreEnv } from '../../env.js';
|
|
2
3
|
export class EncryptedPksDb {
|
|
3
4
|
localStorageKeyPrefix;
|
|
5
|
+
env;
|
|
4
6
|
tableName;
|
|
5
7
|
dbName = 'pk-db';
|
|
6
8
|
dbVersion = 1;
|
|
7
|
-
constructor(localStorageKeyPrefix = 'e_pk_key_', tableName = 'e_pk') {
|
|
9
|
+
constructor(localStorageKeyPrefix = 'e_pk_key_', tableName = 'e_pk', env) {
|
|
8
10
|
this.localStorageKeyPrefix = localStorageKeyPrefix;
|
|
11
|
+
this.env = env;
|
|
9
12
|
this.tableName = tableName;
|
|
10
13
|
}
|
|
11
14
|
computeDbKey(address) {
|
|
12
15
|
return `pk_${address.toLowerCase()}`;
|
|
13
16
|
}
|
|
17
|
+
getIndexedDB() {
|
|
18
|
+
const globalObj = globalThis;
|
|
19
|
+
const indexedDb = this.env?.indexedDB ?? globalObj.indexedDB ?? globalObj.window?.indexedDB;
|
|
20
|
+
if (!indexedDb) {
|
|
21
|
+
throw new Error('indexedDB is not available');
|
|
22
|
+
}
|
|
23
|
+
return indexedDb;
|
|
24
|
+
}
|
|
25
|
+
getStorage() {
|
|
26
|
+
const storage = resolveCoreEnv(this.env).storage;
|
|
27
|
+
if (!storage) {
|
|
28
|
+
throw new Error('storage is not available');
|
|
29
|
+
}
|
|
30
|
+
return storage;
|
|
31
|
+
}
|
|
32
|
+
getCrypto() {
|
|
33
|
+
const globalObj = globalThis;
|
|
34
|
+
const crypto = this.env?.crypto ?? globalObj.crypto ?? globalObj.window?.crypto;
|
|
35
|
+
if (!crypto?.subtle || !crypto?.getRandomValues) {
|
|
36
|
+
throw new Error('crypto.subtle is not available');
|
|
37
|
+
}
|
|
38
|
+
return crypto;
|
|
39
|
+
}
|
|
40
|
+
getTextEncoderCtor() {
|
|
41
|
+
const globalObj = globalThis;
|
|
42
|
+
if (this.env?.text && (!this.env.text.TextEncoder || !this.env.text.TextDecoder)) {
|
|
43
|
+
throw new Error('env.text must provide both TextEncoder and TextDecoder');
|
|
44
|
+
}
|
|
45
|
+
const encoderCtor = this.env?.text?.TextEncoder ?? globalObj.TextEncoder ?? globalObj.window?.TextEncoder;
|
|
46
|
+
if (!encoderCtor) {
|
|
47
|
+
throw new Error('TextEncoder is not available');
|
|
48
|
+
}
|
|
49
|
+
return encoderCtor;
|
|
50
|
+
}
|
|
51
|
+
getTextDecoderCtor() {
|
|
52
|
+
const globalObj = globalThis;
|
|
53
|
+
if (this.env?.text && (!this.env.text.TextEncoder || !this.env.text.TextDecoder)) {
|
|
54
|
+
throw new Error('env.text must provide both TextEncoder and TextDecoder');
|
|
55
|
+
}
|
|
56
|
+
const decoderCtor = this.env?.text?.TextDecoder ?? globalObj.TextDecoder ?? globalObj.window?.TextDecoder;
|
|
57
|
+
if (!decoderCtor) {
|
|
58
|
+
throw new Error('TextDecoder is not available');
|
|
59
|
+
}
|
|
60
|
+
return decoderCtor;
|
|
61
|
+
}
|
|
14
62
|
openDB() {
|
|
15
63
|
return new Promise((resolve, reject) => {
|
|
16
|
-
const request =
|
|
64
|
+
const request = this.getIndexedDB().open(this.dbName, this.dbVersion);
|
|
17
65
|
request.onupgradeneeded = () => {
|
|
18
66
|
const db = request.result;
|
|
19
67
|
if (!db.objectStoreNames.contains(this.tableName)) {
|
|
@@ -55,7 +103,10 @@ export class EncryptedPksDb {
|
|
|
55
103
|
});
|
|
56
104
|
}
|
|
57
105
|
async generateAndStore() {
|
|
58
|
-
const
|
|
106
|
+
const crypto = this.getCrypto();
|
|
107
|
+
const storage = this.getStorage();
|
|
108
|
+
const TextEncoderCtor = this.getTextEncoderCtor();
|
|
109
|
+
const encryptionKey = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, [
|
|
59
110
|
'encrypt',
|
|
60
111
|
'decrypt',
|
|
61
112
|
]);
|
|
@@ -63,12 +114,12 @@ export class EncryptedPksDb {
|
|
|
63
114
|
const publicKey = Secp256k1.getPublicKey({ privateKey });
|
|
64
115
|
const address = Address.fromPublicKey(publicKey);
|
|
65
116
|
const keyPointer = this.localStorageKeyPrefix + address;
|
|
66
|
-
const exportedKey = await
|
|
67
|
-
|
|
68
|
-
const encoder = new
|
|
117
|
+
const exportedKey = await crypto.subtle.exportKey('jwk', encryptionKey);
|
|
118
|
+
storage.setItem(keyPointer, JSON.stringify(exportedKey));
|
|
119
|
+
const encoder = new TextEncoderCtor();
|
|
69
120
|
const encodedPk = encoder.encode(privateKey);
|
|
70
|
-
const iv =
|
|
71
|
-
const encryptedBuffer = await
|
|
121
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
122
|
+
const encryptedBuffer = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, encryptionKey, encodedPk);
|
|
72
123
|
const encrypted = {
|
|
73
124
|
iv,
|
|
74
125
|
data: encryptedBuffer,
|
|
@@ -88,7 +139,7 @@ export class EncryptedPksDb {
|
|
|
88
139
|
const entry = await this.getEncryptedEntry(address);
|
|
89
140
|
if (!entry)
|
|
90
141
|
return;
|
|
91
|
-
return new EncryptedPkStore(entry);
|
|
142
|
+
return new EncryptedPkStore(entry, this.env);
|
|
92
143
|
}
|
|
93
144
|
async listAddresses() {
|
|
94
145
|
const allEntries = await this.getAllData();
|
|
@@ -98,13 +149,38 @@ export class EncryptedPksDb {
|
|
|
98
149
|
const dbKey = this.computeDbKey(address);
|
|
99
150
|
await this.putData(dbKey, undefined);
|
|
100
151
|
const keyPointer = this.localStorageKeyPrefix + address;
|
|
101
|
-
|
|
152
|
+
this.getStorage().removeItem(keyPointer);
|
|
102
153
|
}
|
|
103
154
|
}
|
|
104
155
|
export class EncryptedPkStore {
|
|
105
156
|
encrypted;
|
|
106
|
-
|
|
157
|
+
env;
|
|
158
|
+
constructor(encrypted, env) {
|
|
107
159
|
this.encrypted = encrypted;
|
|
160
|
+
this.env = env;
|
|
161
|
+
}
|
|
162
|
+
getStorage() {
|
|
163
|
+
const storage = resolveCoreEnv(this.env).storage;
|
|
164
|
+
if (!storage) {
|
|
165
|
+
throw new Error('storage is not available');
|
|
166
|
+
}
|
|
167
|
+
return storage;
|
|
168
|
+
}
|
|
169
|
+
getCrypto() {
|
|
170
|
+
const globalObj = globalThis;
|
|
171
|
+
const crypto = this.env?.crypto ?? globalObj.crypto ?? globalObj.window?.crypto;
|
|
172
|
+
if (!crypto?.subtle) {
|
|
173
|
+
throw new Error('crypto.subtle is not available');
|
|
174
|
+
}
|
|
175
|
+
return crypto;
|
|
176
|
+
}
|
|
177
|
+
getTextDecoderCtor() {
|
|
178
|
+
const globalObj = globalThis;
|
|
179
|
+
const decoderCtor = this.env?.text?.TextDecoder ?? globalObj.TextDecoder ?? globalObj.window?.TextDecoder;
|
|
180
|
+
if (!decoderCtor) {
|
|
181
|
+
throw new Error('TextDecoder is not available');
|
|
182
|
+
}
|
|
183
|
+
return decoderCtor;
|
|
108
184
|
}
|
|
109
185
|
address() {
|
|
110
186
|
return this.encrypted.address;
|
|
@@ -113,13 +189,16 @@ export class EncryptedPkStore {
|
|
|
113
189
|
return this.encrypted.publicKey;
|
|
114
190
|
}
|
|
115
191
|
async signDigest(digest) {
|
|
116
|
-
const
|
|
192
|
+
const storage = this.getStorage();
|
|
193
|
+
const crypto = this.getCrypto();
|
|
194
|
+
const TextDecoderCtor = this.getTextDecoderCtor();
|
|
195
|
+
const keyJson = storage.getItem(this.encrypted.keyPointer);
|
|
117
196
|
if (!keyJson)
|
|
118
197
|
throw new Error('Encryption key not found in localStorage');
|
|
119
198
|
const jwk = JSON.parse(keyJson);
|
|
120
|
-
const encryptionKey = await
|
|
121
|
-
const decryptedBuffer = await
|
|
122
|
-
const decoder = new
|
|
199
|
+
const encryptionKey = await crypto.subtle.importKey('jwk', jwk, { name: 'AES-GCM' }, false, ['decrypt']);
|
|
200
|
+
const decryptedBuffer = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: this.encrypted.iv }, encryptionKey, this.encrypted.data);
|
|
201
|
+
const decoder = new TextDecoderCtor();
|
|
123
202
|
const privateKey = decoder.decode(decryptedBuffer);
|
|
124
203
|
return Secp256k1.sign({ payload: digest, privateKey });
|
|
125
204
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Context, Payload, Signature, Config, GenericTree } from '@0xsequence/wallet-primitives';
|
|
2
2
|
import { Address, Hex } from 'ox';
|
|
3
|
+
import type { CoreEnv } from '../../env.js';
|
|
3
4
|
import { Store } from './index.js';
|
|
4
5
|
export declare class IndexedDbStore implements Store {
|
|
6
|
+
private readonly env?;
|
|
5
7
|
private _db;
|
|
6
8
|
private dbName;
|
|
7
|
-
constructor(dbName?: string);
|
|
9
|
+
constructor(dbName?: string, env?: CoreEnv | undefined);
|
|
10
|
+
private getIndexedDB;
|
|
8
11
|
private openDB;
|
|
9
12
|
private get;
|
|
10
13
|
private put;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexed-db.d.ts","sourceRoot":"","sources":["../../../src/state/local/indexed-db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAChG,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,IAAI,CAAA;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAYlC,qBAAa,cAAe,YAAW,KAAK;
|
|
1
|
+
{"version":3,"file":"indexed-db.d.ts","sourceRoot":"","sources":["../../../src/state/local/indexed-db.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,16 +8,26 @@ const STORE_SAPIENT_SIGNER_SUBDIGESTS = 'sapientSignerSubdigests';
|
|
|
8
8
|
const STORE_SAPIENT_SIGNATURES = 'sapientSignatures';
|
|
9
9
|
const STORE_TREES = 'trees';
|
|
10
10
|
export class IndexedDbStore {
|
|
11
|
+
env;
|
|
11
12
|
_db = null;
|
|
12
13
|
dbName;
|
|
13
|
-
constructor(dbName = 'sequence-indexeddb') {
|
|
14
|
+
constructor(dbName = 'sequence-indexeddb', env) {
|
|
15
|
+
this.env = env;
|
|
14
16
|
this.dbName = dbName;
|
|
15
17
|
}
|
|
18
|
+
getIndexedDB() {
|
|
19
|
+
const globalObj = globalThis;
|
|
20
|
+
const indexedDb = this.env?.indexedDB ?? globalObj.indexedDB ?? globalObj.window?.indexedDB;
|
|
21
|
+
if (!indexedDb) {
|
|
22
|
+
throw new Error('indexedDB is not available');
|
|
23
|
+
}
|
|
24
|
+
return indexedDb;
|
|
25
|
+
}
|
|
16
26
|
async openDB() {
|
|
17
27
|
if (this._db)
|
|
18
28
|
return this._db;
|
|
19
29
|
return new Promise((resolve, reject) => {
|
|
20
|
-
const request =
|
|
30
|
+
const request = this.getIndexedDB().open(this.dbName, DB_VERSION);
|
|
21
31
|
request.onupgradeneeded = () => {
|
|
22
32
|
const db = request.result;
|
|
23
33
|
if (!db.objectStoreNames.contains(STORE_CONFIGS)) {
|
|
@@ -3,7 +3,8 @@ import { Config, Context, GenericTree, Payload, Signature } from '@0xsequence/wa
|
|
|
3
3
|
import { Provider } from '../index.js';
|
|
4
4
|
export declare class DevHttpProvider implements Provider {
|
|
5
5
|
private readonly baseUrl;
|
|
6
|
-
|
|
6
|
+
private readonly fetcher;
|
|
7
|
+
constructor(baseUrl: string, fetcher?: typeof fetch);
|
|
7
8
|
private request;
|
|
8
9
|
getConfiguration(imageHash: Hex.Hex): Promise<Config.Config | undefined>;
|
|
9
10
|
getDeploy(wallet: Address.Address): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-http.d.ts","sourceRoot":"","sources":["../../../src/state/remote/dev-http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,IAAI,CAAA;AACjC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAS,MAAM,+BAA+B,CAAA;AACvG,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;
|
|
1
|
+
{"version":3,"file":"dev-http.d.ts","sourceRoot":"","sources":["../../../src/state/remote/dev-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { Utils } from '@0xsequence/wallet-primitives';
|
|
2
2
|
export class DevHttpProvider {
|
|
3
3
|
baseUrl;
|
|
4
|
-
|
|
4
|
+
fetcher;
|
|
5
|
+
constructor(baseUrl, fetcher) {
|
|
5
6
|
// Remove trailing slash if present
|
|
6
7
|
this.baseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
8
|
+
const resolvedFetch = fetcher ?? globalThis.fetch;
|
|
9
|
+
if (!resolvedFetch) {
|
|
10
|
+
throw new Error('fetch is not available');
|
|
11
|
+
}
|
|
12
|
+
this.fetcher = resolvedFetch;
|
|
7
13
|
}
|
|
8
14
|
async request(method, path, body) {
|
|
9
15
|
const url = `${this.baseUrl}${path}`;
|
|
@@ -17,7 +23,7 @@ export class DevHttpProvider {
|
|
|
17
23
|
}
|
|
18
24
|
let response;
|
|
19
25
|
try {
|
|
20
|
-
response = await
|
|
26
|
+
response = await this.fetcher(url, options);
|
|
21
27
|
}
|
|
22
28
|
catch (networkError) {
|
|
23
29
|
// Handle immediate network errors (e.g., DNS resolution failure, refused connection)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Config, Context, GenericTree, Payload, Signature } from '@0xsequence/wallet-primitives';
|
|
2
2
|
import { Address, Hex } from 'ox';
|
|
3
3
|
import { Provider as ProviderInterface } from '../index.js';
|
|
4
|
+
import { type Fetch } from './sessions.gen.js';
|
|
4
5
|
export declare class Provider implements ProviderInterface {
|
|
5
6
|
private readonly service;
|
|
6
|
-
constructor(host?: string);
|
|
7
|
+
constructor(host?: string, fetcher?: Fetch);
|
|
7
8
|
getConfiguration(imageHash: Hex.Hex): Promise<Config.Config | undefined>;
|
|
8
9
|
getDeploy(wallet: Address.Address): Promise<{
|
|
9
10
|
imageHash: Hex.Hex;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/state/sequence/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAa,OAAO,EAAc,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAA;AACvH,OAAO,EAEL,OAAO,EAEP,GAAG,EAIJ,MAAM,IAAI,CAAA;AACX,OAAO,EAAwB,QAAQ,IAAI,iBAAiB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/state/sequence/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,12 @@ import { normalizeAddressKeys } from '../index.js';
|
|
|
4
4
|
import { Sessions, SignatureType } from './sessions.gen.js';
|
|
5
5
|
export class Provider {
|
|
6
6
|
service;
|
|
7
|
-
constructor(host = 'https://keymachine.sequence.app') {
|
|
8
|
-
|
|
7
|
+
constructor(host = 'https://keymachine.sequence.app', fetcher) {
|
|
8
|
+
const resolvedFetch = fetcher ?? globalThis.fetch;
|
|
9
|
+
if (!resolvedFetch) {
|
|
10
|
+
throw new Error('fetch is not available');
|
|
11
|
+
}
|
|
12
|
+
this.service = new Sessions(host, resolvedFetch);
|
|
9
13
|
}
|
|
10
14
|
async getConfiguration(imageHash) {
|
|
11
15
|
const { version, config } = await this.service.config({ imageHash });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xsequence/wallet-core",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.15",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"mipd": "^0.0.7",
|
|
27
27
|
"ox": "^0.9.17",
|
|
28
28
|
"viem": "^2.40.3",
|
|
29
|
-
"@0xsequence/guard": "^3.0.0-beta.
|
|
30
|
-
"@0xsequence/wallet-primitives": "^3.0.0-beta.
|
|
31
|
-
"@0xsequence/relayer": "^3.0.0-beta.
|
|
29
|
+
"@0xsequence/guard": "^3.0.0-beta.15",
|
|
30
|
+
"@0xsequence/wallet-primitives": "^3.0.0-beta.15",
|
|
31
|
+
"@0xsequence/relayer": "^3.0.0-beta.15"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsc",
|
|
@@ -21,11 +21,17 @@ export class PimlicoBundler implements Bundler {
|
|
|
21
21
|
|
|
22
22
|
public readonly provider: Provider.Provider
|
|
23
23
|
public readonly bundlerRpcUrl: string
|
|
24
|
+
private readonly fetcher: typeof fetch
|
|
24
25
|
|
|
25
|
-
constructor(bundlerRpcUrl: string, provider: Provider.Provider | string) {
|
|
26
|
+
constructor(bundlerRpcUrl: string, provider: Provider.Provider | string, fetcher?: typeof fetch) {
|
|
26
27
|
this.id = `pimlico-erc4337-${bundlerRpcUrl}`
|
|
27
28
|
this.provider = typeof provider === 'string' ? Provider.from(RpcTransport.fromHttp(provider)) : provider
|
|
28
29
|
this.bundlerRpcUrl = bundlerRpcUrl
|
|
30
|
+
const resolvedFetch = fetcher ?? (globalThis as any).fetch
|
|
31
|
+
if (!resolvedFetch) {
|
|
32
|
+
throw new Error('fetch is not available')
|
|
33
|
+
}
|
|
34
|
+
this.fetcher = resolvedFetch
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
async isAvailable(entrypoint: Address.Address, chainId: number): Promise<boolean> {
|
|
@@ -165,7 +171,7 @@ export class PimlicoBundler implements Bundler {
|
|
|
165
171
|
|
|
166
172
|
private async bundlerRpc<T>(method: string, params: any[]): Promise<T> {
|
|
167
173
|
const body = JSON.stringify({ jsonrpc: '2.0', id: 1, method, params })
|
|
168
|
-
const res = await
|
|
174
|
+
const res = await this.fetcher(this.bundlerRpcUrl, {
|
|
169
175
|
method: 'POST',
|
|
170
176
|
headers: { 'content-type': 'application/json' },
|
|
171
177
|
body,
|
package/src/env.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type StorageLike = {
|
|
2
|
+
getItem: (key: string) => string | null
|
|
3
|
+
setItem: (key: string, value: string) => void
|
|
4
|
+
removeItem: (key: string) => void
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type CryptoLike = {
|
|
8
|
+
subtle: SubtleCrypto
|
|
9
|
+
getRandomValues: <T extends ArrayBufferView>(array: T) => T
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type TextEncodingLike = {
|
|
13
|
+
TextEncoder: typeof TextEncoder
|
|
14
|
+
TextDecoder: typeof TextDecoder
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type CoreEnv = {
|
|
18
|
+
fetch?: typeof fetch
|
|
19
|
+
crypto?: CryptoLike
|
|
20
|
+
storage?: StorageLike
|
|
21
|
+
indexedDB?: IDBFactory
|
|
22
|
+
text?: Partial<TextEncodingLike>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isStorageLike(value: unknown): value is StorageLike {
|
|
26
|
+
if (!value || typeof value !== 'object') return false
|
|
27
|
+
const candidate = value as StorageLike
|
|
28
|
+
return (
|
|
29
|
+
typeof candidate.getItem === 'function' &&
|
|
30
|
+
typeof candidate.setItem === 'function' &&
|
|
31
|
+
typeof candidate.removeItem === 'function'
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function resolveCoreEnv(env?: CoreEnv): CoreEnv {
|
|
36
|
+
const globalObj = globalThis as any
|
|
37
|
+
const windowObj = typeof window !== 'undefined' ? window : (globalObj.window ?? {})
|
|
38
|
+
let storage: StorageLike | undefined
|
|
39
|
+
let text: Partial<TextEncodingLike> | undefined
|
|
40
|
+
|
|
41
|
+
if (isStorageLike(env?.storage)) {
|
|
42
|
+
storage = env.storage
|
|
43
|
+
} else if (isStorageLike(windowObj.localStorage)) {
|
|
44
|
+
storage = windowObj.localStorage
|
|
45
|
+
} else if (isStorageLike(globalObj.localStorage)) {
|
|
46
|
+
storage = globalObj.localStorage
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (env?.text) {
|
|
50
|
+
if (!env.text.TextEncoder || !env.text.TextDecoder) {
|
|
51
|
+
throw new Error('env.text must provide both TextEncoder and TextDecoder')
|
|
52
|
+
}
|
|
53
|
+
text = env.text
|
|
54
|
+
} else {
|
|
55
|
+
text = {
|
|
56
|
+
TextEncoder: windowObj.TextEncoder ?? globalObj.TextEncoder,
|
|
57
|
+
TextDecoder: windowObj.TextDecoder ?? globalObj.TextDecoder,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
fetch: env?.fetch ?? windowObj.fetch ?? globalObj.fetch,
|
|
63
|
+
crypto: env?.crypto ?? windowObj.crypto ?? globalObj.crypto,
|
|
64
|
+
storage,
|
|
65
|
+
indexedDB: env?.indexedDB ?? windowObj.indexedDB ?? globalObj.indexedDB,
|
|
66
|
+
text,
|
|
67
|
+
}
|
|
68
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * as State from './state/index.js'
|
|
|
5
5
|
export * as Bundler from './bundler/index.js'
|
|
6
6
|
export * as Envelope from './envelope.js'
|
|
7
7
|
export * as Utils from './utils/index.js'
|
|
8
|
+
export * from './env.js'
|
|
8
9
|
export {
|
|
9
10
|
type ExplicitSessionConfig,
|
|
10
11
|
type ExplicitSession,
|
package/src/signers/passkey.ts
CHANGED
|
@@ -5,12 +5,15 @@ import { WebAuthnP256 } from 'ox'
|
|
|
5
5
|
import { State } from '../index.js'
|
|
6
6
|
import { SapientSigner, Witnessable } from './index.js'
|
|
7
7
|
|
|
8
|
+
export type WebAuthnLike = Pick<typeof WebAuthnP256, 'createCredential' | 'sign'>
|
|
9
|
+
|
|
8
10
|
export type PasskeyOptions = {
|
|
9
11
|
extensions: Pick<Extensions.Extensions, 'passkeys'>
|
|
10
12
|
publicKey: Extensions.Passkeys.PublicKey
|
|
11
13
|
credentialId: string
|
|
12
14
|
embedMetadata?: boolean
|
|
13
15
|
metadata?: Extensions.Passkeys.PasskeyMetadata
|
|
16
|
+
webauthn?: WebAuthnLike
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
export type CreatePasskeyOptions = {
|
|
@@ -18,6 +21,11 @@ export type CreatePasskeyOptions = {
|
|
|
18
21
|
requireUserVerification?: boolean
|
|
19
22
|
credentialName?: string
|
|
20
23
|
embedMetadata?: boolean
|
|
24
|
+
webauthn?: WebAuthnLike
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type FindPasskeyOptions = {
|
|
28
|
+
webauthn?: WebAuthnLike
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
export type WitnessMessage = {
|
|
@@ -45,6 +53,7 @@ export class Passkey implements SapientSigner, Witnessable {
|
|
|
45
53
|
public readonly imageHash: Hex.Hex
|
|
46
54
|
public readonly embedMetadata: boolean
|
|
47
55
|
public readonly metadata?: Extensions.Passkeys.PasskeyMetadata
|
|
56
|
+
private readonly webauthn: WebAuthnLike
|
|
48
57
|
|
|
49
58
|
constructor(options: PasskeyOptions) {
|
|
50
59
|
this.address = options.extensions.passkeys
|
|
@@ -53,6 +62,7 @@ export class Passkey implements SapientSigner, Witnessable {
|
|
|
53
62
|
this.embedMetadata = options.embedMetadata ?? false
|
|
54
63
|
this.imageHash = Extensions.Passkeys.rootFor(options.publicKey)
|
|
55
64
|
this.metadata = options.metadata
|
|
65
|
+
this.webauthn = options.webauthn ?? WebAuthnP256
|
|
56
66
|
}
|
|
57
67
|
|
|
58
68
|
static async loadFromWitness(
|
|
@@ -60,6 +70,7 @@ export class Passkey implements SapientSigner, Witnessable {
|
|
|
60
70
|
extensions: Pick<Extensions.Extensions, 'passkeys'>,
|
|
61
71
|
wallet: Address.Address,
|
|
62
72
|
imageHash: Hex.Hex,
|
|
73
|
+
options?: FindPasskeyOptions,
|
|
63
74
|
) {
|
|
64
75
|
// In the witness we will find the public key, and may find the credential id
|
|
65
76
|
const witness = await stateReader.getWitnessForSapient(wallet, extensions.passkeys, imageHash)
|
|
@@ -90,13 +101,15 @@ export class Passkey implements SapientSigner, Witnessable {
|
|
|
90
101
|
publicKey: message.publicKey,
|
|
91
102
|
embedMetadata: decodedSignature.embedMetadata,
|
|
92
103
|
metadata,
|
|
104
|
+
webauthn: options?.webauthn,
|
|
93
105
|
})
|
|
94
106
|
}
|
|
95
107
|
|
|
96
108
|
static async create(extensions: Pick<Extensions.Extensions, 'passkeys'>, options?: CreatePasskeyOptions) {
|
|
109
|
+
const webauthn = options?.webauthn ?? WebAuthnP256
|
|
97
110
|
const name = options?.credentialName ?? `Sequence (${Date.now()})`
|
|
98
111
|
|
|
99
|
-
const credential = await
|
|
112
|
+
const credential = await webauthn.createCredential({
|
|
100
113
|
user: {
|
|
101
114
|
name,
|
|
102
115
|
},
|
|
@@ -120,6 +133,7 @@ export class Passkey implements SapientSigner, Witnessable {
|
|
|
120
133
|
},
|
|
121
134
|
embedMetadata: options?.embedMetadata,
|
|
122
135
|
metadata,
|
|
136
|
+
webauthn,
|
|
123
137
|
})
|
|
124
138
|
|
|
125
139
|
if (options?.stateProvider) {
|
|
@@ -132,8 +146,10 @@ export class Passkey implements SapientSigner, Witnessable {
|
|
|
132
146
|
static async find(
|
|
133
147
|
stateReader: State.Reader,
|
|
134
148
|
extensions: Pick<Extensions.Extensions, 'passkeys'>,
|
|
149
|
+
options?: FindPasskeyOptions,
|
|
135
150
|
): Promise<Passkey | undefined> {
|
|
136
|
-
const
|
|
151
|
+
const webauthn = options?.webauthn ?? WebAuthnP256
|
|
152
|
+
const response = await webauthn.sign({ challenge: Hex.random(32) })
|
|
137
153
|
if (!response.raw) throw new Error('No credential returned')
|
|
138
154
|
|
|
139
155
|
const authenticatorDataBytes = Bytes.fromHex(response.metadata.authenticatorData)
|
|
@@ -218,7 +234,7 @@ export class Passkey implements SapientSigner, Witnessable {
|
|
|
218
234
|
console.warn('Multiple signers found for passkey', flattened)
|
|
219
235
|
}
|
|
220
236
|
|
|
221
|
-
return Passkey.loadFromWitness(stateReader, extensions, flattened[0]!.wallet, flattened[0]!.imageHash)
|
|
237
|
+
return Passkey.loadFromWitness(stateReader, extensions, flattened[0]!.wallet, flattened[0]!.imageHash, options)
|
|
222
238
|
}
|
|
223
239
|
|
|
224
240
|
async signSapient(
|
|
@@ -234,7 +250,7 @@ export class Passkey implements SapientSigner, Witnessable {
|
|
|
234
250
|
|
|
235
251
|
const challenge = Hex.fromBytes(Payload.hash(wallet, chainId, payload))
|
|
236
252
|
|
|
237
|
-
const response = await
|
|
253
|
+
const response = await this.webauthn.sign({
|
|
238
254
|
challenge,
|
|
239
255
|
credentialId: this.credentialId,
|
|
240
256
|
userVerification: this.publicKey.requireUserVerification ? 'required' : 'discouraged',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Hex, Address, PublicKey, Secp256k1, Bytes } from 'ox'
|
|
2
|
+
import { resolveCoreEnv, type CoreEnv, type CryptoLike, type StorageLike, type TextEncodingLike } from '../../env.js'
|
|
2
3
|
import { PkStore } from './index.js'
|
|
3
4
|
|
|
4
5
|
export interface EncryptedData {
|
|
@@ -17,6 +18,7 @@ export class EncryptedPksDb {
|
|
|
17
18
|
constructor(
|
|
18
19
|
private readonly localStorageKeyPrefix: string = 'e_pk_key_',
|
|
19
20
|
tableName: string = 'e_pk',
|
|
21
|
+
private readonly env?: CoreEnv,
|
|
20
22
|
) {
|
|
21
23
|
this.tableName = tableName
|
|
22
24
|
}
|
|
@@ -25,9 +27,59 @@ export class EncryptedPksDb {
|
|
|
25
27
|
return `pk_${address.toLowerCase()}`
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
private getIndexedDB(): IDBFactory {
|
|
31
|
+
const globalObj = globalThis as any
|
|
32
|
+
const indexedDb = this.env?.indexedDB ?? globalObj.indexedDB ?? globalObj.window?.indexedDB
|
|
33
|
+
if (!indexedDb) {
|
|
34
|
+
throw new Error('indexedDB is not available')
|
|
35
|
+
}
|
|
36
|
+
return indexedDb
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private getStorage(): StorageLike {
|
|
40
|
+
const storage = resolveCoreEnv(this.env).storage
|
|
41
|
+
if (!storage) {
|
|
42
|
+
throw new Error('storage is not available')
|
|
43
|
+
}
|
|
44
|
+
return storage
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private getCrypto(): CryptoLike {
|
|
48
|
+
const globalObj = globalThis as any
|
|
49
|
+
const crypto = this.env?.crypto ?? globalObj.crypto ?? globalObj.window?.crypto
|
|
50
|
+
if (!crypto?.subtle || !crypto?.getRandomValues) {
|
|
51
|
+
throw new Error('crypto.subtle is not available')
|
|
52
|
+
}
|
|
53
|
+
return crypto
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private getTextEncoderCtor(): TextEncodingLike['TextEncoder'] {
|
|
57
|
+
const globalObj = globalThis as any
|
|
58
|
+
if (this.env?.text && (!this.env.text.TextEncoder || !this.env.text.TextDecoder)) {
|
|
59
|
+
throw new Error('env.text must provide both TextEncoder and TextDecoder')
|
|
60
|
+
}
|
|
61
|
+
const encoderCtor = this.env?.text?.TextEncoder ?? globalObj.TextEncoder ?? globalObj.window?.TextEncoder
|
|
62
|
+
if (!encoderCtor) {
|
|
63
|
+
throw new Error('TextEncoder is not available')
|
|
64
|
+
}
|
|
65
|
+
return encoderCtor
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private getTextDecoderCtor(): TextEncodingLike['TextDecoder'] {
|
|
69
|
+
const globalObj = globalThis as any
|
|
70
|
+
if (this.env?.text && (!this.env.text.TextEncoder || !this.env.text.TextDecoder)) {
|
|
71
|
+
throw new Error('env.text must provide both TextEncoder and TextDecoder')
|
|
72
|
+
}
|
|
73
|
+
const decoderCtor = this.env?.text?.TextDecoder ?? globalObj.TextDecoder ?? globalObj.window?.TextDecoder
|
|
74
|
+
if (!decoderCtor) {
|
|
75
|
+
throw new Error('TextDecoder is not available')
|
|
76
|
+
}
|
|
77
|
+
return decoderCtor
|
|
78
|
+
}
|
|
79
|
+
|
|
28
80
|
private openDB(): Promise<IDBDatabase> {
|
|
29
81
|
return new Promise((resolve, reject) => {
|
|
30
|
-
const request =
|
|
82
|
+
const request = this.getIndexedDB().open(this.dbName, this.dbVersion)
|
|
31
83
|
request.onupgradeneeded = () => {
|
|
32
84
|
const db = request.result
|
|
33
85
|
if (!db.objectStoreNames.contains(this.tableName)) {
|
|
@@ -73,7 +125,11 @@ export class EncryptedPksDb {
|
|
|
73
125
|
}
|
|
74
126
|
|
|
75
127
|
async generateAndStore(): Promise<EncryptedData> {
|
|
76
|
-
const
|
|
128
|
+
const crypto = this.getCrypto()
|
|
129
|
+
const storage = this.getStorage()
|
|
130
|
+
const TextEncoderCtor = this.getTextEncoderCtor()
|
|
131
|
+
|
|
132
|
+
const encryptionKey = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, [
|
|
77
133
|
'encrypt',
|
|
78
134
|
'decrypt',
|
|
79
135
|
])
|
|
@@ -84,13 +140,13 @@ export class EncryptedPksDb {
|
|
|
84
140
|
const address = Address.fromPublicKey(publicKey)
|
|
85
141
|
const keyPointer = this.localStorageKeyPrefix + address
|
|
86
142
|
|
|
87
|
-
const exportedKey = await
|
|
88
|
-
|
|
143
|
+
const exportedKey = await crypto.subtle.exportKey('jwk', encryptionKey)
|
|
144
|
+
storage.setItem(keyPointer, JSON.stringify(exportedKey))
|
|
89
145
|
|
|
90
|
-
const encoder = new
|
|
146
|
+
const encoder = new TextEncoderCtor()
|
|
91
147
|
const encodedPk = encoder.encode(privateKey)
|
|
92
|
-
const iv =
|
|
93
|
-
const encryptedBuffer = await
|
|
148
|
+
const iv = crypto.getRandomValues(new Uint8Array(12))
|
|
149
|
+
const encryptedBuffer = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, encryptionKey, encodedPk)
|
|
94
150
|
|
|
95
151
|
const encrypted: EncryptedData = {
|
|
96
152
|
iv,
|
|
@@ -113,7 +169,7 @@ export class EncryptedPksDb {
|
|
|
113
169
|
async getEncryptedPkStore(address: Address.Address): Promise<EncryptedPkStore | undefined> {
|
|
114
170
|
const entry = await this.getEncryptedEntry(address)
|
|
115
171
|
if (!entry) return
|
|
116
|
-
return new EncryptedPkStore(entry)
|
|
172
|
+
return new EncryptedPkStore(entry, this.env)
|
|
117
173
|
}
|
|
118
174
|
|
|
119
175
|
async listAddresses(): Promise<Address.Address[]> {
|
|
@@ -125,12 +181,41 @@ export class EncryptedPksDb {
|
|
|
125
181
|
const dbKey = this.computeDbKey(address)
|
|
126
182
|
await this.putData(dbKey, undefined)
|
|
127
183
|
const keyPointer = this.localStorageKeyPrefix + address
|
|
128
|
-
|
|
184
|
+
this.getStorage().removeItem(keyPointer)
|
|
129
185
|
}
|
|
130
186
|
}
|
|
131
187
|
|
|
132
188
|
export class EncryptedPkStore implements PkStore {
|
|
133
|
-
constructor(
|
|
189
|
+
constructor(
|
|
190
|
+
private readonly encrypted: EncryptedData,
|
|
191
|
+
private readonly env?: CoreEnv,
|
|
192
|
+
) {}
|
|
193
|
+
|
|
194
|
+
private getStorage(): StorageLike {
|
|
195
|
+
const storage = resolveCoreEnv(this.env).storage
|
|
196
|
+
if (!storage) {
|
|
197
|
+
throw new Error('storage is not available')
|
|
198
|
+
}
|
|
199
|
+
return storage
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private getCrypto(): CryptoLike {
|
|
203
|
+
const globalObj = globalThis as any
|
|
204
|
+
const crypto = this.env?.crypto ?? globalObj.crypto ?? globalObj.window?.crypto
|
|
205
|
+
if (!crypto?.subtle) {
|
|
206
|
+
throw new Error('crypto.subtle is not available')
|
|
207
|
+
}
|
|
208
|
+
return crypto
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private getTextDecoderCtor(): TextEncodingLike['TextDecoder'] {
|
|
212
|
+
const globalObj = globalThis as any
|
|
213
|
+
const decoderCtor = this.env?.text?.TextDecoder ?? globalObj.TextDecoder ?? globalObj.window?.TextDecoder
|
|
214
|
+
if (!decoderCtor) {
|
|
215
|
+
throw new Error('TextDecoder is not available')
|
|
216
|
+
}
|
|
217
|
+
return decoderCtor
|
|
218
|
+
}
|
|
134
219
|
|
|
135
220
|
address(): Address.Address {
|
|
136
221
|
return this.encrypted.address
|
|
@@ -141,16 +226,20 @@ export class EncryptedPkStore implements PkStore {
|
|
|
141
226
|
}
|
|
142
227
|
|
|
143
228
|
async signDigest(digest: Bytes.Bytes): Promise<{ r: bigint; s: bigint; yParity: number }> {
|
|
144
|
-
const
|
|
229
|
+
const storage = this.getStorage()
|
|
230
|
+
const crypto = this.getCrypto()
|
|
231
|
+
const TextDecoderCtor = this.getTextDecoderCtor()
|
|
232
|
+
|
|
233
|
+
const keyJson = storage.getItem(this.encrypted.keyPointer)
|
|
145
234
|
if (!keyJson) throw new Error('Encryption key not found in localStorage')
|
|
146
235
|
const jwk = JSON.parse(keyJson)
|
|
147
|
-
const encryptionKey = await
|
|
148
|
-
const decryptedBuffer = await
|
|
236
|
+
const encryptionKey = await crypto.subtle.importKey('jwk', jwk, { name: 'AES-GCM' }, false, ['decrypt'])
|
|
237
|
+
const decryptedBuffer = await crypto.subtle.decrypt(
|
|
149
238
|
{ name: 'AES-GCM', iv: this.encrypted.iv },
|
|
150
239
|
encryptionKey,
|
|
151
240
|
this.encrypted.data,
|
|
152
241
|
)
|
|
153
|
-
const decoder = new
|
|
242
|
+
const decoder = new TextDecoderCtor()
|
|
154
243
|
const privateKey = decoder.decode(decryptedBuffer) as Hex.Hex
|
|
155
244
|
return Secp256k1.sign({ payload: digest, privateKey })
|
|
156
245
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Context, Payload, Signature, Config, GenericTree } from '@0xsequence/wallet-primitives'
|
|
2
2
|
import { Address, Hex } from 'ox'
|
|
3
|
+
import type { CoreEnv } from '../../env.js'
|
|
3
4
|
import { Store } from './index.js'
|
|
4
5
|
|
|
5
6
|
const DB_VERSION = 1
|
|
@@ -16,15 +17,27 @@ export class IndexedDbStore implements Store {
|
|
|
16
17
|
private _db: IDBDatabase | null = null
|
|
17
18
|
private dbName: string
|
|
18
19
|
|
|
19
|
-
constructor(
|
|
20
|
+
constructor(
|
|
21
|
+
dbName: string = 'sequence-indexeddb',
|
|
22
|
+
private readonly env?: CoreEnv,
|
|
23
|
+
) {
|
|
20
24
|
this.dbName = dbName
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
private getIndexedDB(): IDBFactory {
|
|
28
|
+
const globalObj = globalThis as any
|
|
29
|
+
const indexedDb = this.env?.indexedDB ?? globalObj.indexedDB ?? globalObj.window?.indexedDB
|
|
30
|
+
if (!indexedDb) {
|
|
31
|
+
throw new Error('indexedDB is not available')
|
|
32
|
+
}
|
|
33
|
+
return indexedDb
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
private async openDB(): Promise<IDBDatabase> {
|
|
24
37
|
if (this._db) return this._db
|
|
25
38
|
|
|
26
39
|
return new Promise((resolve, reject) => {
|
|
27
|
-
const request =
|
|
40
|
+
const request = this.getIndexedDB().open(this.dbName, DB_VERSION)
|
|
28
41
|
|
|
29
42
|
request.onupgradeneeded = () => {
|
|
30
43
|
const db = request.result
|
|
@@ -4,10 +4,16 @@ import { Provider } from '../index.js'
|
|
|
4
4
|
|
|
5
5
|
export class DevHttpProvider implements Provider {
|
|
6
6
|
private readonly baseUrl: string
|
|
7
|
+
private readonly fetcher: typeof fetch
|
|
7
8
|
|
|
8
|
-
constructor(baseUrl: string) {
|
|
9
|
+
constructor(baseUrl: string, fetcher?: typeof fetch) {
|
|
9
10
|
// Remove trailing slash if present
|
|
10
11
|
this.baseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl
|
|
12
|
+
const resolvedFetch = fetcher ?? (globalThis as any).fetch
|
|
13
|
+
if (!resolvedFetch) {
|
|
14
|
+
throw new Error('fetch is not available')
|
|
15
|
+
}
|
|
16
|
+
this.fetcher = resolvedFetch
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
private async request<T>(method: 'GET' | 'POST', path: string, body?: any): Promise<T> {
|
|
@@ -24,7 +30,7 @@ export class DevHttpProvider implements Provider {
|
|
|
24
30
|
|
|
25
31
|
let response: Response
|
|
26
32
|
try {
|
|
27
|
-
response = await
|
|
33
|
+
response = await this.fetcher(url, options)
|
|
28
34
|
} catch (networkError) {
|
|
29
35
|
// Handle immediate network errors (e.g., DNS resolution failure, refused connection)
|
|
30
36
|
console.error(`Network error during ${method} request to ${url}:`, networkError)
|
|
@@ -9,13 +9,17 @@ import {
|
|
|
9
9
|
TransactionRequest,
|
|
10
10
|
} from 'ox'
|
|
11
11
|
import { normalizeAddressKeys, Provider as ProviderInterface } from '../index.js'
|
|
12
|
-
import { Sessions, SignatureType } from './sessions.gen.js'
|
|
12
|
+
import { Sessions, SignatureType, type Fetch } from './sessions.gen.js'
|
|
13
13
|
|
|
14
14
|
export class Provider implements ProviderInterface {
|
|
15
15
|
private readonly service: Sessions
|
|
16
16
|
|
|
17
|
-
constructor(host = 'https://keymachine.sequence.app') {
|
|
18
|
-
|
|
17
|
+
constructor(host = 'https://keymachine.sequence.app', fetcher?: Fetch) {
|
|
18
|
+
const resolvedFetch = fetcher ?? (globalThis as any).fetch
|
|
19
|
+
if (!resolvedFetch) {
|
|
20
|
+
throw new Error('fetch is not available')
|
|
21
|
+
}
|
|
22
|
+
this.service = new Sessions(host, resolvedFetch)
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
async getConfiguration(imageHash: Hex.Hex): Promise<Config.Config | undefined> {
|