@0xsequence/wallet-core 3.0.0-beta.9 → 3.0.1
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 +2 -2
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +290 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +158 -0
- package/dist/bundler/bundlers/pimlico.d.ts +3 -2
- package/dist/bundler/bundlers/pimlico.d.ts.map +1 -1
- package/dist/bundler/bundlers/pimlico.js +9 -3
- 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/index.d.ts +1 -1
- package/dist/signers/passkey.d.ts +11 -3
- 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/signers/pk/index.d.ts +1 -1
- package/dist/signers/session/explicit.d.ts.map +1 -1
- package/dist/signers/session/explicit.js +5 -8
- package/dist/signers/session/implicit.d.ts.map +1 -1
- package/dist/signers/session/implicit.js +1 -1
- package/dist/signers/session/session.d.ts +1 -0
- package/dist/signers/session/session.d.ts.map +1 -1
- package/dist/signers/session/session.js +7 -0
- package/dist/signers/session-manager.d.ts +4 -0
- package/dist/signers/session-manager.d.ts.map +1 -1
- package/dist/signers/session-manager.js +65 -22
- package/dist/state/local/index.d.ts.map +1 -1
- package/dist/state/local/index.js +3 -2
- 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 +11 -5
- 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 +14 -5
- package/dist/wallet.js +2 -2
- package/eslint.config.js +12 -0
- package/package.json +12 -10
- package/src/bundler/bundlers/pimlico.ts +10 -4
- package/src/env.ts +68 -0
- package/src/index.ts +1 -0
- package/src/signers/index.ts +1 -1
- package/src/signers/passkey.ts +21 -5
- package/src/signers/pk/encrypted.ts +103 -14
- package/src/signers/pk/index.ts +1 -1
- package/src/signers/session/explicit.ts +5 -20
- package/src/signers/session/implicit.ts +1 -2
- package/src/signers/session/session.ts +10 -2
- package/src/signers/session-manager.ts +82 -25
- package/src/state/local/index.ts +4 -2
- package/src/state/local/indexed-db.ts +15 -2
- package/src/state/remote/dev-http.ts +11 -5
- package/src/state/sequence/index.ts +15 -6
- package/src/wallet.ts +2 -2
- package/test/constants.ts +4 -0
- package/test/envelope.test.ts +0 -1
- package/test/session-manager.test.ts +345 -3
- package/test/signers-pk.test.ts +1 -1
- package/test/signers-session-implicit.test.ts +0 -2
- package/test/state/debug.test.ts +2 -3
package/dist/index.js
CHANGED
package/dist/signers/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export interface SapientSigner {
|
|
|
16
16
|
signSapient: (wallet: Address.Address, chainId: number, payload: Payload.Parented, imageHash: Hex.Hex) => Config.SignerSignature<Signature.SignatureOfSapientSignerLeaf>;
|
|
17
17
|
}
|
|
18
18
|
export interface Witnessable {
|
|
19
|
-
witness: (stateWriter: State.Writer, wallet: Address.Address, extra?:
|
|
19
|
+
witness: (stateWriter: State.Writer, wallet: Address.Address, extra?: object) => Promise<void>;
|
|
20
20
|
}
|
|
21
21
|
type MaybePromise<T> = T | Promise<T>;
|
|
22
22
|
export declare function isSapientSigner(signer: Signer | SapientSigner): signer is SapientSigner;
|
|
@@ -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,11 +38,12 @@ 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
|
-
witness(stateWriter: State.Writer, wallet: Address.Address, extra?:
|
|
47
|
+
witness(stateWriter: State.Writer, wallet: Address.Address, extra?: object): Promise<void>;
|
|
40
48
|
}
|
|
41
49
|
//# sourceMappingURL=passkey.d.ts.map
|
|
@@ -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":"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"}
|
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
|
}
|
|
@@ -29,7 +29,7 @@ export declare class Pk implements SignerInterface, Witnessable {
|
|
|
29
29
|
constructor(privateKey: Hex.Hex | PkStore);
|
|
30
30
|
sign(wallet: Address.Address, chainId: number, payload: PayloadTypes.Parented): Promise<SignatureTypes.SignatureOfSignerLeaf>;
|
|
31
31
|
signDigest(digest: Bytes.Bytes): Promise<SignatureTypes.SignatureOfSignerLeaf>;
|
|
32
|
-
witness(stateWriter: State.Writer, wallet: Address.Address, extra?:
|
|
32
|
+
witness(stateWriter: State.Writer, wallet: Address.Address, extra?: object): Promise<void>;
|
|
33
33
|
}
|
|
34
34
|
export * as Encrypted from './encrypted.js';
|
|
35
35
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explicit.d.ts","sourceRoot":"","sources":["../../../src/signers/session/explicit.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"explicit.d.ts","sourceRoot":"","sources":["../../../src/signers/session/explicit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAC/G,OAAO,EAA8B,OAAO,EAAe,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACpF,OAAO,EAAiB,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,EAAE,qBAAqB,EAAmB,qBAAqB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAExG,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAA;AAI1E,qBAAa,QAAS,YAAW,qBAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,SAAgB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IACxC,SAAgB,kBAAkB,EAAE,UAAU,CAAC,kBAAkB,CAAA;gBAErD,UAAU,EAAE,GAAG,CAAC,GAAG,GAAG,OAAO,EAAE,kBAAkB,EAAE,cAAc;IAS7E,OAAO,CAAC,eAAe,EAAE,aAAa,CAAC,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,qBAAqB;IA+C1F,uBAAuB,CAC3B,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,UAAU,CAAC,UAAU,GAAG,SAAS,CAAC;IAmC7C,OAAO,CAAC,sBAAsB;IAmB9B,OAAO,CAAC,iBAAiB;IAYnB,kBAAkB,CACtB,UAAU,EAAE,UAAU,CAAC,UAAU,EACjC,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,OAAO,CAAC;IAsDb,aAAa,CACjB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,OAAO,CAAC;IAab,QAAQ,CACZ,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,KAAK,EACtB,OAAO,EAAE,MAAM,EACf,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC;YA6BnC,qBAAqB;IAwB7B,iBAAiB,CACrB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,EACrB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,GAC1B,OAAO,CAAC,UAAU,EAAE,CAAC;CA8EzB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Constants, Permission, SessionConfig, SessionSignature
|
|
1
|
+
import { Constants, Permission, SessionConfig, SessionSignature } from '@0xsequence/wallet-primitives';
|
|
2
2
|
import { AbiFunction, AbiParameters, Address, Bytes, Hash, Hex } from 'ox';
|
|
3
3
|
import { MemoryPkStore } from '../pk/index.js';
|
|
4
|
+
import { isIncrementCall } from './session.js';
|
|
4
5
|
const VALUE_TRACKING_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
5
6
|
export class Explicit {
|
|
6
7
|
_privateKey;
|
|
@@ -143,9 +144,7 @@ export class Explicit {
|
|
|
143
144
|
return true;
|
|
144
145
|
}
|
|
145
146
|
async supportedCall(wallet, chainId, call, sessionManagerAddress, provider) {
|
|
146
|
-
if (
|
|
147
|
-
Hex.size(call.data) > 4 &&
|
|
148
|
-
Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT))) {
|
|
147
|
+
if (isIncrementCall(call, sessionManagerAddress)) {
|
|
149
148
|
// Can sign increment usage calls
|
|
150
149
|
return true;
|
|
151
150
|
}
|
|
@@ -158,9 +157,7 @@ export class Explicit {
|
|
|
158
157
|
async signCall(wallet, chainId, payload, callIdx, sessionManagerAddress, provider) {
|
|
159
158
|
const call = payload.calls[callIdx];
|
|
160
159
|
let permissionIndex;
|
|
161
|
-
if (
|
|
162
|
-
Hex.size(call.data) > 4 &&
|
|
163
|
-
Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT))) {
|
|
160
|
+
if (isIncrementCall(call, sessionManagerAddress)) {
|
|
164
161
|
// Permission check not required. Use the first permission
|
|
165
162
|
permissionIndex = 0;
|
|
166
163
|
}
|
|
@@ -220,7 +217,7 @@ export class Explicit {
|
|
|
220
217
|
}
|
|
221
218
|
// Extract the masked value
|
|
222
219
|
const callDataValue = Bytes.padRight(Bytes.fromHex(call.data).slice(Number(rule.offset), Number(rule.offset) + 32), 32);
|
|
223
|
-
|
|
220
|
+
const value = callDataValue.map((b, i) => b & rule.mask[i]);
|
|
224
221
|
if (Bytes.toBigInt(value) === 0n)
|
|
225
222
|
continue;
|
|
226
223
|
// Add to list
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implicit.d.ts","sourceRoot":"","sources":["../../../src/signers/session/implicit.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,
|
|
1
|
+
{"version":3,"file":"implicit.d.ts","sourceRoot":"","sources":["../../../src/signers/session/implicit.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,OAAO,EACP,SAAS,IAAI,iBAAiB,EAC9B,aAAa,EACb,gBAAgB,EACjB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAe,OAAO,EAAS,GAAG,EAAE,QAAQ,EAAwB,MAAM,IAAI,CAAA;AACrF,OAAO,EAAiB,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAE3E,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAA;AAE/E,qBAAa,QAAS,YAAW,qBAAqB;IAOlD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,eAAe;IARlC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAuB;IAC1D,SAAgB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;gBAGtC,UAAU,EAAE,GAAG,CAAC,GAAG,GAAG,OAAO,EACZ,YAAY,EAAE,WAAW,CAAC,WAAW,EACtD,iBAAiB,EAAE,iBAAiB,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,EACjC,eAAe,EAAE,OAAO,CAAC,OAAO;IAcnD,IAAI,cAAc,IAAI,OAAO,CAAC,OAAO,CAKpC;IAED,OAAO,CAAC,eAAe,EAAE,aAAa,CAAC,gBAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,qBAAqB;IAa3F,aAAa,CACjB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,sBAAsB,EAAE,OAAO,CAAC,OAAO,EACvC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,OAAO,CAAC;IAyCb,QAAQ,CACZ,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,KAAK,EACtB,OAAO,EAAE,MAAM,EACf,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC;CAclD"}
|
|
@@ -73,7 +73,7 @@ export class Implicit {
|
|
|
73
73
|
const expectedResult = Bytes.toHex(Attestation.generateImplicitRequestMagic(this._attestation, wallet));
|
|
74
74
|
return acceptImplicitRequest === expectedResult;
|
|
75
75
|
}
|
|
76
|
-
catch
|
|
76
|
+
catch {
|
|
77
77
|
// console.log('implicit signer unsupported call', call, error)
|
|
78
78
|
return false;
|
|
79
79
|
}
|
|
@@ -23,4 +23,5 @@ export interface ImplicitSessionSigner extends SessionSigner {
|
|
|
23
23
|
}
|
|
24
24
|
export declare function isExplicitSessionSigner(signer: SessionSigner): signer is ExplicitSessionSigner;
|
|
25
25
|
export declare function isImplicitSessionSigner(signer: SessionSigner): signer is ImplicitSessionSigner;
|
|
26
|
+
export declare function isIncrementCall(call: Payload.Call, sessionManagerAddress: Address.Address): boolean;
|
|
26
27
|
//# sourceMappingURL=session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/signers/session/session.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/signers/session/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACnG,OAAO,EAAe,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AAExD,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,0BAA0B,GAC1B,2BAA2B,GAC3B,0BAA0B,GAC1B,aAAa,CAAA;AAEjB,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,0BAA0B,CAAA;CAC3C,CAAA;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAGnD,OAAO,EAAE,CAAC,eAAe,EAAE,aAAa,CAAC,gBAAgB,EAAE,OAAO,EAAE,MAAM,KAAK,qBAAqB,CAAA;IAGpG,aAAa,EAAE,CACb,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACzB,OAAO,CAAC,OAAO,CAAC,CAAA;IAGrB,QAAQ,EAAE,CACR,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,KAAK,EACtB,OAAO,EAAE,MAAM,EACf,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACzB,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;CACpD;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,iBAAiB,EAAE,CACjB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,EACrB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,KACxB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;CAC3B;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,cAAc,EAAE,OAAO,CAAC,OAAO,CAAA;CAChC;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,qBAAqB,CAE9F;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,qBAAqB,CAE9F;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,qBAAqB,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAMnG"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
import { Constants } from '@0xsequence/wallet-primitives';
|
|
2
|
+
import { AbiFunction, Address, Hex } from 'ox';
|
|
1
3
|
export function isExplicitSessionSigner(signer) {
|
|
2
4
|
return 'prepareIncrements' in signer;
|
|
3
5
|
}
|
|
4
6
|
export function isImplicitSessionSigner(signer) {
|
|
5
7
|
return 'identitySigner' in signer;
|
|
6
8
|
}
|
|
9
|
+
export function isIncrementCall(call, sessionManagerAddress) {
|
|
10
|
+
return (Address.isEqual(call.to, sessionManagerAddress) &&
|
|
11
|
+
Hex.size(call.data) >= 4 &&
|
|
12
|
+
Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT)));
|
|
13
|
+
}
|
|
@@ -31,6 +31,10 @@ export declare class SessionManager implements SapientSigner {
|
|
|
31
31
|
isValid: boolean;
|
|
32
32
|
invalidReason?: SessionSignerInvalidReason;
|
|
33
33
|
}[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Find one signer per call from the given candidate list (first that supports each call).
|
|
36
|
+
*/
|
|
37
|
+
private findSignersForCallsWithCandidates;
|
|
34
38
|
findSignersForCalls(wallet: Address.Address, chainId: number, calls: Payload.Call[]): Promise<SessionSigner[]>;
|
|
35
39
|
prepareIncrement(wallet: Address.Address, chainId: number, calls: Payload.Call[]): Promise<Payload.Call | null>;
|
|
36
40
|
signSapient(wallet: Address.Address, chainId: number, payload: Payload.Parented, imageHash: Hex.Hex): Promise<SignatureTypes.SignatureOfSapientSignerLeaf>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/signers/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,OAAO,EACP,aAAa,EAEb,SAAS,IAAI,cAAc,EAC5B,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAe,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACxD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EACL,QAAQ,EACR,QAAQ,EAER,aAAa,EACb,0BAA0B,
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/signers/session-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Config, Constants, Extensions, Payload, SessionConfig, SessionSignature, } from '@0xsequence/wallet-primitives';
|
|
2
2
|
import { AbiFunction, Address, Hex } from 'ox';
|
|
3
|
-
import { isExplicitSessionSigner, isImplicitSessionSigner, } from './session/index.js';
|
|
3
|
+
import { isExplicitSessionSigner, isImplicitSessionSigner, isIncrementCall, } from './session/index.js';
|
|
4
4
|
const MAX_SPACE = 2n ** 80n - 1n;
|
|
5
5
|
export class SessionManager {
|
|
6
6
|
wallet;
|
|
@@ -86,19 +86,10 @@ export class SessionManager {
|
|
|
86
86
|
invalidReason,
|
|
87
87
|
}));
|
|
88
88
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (identitySigners.length === 0) {
|
|
94
|
-
throw new Error('Identity signers not found');
|
|
95
|
-
}
|
|
96
|
-
// Prioritize implicit signers
|
|
97
|
-
const availableSigners = [...this._implicitSigners, ...this._explicitSigners];
|
|
98
|
-
if (availableSigners.length === 0) {
|
|
99
|
-
throw new Error('No signers match the topology');
|
|
100
|
-
}
|
|
101
|
-
// Find supported signers for each call
|
|
89
|
+
/**
|
|
90
|
+
* Find one signer per call from the given candidate list (first that supports each call).
|
|
91
|
+
*/
|
|
92
|
+
async findSignersForCallsWithCandidates(wallet, chainId, calls, topology, availableSigners) {
|
|
102
93
|
const signers = [];
|
|
103
94
|
for (const call of calls) {
|
|
104
95
|
let supported = false;
|
|
@@ -128,7 +119,56 @@ export class SessionManager {
|
|
|
128
119
|
if (expiredSupportedSigner) {
|
|
129
120
|
throw new Error(`Signer supporting call is expired: ${expiredSupportedSigner.address}`);
|
|
130
121
|
}
|
|
131
|
-
throw new Error(`No signer supported for call.
|
|
122
|
+
throw new Error(`No signer supported for call. Call: to=${call.to}, data=${call.data}, value=${call.value}, `);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return signers;
|
|
126
|
+
}
|
|
127
|
+
async findSignersForCalls(wallet, chainId, calls) {
|
|
128
|
+
const topology = await this.topology;
|
|
129
|
+
const identitySigners = SessionConfig.getIdentitySigners(topology);
|
|
130
|
+
if (identitySigners.length === 0) {
|
|
131
|
+
throw new Error('Identity signers not found');
|
|
132
|
+
}
|
|
133
|
+
const availableSigners = [...this._implicitSigners, ...this._explicitSigners];
|
|
134
|
+
if (availableSigners.length === 0) {
|
|
135
|
+
throw new Error('No signers match the topology');
|
|
136
|
+
}
|
|
137
|
+
const nonIncrementCalls = [];
|
|
138
|
+
const incrementCalls = [];
|
|
139
|
+
for (const call of calls) {
|
|
140
|
+
if (isIncrementCall(call, this.address)) {
|
|
141
|
+
incrementCalls.push(call);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
nonIncrementCalls.push(call);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Find signers for non-increment calls
|
|
148
|
+
const nonIncrementSigners = nonIncrementCalls.length > 0
|
|
149
|
+
? await this.findSignersForCallsWithCandidates(wallet, chainId, nonIncrementCalls, topology, availableSigners)
|
|
150
|
+
: [];
|
|
151
|
+
let incrementSigners = [];
|
|
152
|
+
if (incrementCalls.length > 0) {
|
|
153
|
+
// Find signers for increment calls, preferring signers that signed non-increment calls
|
|
154
|
+
const incrementCandidates = [
|
|
155
|
+
...nonIncrementSigners,
|
|
156
|
+
...availableSigners.filter((s) => !nonIncrementSigners.includes(s)),
|
|
157
|
+
];
|
|
158
|
+
incrementSigners = await this.findSignersForCallsWithCandidates(wallet, chainId, incrementCalls, topology, incrementCandidates);
|
|
159
|
+
}
|
|
160
|
+
// Merge back in original call order
|
|
161
|
+
const signers = [];
|
|
162
|
+
let nonIncrementIndex = 0;
|
|
163
|
+
let incrementIndex = 0;
|
|
164
|
+
for (const call of calls) {
|
|
165
|
+
if (isIncrementCall(call, this.address)) {
|
|
166
|
+
signers.push(incrementSigners[incrementIndex]);
|
|
167
|
+
incrementIndex++;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
signers.push(nonIncrementSigners[nonIncrementIndex]);
|
|
171
|
+
nonIncrementIndex++;
|
|
132
172
|
}
|
|
133
173
|
}
|
|
134
174
|
return signers;
|
|
@@ -138,17 +178,20 @@ export class SessionManager {
|
|
|
138
178
|
throw new Error('No calls provided');
|
|
139
179
|
}
|
|
140
180
|
const signers = await this.findSignersForCalls(wallet, chainId, calls);
|
|
141
|
-
//
|
|
142
|
-
const
|
|
181
|
+
// Map each signer to only their non-increment calls
|
|
182
|
+
const signerToNonIncrementCalls = new Map();
|
|
143
183
|
signers.forEach((signer, index) => {
|
|
144
184
|
const call = calls[index];
|
|
145
|
-
|
|
146
|
-
|
|
185
|
+
if (isIncrementCall(call, this.address)) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const existing = signerToNonIncrementCalls.get(signer) || [];
|
|
189
|
+
signerToNonIncrementCalls.set(signer, [...existing, call]);
|
|
147
190
|
});
|
|
148
|
-
// Prepare increments for each explicit signer
|
|
149
|
-
const increments = (await Promise.all(Array.from(
|
|
191
|
+
// Prepare increments for each explicit signer from their non-increment calls only
|
|
192
|
+
const increments = (await Promise.all(Array.from(signerToNonIncrementCalls.entries()).map(async ([signer, nonIncrementCalls]) => {
|
|
150
193
|
if (isExplicitSessionSigner(signer)) {
|
|
151
|
-
return signer.prepareIncrements(wallet, chainId,
|
|
194
|
+
return signer.prepareIncrements(wallet, chainId, nonIncrementCalls, this.address, this._provider);
|
|
152
195
|
}
|
|
153
196
|
return [];
|
|
154
197
|
}))).flat();
|