@0xsequence/wallet-core 0.0.0-20250520201059

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.
Files changed (106) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/CHANGELOG.md +9 -0
  3. package/LICENSE +202 -0
  4. package/dist/envelope.d.ts +34 -0
  5. package/dist/envelope.d.ts.map +1 -0
  6. package/dist/envelope.js +96 -0
  7. package/dist/index.d.ts +6 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +5 -0
  10. package/dist/relayer/index.d.ts +4 -0
  11. package/dist/relayer/index.d.ts.map +1 -0
  12. package/dist/relayer/index.js +3 -0
  13. package/dist/relayer/local.d.ts +28 -0
  14. package/dist/relayer/local.d.ts.map +1 -0
  15. package/dist/relayer/local.js +101 -0
  16. package/dist/relayer/pk-relayer.d.ts +18 -0
  17. package/dist/relayer/pk-relayer.d.ts.map +1 -0
  18. package/dist/relayer/pk-relayer.js +88 -0
  19. package/dist/relayer/relayer.d.ts +39 -0
  20. package/dist/relayer/relayer.d.ts.map +1 -0
  21. package/dist/relayer/relayer.js +1 -0
  22. package/dist/signers/index.d.ts +23 -0
  23. package/dist/signers/index.d.ts.map +1 -0
  24. package/dist/signers/index.js +10 -0
  25. package/dist/signers/passkey.d.ts +41 -0
  26. package/dist/signers/passkey.d.ts.map +1 -0
  27. package/dist/signers/passkey.js +196 -0
  28. package/dist/signers/pk/encrypted.d.ts +37 -0
  29. package/dist/signers/pk/encrypted.d.ts.map +1 -0
  30. package/dist/signers/pk/encrypted.js +123 -0
  31. package/dist/signers/pk/index.d.ts +35 -0
  32. package/dist/signers/pk/index.d.ts.map +1 -0
  33. package/dist/signers/pk/index.js +51 -0
  34. package/dist/signers/session/explicit.d.ts +18 -0
  35. package/dist/signers/session/explicit.d.ts.map +1 -0
  36. package/dist/signers/session/explicit.js +126 -0
  37. package/dist/signers/session/implicit.d.ts +20 -0
  38. package/dist/signers/session/implicit.d.ts.map +1 -0
  39. package/dist/signers/session/implicit.js +120 -0
  40. package/dist/signers/session/index.d.ts +4 -0
  41. package/dist/signers/session/index.d.ts.map +1 -0
  42. package/dist/signers/session/index.js +3 -0
  43. package/dist/signers/session/session.d.ts +11 -0
  44. package/dist/signers/session/session.d.ts.map +1 -0
  45. package/dist/signers/session/session.js +1 -0
  46. package/dist/signers/session-manager.d.ts +33 -0
  47. package/dist/signers/session-manager.d.ts.map +1 -0
  48. package/dist/signers/session-manager.js +181 -0
  49. package/dist/state/cached.d.ts +59 -0
  50. package/dist/state/cached.d.ts.map +1 -0
  51. package/dist/state/cached.js +157 -0
  52. package/dist/state/index.d.ts +61 -0
  53. package/dist/state/index.d.ts.map +1 -0
  54. package/dist/state/index.js +4 -0
  55. package/dist/state/local/index.d.ts +98 -0
  56. package/dist/state/local/index.d.ts.map +1 -0
  57. package/dist/state/local/index.js +247 -0
  58. package/dist/state/local/indexed-db.d.ts +41 -0
  59. package/dist/state/local/indexed-db.d.ts.map +1 -0
  60. package/dist/state/local/indexed-db.js +149 -0
  61. package/dist/state/local/memory.d.ts +41 -0
  62. package/dist/state/local/memory.d.ts.map +1 -0
  63. package/dist/state/local/memory.js +77 -0
  64. package/dist/state/remote/dev-http.d.ts +57 -0
  65. package/dist/state/remote/dev-http.d.ts.map +1 -0
  66. package/dist/state/remote/dev-http.js +162 -0
  67. package/dist/state/remote/index.d.ts +2 -0
  68. package/dist/state/remote/index.d.ts.map +1 -0
  69. package/dist/state/remote/index.js +1 -0
  70. package/dist/state/utils.d.ts +12 -0
  71. package/dist/state/utils.d.ts.map +1 -0
  72. package/dist/state/utils.js +29 -0
  73. package/dist/wallet.d.ts +58 -0
  74. package/dist/wallet.d.ts.map +1 -0
  75. package/dist/wallet.js +306 -0
  76. package/package.json +33 -0
  77. package/src/envelope.ts +148 -0
  78. package/src/index.ts +6 -0
  79. package/src/relayer/index.ts +3 -0
  80. package/src/relayer/local.ts +125 -0
  81. package/src/relayer/pk-relayer.ts +110 -0
  82. package/src/relayer/relayer.ts +52 -0
  83. package/src/signers/index.ts +44 -0
  84. package/src/signers/passkey.ts +284 -0
  85. package/src/signers/pk/encrypted.ts +153 -0
  86. package/src/signers/pk/index.ts +77 -0
  87. package/src/signers/session/explicit.ts +173 -0
  88. package/src/signers/session/implicit.ts +145 -0
  89. package/src/signers/session/index.ts +3 -0
  90. package/src/signers/session/session.ts +26 -0
  91. package/src/signers/session-manager.ts +241 -0
  92. package/src/state/cached.ts +233 -0
  93. package/src/state/index.ts +85 -0
  94. package/src/state/local/index.ts +422 -0
  95. package/src/state/local/indexed-db.ts +204 -0
  96. package/src/state/local/memory.ts +126 -0
  97. package/src/state/remote/dev-http.ts +253 -0
  98. package/src/state/remote/index.ts +1 -0
  99. package/src/state/utils.ts +50 -0
  100. package/src/wallet.ts +390 -0
  101. package/test/constants.ts +15 -0
  102. package/test/session-manager.test.ts +451 -0
  103. package/test/setup.ts +63 -0
  104. package/test/wallet.test.ts +90 -0
  105. package/tsconfig.json +10 -0
  106. package/vitest.config.ts +9 -0
@@ -0,0 +1,126 @@
1
+ import { Permission, SessionSignature, Utils } from '@0xsequence/wallet-primitives';
2
+ import { AbiParameters, Address, Bytes, Hash, Hex } from 'ox';
3
+ import { MemoryPkStore } from '../pk/index.js';
4
+ export class Explicit {
5
+ _privateKey;
6
+ address;
7
+ sessionPermissions;
8
+ constructor(privateKey, sessionPermissions) {
9
+ this._privateKey = typeof privateKey === 'string' ? new MemoryPkStore(privateKey) : privateKey;
10
+ this.address = this._privateKey.address();
11
+ this.sessionPermissions = {
12
+ ...sessionPermissions,
13
+ signer: this.address,
14
+ };
15
+ }
16
+ async findSupportedPermission(wallet, _chainId, call, provider) {
17
+ // Wallet and signer are encoded as a prefix for the usage hash
18
+ const limitHashPrefix = Hash.keccak256(AbiParameters.encode([
19
+ { type: 'address', name: 'wallet' },
20
+ { type: 'address', name: 'signer' },
21
+ ], [wallet, this.address]));
22
+ for (const [permissionIndex, permission] of this.sessionPermissions.permissions.entries()) {
23
+ // Encode the permission and permission index as a parameter for the usage hash
24
+ const encodeParams = [
25
+ { type: 'bytes32', name: 'limitHashPrefix' },
26
+ Permission.permissionStructAbi,
27
+ { type: 'uint256', name: 'permissionIndex' },
28
+ ];
29
+ const usageHash = Hash.keccak256(AbiParameters.encode(encodeParams, [
30
+ limitHashPrefix,
31
+ {
32
+ target: permission.target,
33
+ rules: permission.rules.map((rule) => ({
34
+ cumulative: rule.cumulative,
35
+ operation: rule.operation,
36
+ value: Bytes.toHex(Bytes.padRight(rule.value, 32)),
37
+ offset: rule.offset,
38
+ mask: Bytes.toHex(Bytes.padRight(rule.mask, 32)),
39
+ })),
40
+ },
41
+ BigInt(permissionIndex),
42
+ ]));
43
+ // Validate the permission
44
+ if (await validatePermission(permission, call, provider, usageHash)) {
45
+ return permission;
46
+ }
47
+ }
48
+ return undefined;
49
+ }
50
+ async supportedCall(wallet, chainId, call, provider) {
51
+ //FIXME Should this be stateful to support cumulative rules within a payload?
52
+ const permission = await this.findSupportedPermission(wallet, chainId, call, provider);
53
+ if (!permission) {
54
+ return false;
55
+ }
56
+ return true;
57
+ }
58
+ async signCall(wallet, chainId, call, nonce, provider) {
59
+ // Find the valid permission for this call
60
+ const permission = await this.findSupportedPermission(wallet, chainId, call, provider);
61
+ if (!permission) {
62
+ // This covers the support check
63
+ throw new Error('Invalid permission');
64
+ }
65
+ const permissionIndex = this.sessionPermissions.permissions.indexOf(permission);
66
+ if (permissionIndex === -1) {
67
+ // Unreachable
68
+ throw new Error('Invalid permission');
69
+ }
70
+ // Sign it
71
+ const callHash = SessionSignature.hashCallWithReplayProtection(call, chainId, nonce.space, nonce.nonce);
72
+ const sessionSignature = await this._privateKey.signDigest(Bytes.fromHex(callHash));
73
+ return {
74
+ permissionIndex: BigInt(permissionIndex),
75
+ sessionSignature,
76
+ };
77
+ }
78
+ }
79
+ async function validatePermission(permission, call, provider, usageHash) {
80
+ if (!Address.isEqual(permission.target, call.to)) {
81
+ return false;
82
+ }
83
+ for (const rule of permission.rules) {
84
+ // Extract value from calldata at offset
85
+ const callDataValue = Bytes.padRight(Bytes.fromHex(call.data).slice(Number(rule.offset), Number(rule.offset) + 32), 32);
86
+ // Apply mask
87
+ let value = callDataValue.map((b, i) => b & rule.mask[i]);
88
+ if (rule.cumulative) {
89
+ if (provider && usageHash) {
90
+ // Get the cumulative value from the contract storage
91
+ const storageSlot = Utils.getStorageSlotForMappingWithKey(Hex.toBigInt(usageHash), Hex.fromBytes(rule.value));
92
+ const storageValue = await provider.request({
93
+ method: 'eth_getStorageAt',
94
+ params: [permission.target, storageSlot, 'latest'],
95
+ });
96
+ // Increment the value
97
+ value = Bytes.padLeft(Bytes.fromNumber(Hex.toBigInt(storageValue) + Bytes.toBigInt(value)), 32);
98
+ }
99
+ else {
100
+ throw new Error('Cumulative rules require a provider and usage hash');
101
+ }
102
+ }
103
+ // Compare based on operation
104
+ if (rule.operation === Permission.ParameterOperation.EQUAL) {
105
+ if (!Bytes.isEqual(value, rule.value)) {
106
+ return false;
107
+ }
108
+ }
109
+ if (rule.operation === Permission.ParameterOperation.LESS_THAN_OR_EQUAL) {
110
+ if (Bytes.toBigInt(value) > Bytes.toBigInt(rule.value)) {
111
+ return false;
112
+ }
113
+ }
114
+ if (rule.operation === Permission.ParameterOperation.NOT_EQUAL) {
115
+ if (Bytes.isEqual(value, rule.value)) {
116
+ return false;
117
+ }
118
+ }
119
+ if (rule.operation === Permission.ParameterOperation.GREATER_THAN_OR_EQUAL) {
120
+ if (Bytes.toBigInt(value) < Bytes.toBigInt(rule.value)) {
121
+ return false;
122
+ }
123
+ }
124
+ }
125
+ return true;
126
+ }
@@ -0,0 +1,20 @@
1
+ import { Attestation, Payload, Signature as SequenceSignature, SessionSignature } from '@0xsequence/wallet-primitives';
2
+ import { Address, Hex, Provider } from 'ox';
3
+ import { PkStore } from '../pk/index.js';
4
+ import { SessionSigner } from './session.js';
5
+ export type AttestationParams = Omit<Attestation.Attestation, 'approvedSigner'>;
6
+ export declare class Implicit implements SessionSigner {
7
+ private readonly _attestation;
8
+ private readonly _sessionManager;
9
+ private readonly _privateKey;
10
+ private readonly _identitySignature;
11
+ readonly address: Address.Address;
12
+ constructor(privateKey: Hex.Hex | PkStore, _attestation: Attestation.Attestation, identitySignature: SequenceSignature.RSY | Hex.Hex, _sessionManager: Address.Address);
13
+ get identitySigner(): Address.Address;
14
+ supportedCall(wallet: Address.Address, _chainId: bigint, call: Payload.Call, provider?: Provider.Provider): Promise<boolean>;
15
+ signCall(wallet: Address.Address, chainId: bigint, call: Payload.Call, nonce: {
16
+ space: bigint;
17
+ nonce: bigint;
18
+ }, provider?: Provider.Provider): Promise<SessionSignature.SessionCallSignature>;
19
+ }
20
+ //# sourceMappingURL=implicit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"implicit.d.ts","sourceRoot":"","sources":["../../../src/signers/session/implicit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,IAAI,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACtH,OAAO,EAAe,OAAO,EAAS,GAAG,EAAE,QAAQ,EAAwB,MAAM,IAAI,CAAA;AACrF,OAAO,EAAiB,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAA;AAE/E,qBAAa,QAAS,YAAW,aAAa;IAO1C,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;IAWnD,IAAI,cAAc,IAAI,OAAO,CAAC,OAAO,CAKpC;IAEK,aAAa,CACjB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,OAAO,CAAC;IAyCb,QAAQ,CACZ,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,CAAA;KACd,EACD,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC;CAalD"}
@@ -0,0 +1,120 @@
1
+ import { Attestation, Payload, SessionSignature } from '@0xsequence/wallet-primitives';
2
+ import { AbiFunction, Address, Bytes, Hex, Secp256k1, Signature } from 'ox';
3
+ import { MemoryPkStore } from '../pk/index.js';
4
+ export class Implicit {
5
+ _attestation;
6
+ _sessionManager;
7
+ _privateKey;
8
+ _identitySignature;
9
+ address;
10
+ constructor(privateKey, _attestation, identitySignature, _sessionManager) {
11
+ this._attestation = _attestation;
12
+ this._sessionManager = _sessionManager;
13
+ this._privateKey = typeof privateKey === 'string' ? new MemoryPkStore(privateKey) : privateKey;
14
+ this.address = this._privateKey.address();
15
+ if (this._attestation.approvedSigner !== this.address) {
16
+ throw new Error('Invalid attestation');
17
+ }
18
+ this._identitySignature =
19
+ typeof identitySignature === 'string' ? Signature.fromHex(identitySignature) : identitySignature;
20
+ }
21
+ get identitySigner() {
22
+ // Recover identity signer from attestions and identity signature
23
+ const attestationHash = Attestation.hash(this._attestation);
24
+ const identityPubKey = Secp256k1.recoverPublicKey({ payload: attestationHash, signature: this._identitySignature });
25
+ return Address.fromPublicKey(identityPubKey);
26
+ }
27
+ async supportedCall(wallet, _chainId, call, provider) {
28
+ if (!provider) {
29
+ throw new Error('Provider is required');
30
+ }
31
+ try {
32
+ // Call the acceptImplicitRequest function on the called contract
33
+ const encodedCallData = AbiFunction.encodeData(acceptImplicitRequestFunctionAbi, [
34
+ wallet,
35
+ {
36
+ approvedSigner: this._attestation.approvedSigner,
37
+ identityType: Bytes.toHex(this._attestation.identityType),
38
+ issuerHash: Bytes.toHex(this._attestation.issuerHash),
39
+ audienceHash: Bytes.toHex(this._attestation.audienceHash),
40
+ applicationData: Bytes.toHex(this._attestation.applicationData),
41
+ authData: this._attestation.authData,
42
+ },
43
+ {
44
+ to: call.to,
45
+ value: call.value,
46
+ data: call.data,
47
+ gasLimit: call.gasLimit,
48
+ delegateCall: call.delegateCall,
49
+ onlyFallback: call.onlyFallback,
50
+ behaviorOnError: BigInt(Payload.encodeBehaviorOnError(call.behaviorOnError)),
51
+ },
52
+ ]);
53
+ const acceptImplicitRequestResult = await provider.request({
54
+ method: 'eth_call',
55
+ params: [{ from: this._sessionManager, to: call.to, data: encodedCallData }],
56
+ });
57
+ const acceptImplicitRequest = Hex.from(AbiFunction.decodeResult(acceptImplicitRequestFunctionAbi, acceptImplicitRequestResult));
58
+ const expectedResult = Bytes.toHex(Attestation.generateImplicitRequestMagic(this._attestation, wallet));
59
+ return acceptImplicitRequest === expectedResult;
60
+ }
61
+ catch (error) {
62
+ console.log('implicit signer unsupported call', call, error);
63
+ return false;
64
+ }
65
+ }
66
+ async signCall(wallet, chainId, call, nonce, provider) {
67
+ const isSupported = await this.supportedCall(wallet, chainId, call, provider);
68
+ if (!isSupported) {
69
+ throw new Error('Unsupported call');
70
+ }
71
+ const callHash = SessionSignature.hashCallWithReplayProtection(call, chainId, nonce.space, nonce.nonce);
72
+ const sessionSignature = await this._privateKey.signDigest(Bytes.fromHex(callHash));
73
+ return {
74
+ attestation: this._attestation,
75
+ identitySignature: this._identitySignature,
76
+ sessionSignature,
77
+ };
78
+ }
79
+ }
80
+ const acceptImplicitRequestFunctionAbi = {
81
+ type: 'function',
82
+ name: 'acceptImplicitRequest',
83
+ inputs: [
84
+ { name: 'wallet', type: 'address', internalType: 'address' },
85
+ {
86
+ name: 'attestation',
87
+ type: 'tuple',
88
+ internalType: 'struct Attestation',
89
+ components: [
90
+ { name: 'approvedSigner', type: 'address', internalType: 'address' },
91
+ { name: 'identityType', type: 'bytes4', internalType: 'bytes4' },
92
+ { name: 'issuerHash', type: 'bytes32', internalType: 'bytes32' },
93
+ { name: 'audienceHash', type: 'bytes32', internalType: 'bytes32' },
94
+ { name: 'applicationData', type: 'bytes', internalType: 'bytes' },
95
+ {
96
+ internalType: 'struct AuthData',
97
+ name: 'authData',
98
+ type: 'tuple',
99
+ components: [{ internalType: 'string', name: 'redirectUrl', type: 'string' }],
100
+ },
101
+ ],
102
+ },
103
+ {
104
+ name: 'call',
105
+ type: 'tuple',
106
+ internalType: 'struct Payload.Call',
107
+ components: [
108
+ { name: 'to', type: 'address', internalType: 'address' },
109
+ { name: 'value', type: 'uint256', internalType: 'uint256' },
110
+ { name: 'data', type: 'bytes', internalType: 'bytes' },
111
+ { name: 'gasLimit', type: 'uint256', internalType: 'uint256' },
112
+ { name: 'delegateCall', type: 'bool', internalType: 'bool' },
113
+ { name: 'onlyFallback', type: 'bool', internalType: 'bool' },
114
+ { name: 'behaviorOnError', type: 'uint256', internalType: 'uint256' },
115
+ ],
116
+ },
117
+ ],
118
+ outputs: [{ name: '', type: 'bytes32', internalType: 'bytes32' }],
119
+ stateMutability: 'view',
120
+ };
@@ -0,0 +1,4 @@
1
+ export * from './explicit.js';
2
+ export * from './implicit.js';
3
+ export * from './session.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/signers/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './explicit.js';
2
+ export * from './implicit.js';
3
+ export * from './session.js';
@@ -0,0 +1,11 @@
1
+ import { Address, Provider } from 'ox';
2
+ import { Payload, SessionSignature } from '@0xsequence/wallet-primitives';
3
+ export interface SessionSigner {
4
+ address: Address.Address | Promise<Address.Address>;
5
+ supportedCall: (wallet: Address.Address, chainId: bigint, call: Payload.Call, provider?: Provider.Provider) => Promise<boolean>;
6
+ signCall: (wallet: Address.Address, chainId: bigint, call: Payload.Call, nonce: {
7
+ space: bigint;
8
+ nonce: bigint;
9
+ }, provider?: Provider.Provider) => Promise<SessionSignature.SessionCallSignature>;
10
+ }
11
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/signers/session/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAEzE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAGnD,aAAa,EAAE,CACb,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,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,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,CAAA;KACd,EACD,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACzB,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;CACpD"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import { Payload, SessionConfig, Signature as SignatureTypes } from '@0xsequence/wallet-primitives';
2
+ import { Address, Hex, Provider } from 'ox';
3
+ import * as State from '../state/index.js';
4
+ import { Wallet } from '../wallet.js';
5
+ import { SapientSigner } from './index.js';
6
+ import { Explicit, Implicit } from './session/index.js';
7
+ export type SessionManagerOptions = {
8
+ sessionManagerAddress: Address.Address;
9
+ stateProvider?: State.Provider;
10
+ implicitSigners: Implicit[];
11
+ explicitSigners: Explicit[];
12
+ provider?: Provider.Provider;
13
+ };
14
+ export declare const DefaultSessionManagerOptions: SessionManagerOptions;
15
+ export declare class SessionManager implements SapientSigner {
16
+ readonly wallet: Wallet;
17
+ readonly stateProvider: State.Provider;
18
+ readonly address: Address.Address;
19
+ private readonly _implicitSigners;
20
+ private readonly _explicitSigners;
21
+ private readonly _provider?;
22
+ constructor(wallet: Wallet, options?: Partial<SessionManagerOptions>);
23
+ get imageHash(): Promise<Hex.Hex | undefined>;
24
+ getImageHash(): Promise<Hex.Hex | undefined>;
25
+ get topology(): Promise<SessionConfig.SessionsTopology>;
26
+ getTopology(): Promise<SessionConfig.SessionsTopology>;
27
+ withProvider(provider: Provider.Provider): SessionManager;
28
+ withImplicitSigner(signer: Implicit): SessionManager;
29
+ withExplicitSigner(signer: Explicit): SessionManager;
30
+ signSapient(wallet: Address.Address, chainId: bigint, payload: Payload.Parented, imageHash: Hex.Hex): Promise<SignatureTypes.SignatureOfSapientSignerLeaf>;
31
+ isValidSapientSignature(wallet: Address.Address, chainId: bigint, payload: Payload.Parented, signature: SignatureTypes.SignatureOfSapientSignerLeaf): Promise<boolean>;
32
+ }
33
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/signers/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,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,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAEvD,MAAM,MAAM,qBAAqB,GAAG;IAClC,qBAAqB,EAAE,OAAO,CAAC,OAAO,CAAA;IACtC,aAAa,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAA;IAC9B,eAAe,EAAE,QAAQ,EAAE,CAAA;IAC3B,eAAe,EAAE,QAAQ,EAAE,CAAA;IAC3B,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;CAC7B,CAAA;AAED,eAAO,MAAM,4BAA4B,EAAE,qBAI1C,CAAA;AAED,qBAAa,cAAe,YAAW,aAAa;IAShD,QAAQ,CAAC,MAAM,EAAE,MAAM;IARzB,SAAgB,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAA;IAC7C,SAAgB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IAExC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAY;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAY;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAmB;gBAGnC,MAAM,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAU1C,IAAI,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC,CAE5C;IAEK,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC;IASlD,IAAI,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAEtD;IAEK,WAAW,IAAI,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC;IAY5D,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,GAAG,cAAc;IAUzD,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,cAAc;IAWpD,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,cAAc;IAY9C,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;IAkFjD,uBAAuB,CAC3B,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,QAAQ,EACzB,SAAS,EAAE,cAAc,CAAC,4BAA4B,GACrD,OAAO,CAAC,OAAO,CAAC;CAsCpB"}
@@ -0,0 +1,181 @@
1
+ import { Config, Constants, Payload, SessionConfig, SessionSignature, } from '@0xsequence/wallet-primitives';
2
+ import { AbiFunction, Address, Hex } from 'ox';
3
+ export const DefaultSessionManagerOptions = {
4
+ sessionManagerAddress: Constants.DefaultSessionManager,
5
+ implicitSigners: [],
6
+ explicitSigners: [],
7
+ };
8
+ export class SessionManager {
9
+ wallet;
10
+ stateProvider;
11
+ address;
12
+ _implicitSigners;
13
+ _explicitSigners;
14
+ _provider;
15
+ constructor(wallet, options) {
16
+ this.wallet = wallet;
17
+ const combinedOptions = { ...DefaultSessionManagerOptions, ...options };
18
+ this.stateProvider = combinedOptions.stateProvider ?? wallet.stateProvider;
19
+ this.address = combinedOptions.sessionManagerAddress;
20
+ this._implicitSigners = combinedOptions.implicitSigners;
21
+ this._explicitSigners = combinedOptions.explicitSigners;
22
+ this._provider = combinedOptions.provider;
23
+ }
24
+ get imageHash() {
25
+ return this.getImageHash();
26
+ }
27
+ async getImageHash() {
28
+ const { configuration } = await this.wallet.getStatus();
29
+ const sessionConfigLeaf = Config.findSignerLeaf(configuration, this.address);
30
+ if (!sessionConfigLeaf || !Config.isSapientSignerLeaf(sessionConfigLeaf)) {
31
+ return undefined;
32
+ }
33
+ return sessionConfigLeaf.imageHash;
34
+ }
35
+ get topology() {
36
+ return this.getTopology();
37
+ }
38
+ async getTopology() {
39
+ const imageHash = await this.imageHash;
40
+ if (!imageHash) {
41
+ throw new Error(`Session configuration not found for image hash ${imageHash}`);
42
+ }
43
+ const tree = await this.stateProvider.getTree(imageHash);
44
+ if (!tree) {
45
+ throw new Error(`Session configuration not found for image hash ${imageHash}`);
46
+ }
47
+ return SessionConfig.configurationTreeToSessionsTopology(tree);
48
+ }
49
+ withProvider(provider) {
50
+ return new SessionManager(this.wallet, {
51
+ sessionManagerAddress: this.address,
52
+ stateProvider: this.stateProvider,
53
+ implicitSigners: this._implicitSigners,
54
+ explicitSigners: this._explicitSigners,
55
+ provider,
56
+ });
57
+ }
58
+ withImplicitSigner(signer) {
59
+ const implicitSigners = [...this._implicitSigners, signer];
60
+ return new SessionManager(this.wallet, {
61
+ sessionManagerAddress: this.address,
62
+ stateProvider: this.stateProvider,
63
+ implicitSigners,
64
+ explicitSigners: this._explicitSigners,
65
+ provider: this._provider,
66
+ });
67
+ }
68
+ withExplicitSigner(signer) {
69
+ const explicitSigners = [...this._explicitSigners, signer];
70
+ return new SessionManager(this.wallet, {
71
+ sessionManagerAddress: this.address,
72
+ stateProvider: this.stateProvider,
73
+ implicitSigners: this._implicitSigners,
74
+ explicitSigners,
75
+ provider: this._provider,
76
+ });
77
+ }
78
+ async signSapient(wallet, chainId, payload, imageHash) {
79
+ if (wallet !== this.wallet.address) {
80
+ throw new Error('Wallet address mismatch');
81
+ }
82
+ if ((await this.imageHash) !== imageHash) {
83
+ throw new Error('Unexpected image hash');
84
+ }
85
+ //FIXME Test chain id
86
+ // if (this._provider) {
87
+ // const providerChainId = await this._provider.request({
88
+ // method: 'eth_chainId',
89
+ // })
90
+ // if (providerChainId !== Hex.fromNumber(chainId)) {
91
+ // throw new Error(`Provider chain id mismatch, expected ${Hex.fromNumber(chainId)} but got ${providerChainId}`)
92
+ // }
93
+ // }
94
+ if (!Payload.isCalls(payload)) {
95
+ throw new Error('Only calls are supported');
96
+ }
97
+ // Only use signers that match the topology
98
+ const topology = await this.topology;
99
+ const identitySigner = SessionConfig.getIdentitySigner(topology);
100
+ if (!identitySigner) {
101
+ throw new Error('Identity signer not found');
102
+ }
103
+ const blacklist = SessionConfig.getImplicitBlacklist(topology);
104
+ const validImplicitSigners = this._implicitSigners.filter((signer) => Address.isEqual(signer.identitySigner, identitySigner) &&
105
+ // Blacklist must exist for implicit signers to be used
106
+ blacklist &&
107
+ !blacklist.some((b) => Address.isEqual(b, signer.address)));
108
+ const topologyExplicitSigners = SessionConfig.getExplicitSigners(topology);
109
+ const validExplicitSigners = this._explicitSigners.filter((signer) => topologyExplicitSigners.some((s) => Address.isEqual(s, signer.address)));
110
+ // Try to sign with each signer, prioritizing implicit signers
111
+ const signers = [...validImplicitSigners, ...validExplicitSigners];
112
+ if (signers.length === 0) {
113
+ throw new Error('No signers match the topology');
114
+ }
115
+ const signatures = await Promise.all(
116
+ //FIXME Run sync to support cumulative rules within a payload
117
+ payload.calls.map(async (call) => {
118
+ for (const signer of signers) {
119
+ try {
120
+ if (await signer.supportedCall(wallet, chainId, call, this._provider)) {
121
+ const signature = await signer.signCall(wallet, chainId, call, payload, this._provider);
122
+ return {
123
+ ...signature,
124
+ signer: signer.address,
125
+ };
126
+ }
127
+ }
128
+ catch (error) {
129
+ console.error('signSapient error', error);
130
+ }
131
+ }
132
+ throw new Error('No signer supported');
133
+ }));
134
+ const explicitSigners = signatures
135
+ .filter((sig) => SessionSignature.isExplicitSessionCallSignature(sig))
136
+ .map((sig) => sig.signer);
137
+ const implicitSigners = signatures
138
+ .filter((sig) => SessionSignature.isImplicitSessionCallSignature(sig))
139
+ .map((sig) => sig.signer);
140
+ return {
141
+ type: 'sapient',
142
+ address: this.address,
143
+ data: Hex.from(SessionSignature.encodeSessionCallSignatures(signatures, topology, explicitSigners, implicitSigners)),
144
+ };
145
+ }
146
+ async isValidSapientSignature(wallet, chainId, payload, signature) {
147
+ if (!Payload.isCalls(payload)) {
148
+ // Only calls are supported
149
+ return false;
150
+ }
151
+ if (!this._provider) {
152
+ throw new Error('Provider not set');
153
+ }
154
+ //FIXME Test chain id
155
+ // const providerChainId = await this._provider.request({
156
+ // method: 'eth_chainId',
157
+ // })
158
+ // if (providerChainId !== Hex.fromNumber(chainId)) {
159
+ // throw new Error(
160
+ // `Provider chain id mismatch, expected ${Hex.fromNumber(chainId)} but got ${providerChainId}`,
161
+ // )
162
+ // }
163
+ const encodedPayload = Payload.encodeSapient(chainId, payload);
164
+ const encodedCallData = AbiFunction.encodeData(Constants.RECOVER_SAPIENT_SIGNATURE, [
165
+ encodedPayload,
166
+ signature.data,
167
+ ]);
168
+ try {
169
+ const recoverSapientSignatureResult = await this._provider.request({
170
+ method: 'eth_call',
171
+ params: [{ from: wallet, to: this.address, data: encodedCallData }],
172
+ });
173
+ const resultImageHash = Hex.from(AbiFunction.decodeResult(Constants.RECOVER_SAPIENT_SIGNATURE, recoverSapientSignatureResult));
174
+ return resultImageHash === (await this.imageHash);
175
+ }
176
+ catch (error) {
177
+ console.error('recoverSapientSignature error', error);
178
+ return false;
179
+ }
180
+ }
181
+ }
@@ -0,0 +1,59 @@
1
+ import { Address, Hex } from 'ox';
2
+ import { MaybePromise, Provider } from './index.js';
3
+ import { Config, Context, GenericTree, Payload, Signature } from '@0xsequence/wallet-primitives';
4
+ export declare class Cached implements Provider {
5
+ private readonly args;
6
+ constructor(args: {
7
+ readonly source: Provider;
8
+ readonly cache: Provider;
9
+ });
10
+ getConfiguration(imageHash: Hex.Hex): Promise<Config.Config | undefined>;
11
+ getDeploy(wallet: Address.Address): Promise<{
12
+ imageHash: Hex.Hex;
13
+ context: Context.Context;
14
+ } | undefined>;
15
+ getWallets(signer: Address.Address): Promise<{
16
+ [wallet: Address.Address]: {
17
+ chainId: bigint;
18
+ payload: Payload.Parented;
19
+ signature: Signature.SignatureOfSignerLeaf;
20
+ };
21
+ }>;
22
+ getWalletsForSapient(signer: Address.Address, imageHash: Hex.Hex): Promise<{
23
+ [wallet: Address.Address]: {
24
+ chainId: bigint;
25
+ payload: Payload.Parented;
26
+ signature: Signature.SignatureOfSapientSignerLeaf;
27
+ };
28
+ }>;
29
+ getWitnessFor(wallet: Address.Address, signer: Address.Address): Promise<{
30
+ chainId: bigint;
31
+ payload: Payload.Parented;
32
+ signature: Signature.SignatureOfSignerLeaf;
33
+ } | undefined>;
34
+ getWitnessForSapient(wallet: Address.Address, signer: Address.Address, imageHash: Hex.Hex): Promise<{
35
+ chainId: bigint;
36
+ payload: Payload.Parented;
37
+ signature: Signature.SignatureOfSapientSignerLeaf;
38
+ } | undefined>;
39
+ getConfigurationUpdates(wallet: Address.Address, fromImageHash: Hex.Hex, options?: {
40
+ allUpdates?: boolean;
41
+ }): Promise<Array<{
42
+ imageHash: Hex.Hex;
43
+ signature: Signature.RawSignature;
44
+ }>>;
45
+ getTree(rootHash: Hex.Hex): Promise<GenericTree.Tree | undefined>;
46
+ saveWallet(deployConfiguration: Config.Config, context: Context.Context): MaybePromise<void>;
47
+ saveWitnesses(wallet: Address.Address, chainId: bigint, payload: Payload.Parented, signatures: Signature.RawTopology): MaybePromise<void>;
48
+ saveUpdate(wallet: Address.Address, configuration: Config.Config, signature: Signature.RawSignature): MaybePromise<void>;
49
+ saveTree(tree: GenericTree.Tree): MaybePromise<void>;
50
+ saveConfiguration(config: Config.Config): MaybePromise<void>;
51
+ saveDeploy(imageHash: Hex.Hex, context: Context.Context): MaybePromise<void>;
52
+ getPayload(opHash: Hex.Hex): Promise<{
53
+ chainId: bigint;
54
+ payload: Payload.Parented;
55
+ wallet: Address.Address;
56
+ } | undefined>;
57
+ savePayload(wallet: Address.Address, payload: Payload.Parented, chainId: bigint): MaybePromise<void>;
58
+ }
59
+ //# sourceMappingURL=cached.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cached.d.ts","sourceRoot":"","sources":["../../src/state/cached.ts"],"names":[],"mappings":"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"}