@0xsequence/wallet-primitives 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 (96) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/CHANGELOG.md +7 -0
  3. package/LICENSE +202 -0
  4. package/dist/address.d.ts +5 -0
  5. package/dist/address.d.ts.map +1 -0
  6. package/dist/address.js +7 -0
  7. package/dist/address.js.map +1 -0
  8. package/dist/attestation.d.ts +24 -0
  9. package/dist/attestation.d.ts.map +1 -0
  10. package/dist/attestation.js +77 -0
  11. package/dist/attestation.js.map +1 -0
  12. package/dist/config.d.ts +85 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/config.js +381 -0
  15. package/dist/config.js.map +1 -0
  16. package/dist/constants.d.ts +173 -0
  17. package/dist/constants.d.ts.map +1 -0
  18. package/dist/constants.js +31 -0
  19. package/dist/constants.js.map +1 -0
  20. package/dist/context.d.ts +9 -0
  21. package/dist/context.d.ts.map +1 -0
  22. package/dist/context.js +8 -0
  23. package/dist/context.js.map +1 -0
  24. package/dist/erc-6492.d.ts +19 -0
  25. package/dist/erc-6492.d.ts.map +1 -0
  26. package/dist/erc-6492.js +64 -0
  27. package/dist/erc-6492.js.map +1 -0
  28. package/dist/extensions/index.d.ts +9 -0
  29. package/dist/extensions/index.d.ts.map +1 -0
  30. package/dist/extensions/index.js +7 -0
  31. package/dist/extensions/index.js.map +1 -0
  32. package/dist/extensions/passkeys.d.ts +31 -0
  33. package/dist/extensions/passkeys.d.ts.map +1 -0
  34. package/dist/extensions/passkeys.js +224 -0
  35. package/dist/extensions/passkeys.js.map +1 -0
  36. package/dist/extensions/recovery.d.ts +310 -0
  37. package/dist/extensions/recovery.d.ts.map +1 -0
  38. package/dist/extensions/recovery.js +444 -0
  39. package/dist/extensions/recovery.js.map +1 -0
  40. package/dist/generic-tree.d.ts +14 -0
  41. package/dist/generic-tree.d.ts.map +1 -0
  42. package/dist/generic-tree.js +34 -0
  43. package/dist/generic-tree.js.map +1 -0
  44. package/dist/index.d.ts +16 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +16 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/network.d.ts +15 -0
  49. package/dist/network.d.ts.map +1 -0
  50. package/dist/network.js +24 -0
  51. package/dist/network.js.map +1 -0
  52. package/dist/payload.d.ts +108 -0
  53. package/dist/payload.d.ts.map +1 -0
  54. package/dist/payload.js +627 -0
  55. package/dist/payload.js.map +1 -0
  56. package/dist/permission.d.ts +73 -0
  57. package/dist/permission.d.ts.map +1 -0
  58. package/dist/permission.js +188 -0
  59. package/dist/permission.js.map +1 -0
  60. package/dist/session-config.d.ts +113 -0
  61. package/dist/session-config.d.ts.map +1 -0
  62. package/dist/session-config.js +554 -0
  63. package/dist/session-config.js.map +1 -0
  64. package/dist/session-signature.d.ts +24 -0
  65. package/dist/session-signature.d.ts.map +1 -0
  66. package/dist/session-signature.js +141 -0
  67. package/dist/session-signature.js.map +1 -0
  68. package/dist/signature.d.ts +108 -0
  69. package/dist/signature.d.ts.map +1 -0
  70. package/dist/signature.js +1079 -0
  71. package/dist/signature.js.map +1 -0
  72. package/dist/utils.d.ts +45 -0
  73. package/dist/utils.d.ts.map +1 -0
  74. package/dist/utils.js +100 -0
  75. package/dist/utils.js.map +1 -0
  76. package/eslint.config.mjs +4 -0
  77. package/package.json +27 -0
  78. package/src/address.ts +19 -0
  79. package/src/attestation.ts +114 -0
  80. package/src/config.ts +521 -0
  81. package/src/constants.ts +39 -0
  82. package/src/context.ts +16 -0
  83. package/src/erc-6492.ts +97 -0
  84. package/src/extensions/index.ts +14 -0
  85. package/src/extensions/passkeys.ts +283 -0
  86. package/src/extensions/recovery.ts +542 -0
  87. package/src/generic-tree.ts +55 -0
  88. package/src/index.ts +15 -0
  89. package/src/network.ts +37 -0
  90. package/src/payload.ts +825 -0
  91. package/src/permission.ts +252 -0
  92. package/src/session-config.ts +681 -0
  93. package/src/session-signature.ts +197 -0
  94. package/src/signature.ts +1398 -0
  95. package/src/utils.ts +114 -0
  96. package/tsconfig.json +10 -0
@@ -0,0 +1,197 @@
1
+ import { Address, Bytes, Hash, Hex } from 'ox'
2
+ import { Attestation, encode, encodeForJson, fromParsed } from './attestation.js'
3
+ import { MAX_PERMISSIONS_COUNT } from './permission.js'
4
+ import {
5
+ encodeSessionsTopology,
6
+ isCompleteSessionsTopology,
7
+ minimiseSessionsTopology,
8
+ SessionsTopology,
9
+ } from './session-config.js'
10
+ import { RSY } from './signature.js'
11
+ import { minBytesFor, packRSY } from './utils.js'
12
+ import { Payload } from './index.js'
13
+
14
+ export type ImplicitSessionCallSignature = {
15
+ attestation: Attestation
16
+ identitySignature: RSY
17
+ sessionSignature: RSY
18
+ }
19
+
20
+ export type ExplicitSessionCallSignature = {
21
+ permissionIndex: bigint
22
+ sessionSignature: RSY
23
+ }
24
+
25
+ export type SessionCallSignature = ImplicitSessionCallSignature | ExplicitSessionCallSignature
26
+
27
+ export function isImplicitSessionCallSignature(
28
+ callSignature: SessionCallSignature,
29
+ ): callSignature is ImplicitSessionCallSignature {
30
+ return 'attestation' in callSignature && 'identitySignature' in callSignature && 'sessionSignature' in callSignature
31
+ }
32
+
33
+ export function isExplicitSessionCallSignature(
34
+ callSignature: SessionCallSignature,
35
+ ): callSignature is ExplicitSessionCallSignature {
36
+ return 'permissionIndex' in callSignature && 'sessionSignature' in callSignature
37
+ }
38
+
39
+ // JSON
40
+
41
+ export function sessionCallSignatureToJson(callSignature: SessionCallSignature): string {
42
+ return JSON.stringify(encodeSessionCallSignatureForJson(callSignature))
43
+ }
44
+
45
+ export function encodeSessionCallSignatureForJson(callSignature: SessionCallSignature): any {
46
+ if (isImplicitSessionCallSignature(callSignature)) {
47
+ return {
48
+ attestation: encodeForJson(callSignature.attestation),
49
+ identitySignature: rsyToRsvStr(callSignature.identitySignature),
50
+ sessionSignature: rsyToRsvStr(callSignature.sessionSignature),
51
+ }
52
+ } else if (isExplicitSessionCallSignature(callSignature)) {
53
+ return {
54
+ permissionIndex: callSignature.permissionIndex,
55
+ sessionSignature: rsyToRsvStr(callSignature.sessionSignature),
56
+ }
57
+ } else {
58
+ throw new Error('Invalid call signature')
59
+ }
60
+ }
61
+
62
+ export function sessionCallSignatureFromJson(json: string): SessionCallSignature {
63
+ const decoded = JSON.parse(json)
64
+ return sessionCallSignatureFromParsed(decoded)
65
+ }
66
+
67
+ export function sessionCallSignatureFromParsed(decoded: any): SessionCallSignature {
68
+ if (decoded.attestation) {
69
+ return {
70
+ attestation: fromParsed(decoded.attestation),
71
+ identitySignature: rsyFromRsvStr(decoded.identitySignature),
72
+ sessionSignature: rsyFromRsvStr(decoded.sessionSignature),
73
+ }
74
+ } else if (decoded.permissionIndex) {
75
+ return {
76
+ permissionIndex: decoded.permissionIndex,
77
+ sessionSignature: rsyFromRsvStr(decoded.sessionSignature),
78
+ }
79
+ } else {
80
+ throw new Error('Invalid call signature')
81
+ }
82
+ }
83
+
84
+ function rsyToRsvStr(sig: RSY): string {
85
+ return `${sig.r.toString()}:${sig.s.toString()}:${sig.yParity + 27}`
86
+ }
87
+
88
+ function rsyFromRsvStr(sigStr: string): RSY {
89
+ const parts = sigStr.split(':')
90
+ if (parts.length !== 3) {
91
+ throw new Error('Signature must be in r:s:v format')
92
+ }
93
+ const [rStr, sStr, vStr] = parts
94
+ if (!rStr || !sStr || !vStr) {
95
+ throw new Error('Invalid signature format')
96
+ }
97
+ return {
98
+ r: Bytes.toBigInt(Bytes.fromHex(rStr as `0x${string}`, { size: 32 })),
99
+ s: Bytes.toBigInt(Bytes.fromHex(sStr as `0x${string}`, { size: 32 })),
100
+ yParity: parseInt(vStr, 10) - 27,
101
+ }
102
+ }
103
+
104
+ // Usage
105
+
106
+ export function encodeSessionCallSignatures(
107
+ callSignatures: SessionCallSignature[],
108
+ topology: SessionsTopology,
109
+ explicitSigners: Address.Address[] = [],
110
+ implicitSigners: Address.Address[] = [],
111
+ ): Bytes.Bytes {
112
+ const parts: Bytes.Bytes[] = []
113
+
114
+ // Validate the topology
115
+ if (!isCompleteSessionsTopology(topology)) {
116
+ // Refuse to encode incomplete topologies
117
+ throw new Error('Incomplete topology')
118
+ }
119
+
120
+ // Optimise the configuration tree by rolling unused signers into nodes.
121
+ topology = minimiseSessionsTopology(topology, explicitSigners, implicitSigners)
122
+
123
+ // Session topology
124
+ const encodedTopology = encodeSessionsTopology(topology)
125
+ if (minBytesFor(BigInt(encodedTopology.length)) > 3) {
126
+ throw new Error('Session topology is too large')
127
+ }
128
+ parts.push(Bytes.fromNumber(encodedTopology.length, { size: 3 }), encodedTopology)
129
+
130
+ // Create unique attestation list and maintain index mapping
131
+ const attestationMap = new Map<string, number>()
132
+ const encodedAttestations: Bytes.Bytes[] = []
133
+
134
+ // Map each call signature to its attestation index
135
+ callSignatures.filter(isImplicitSessionCallSignature).forEach((callSig) => {
136
+ if (callSig.attestation) {
137
+ const attestationStr = JSON.stringify(callSig.attestation)
138
+ if (!attestationMap.has(attestationStr)) {
139
+ attestationMap.set(attestationStr, encodedAttestations.length)
140
+ encodedAttestations.push(Bytes.concat(encode(callSig.attestation), packRSY(callSig.identitySignature)))
141
+ }
142
+ }
143
+ })
144
+
145
+ // Add the attestations to the parts
146
+ if (encodedAttestations.length >= 128) {
147
+ throw new Error('Too many attestations')
148
+ }
149
+ parts.push(Bytes.fromNumber(encodedAttestations.length, { size: 1 }), Bytes.concat(...encodedAttestations))
150
+
151
+ // Call signature parts
152
+ for (const callSignature of callSignatures) {
153
+ if (isImplicitSessionCallSignature(callSignature)) {
154
+ // Implicit
155
+ const attestationStr = JSON.stringify(callSignature.attestation)
156
+ const attestationIndex = attestationMap.get(attestationStr)
157
+ if (attestationIndex === undefined) {
158
+ // Unreachable
159
+ throw new Error('Failed to find attestation index')
160
+ }
161
+ const packedFlag = 0x80 | attestationIndex // Implicit flag (MSB) true + attestation index
162
+ parts.push(Bytes.fromNumber(packedFlag, { size: 1 }), packRSY(callSignature.sessionSignature))
163
+ } else if (isExplicitSessionCallSignature(callSignature)) {
164
+ // Explicit
165
+ if (callSignature.permissionIndex > MAX_PERMISSIONS_COUNT) {
166
+ throw new Error('Permission index is too large')
167
+ }
168
+ const packedFlag = callSignature.permissionIndex // Implicit flag (MSB) false + permission index
169
+ parts.push(Bytes.fromNumber(packedFlag, { size: 1 }), packRSY(callSignature.sessionSignature))
170
+ } else {
171
+ // Invalid call signature
172
+ throw new Error('Invalid call signature')
173
+ }
174
+ }
175
+
176
+ return Bytes.concat(...parts)
177
+ }
178
+
179
+ // Helper
180
+
181
+ export function hashCallWithReplayProtection(
182
+ call: Payload.Call,
183
+ chainId: bigint,
184
+ space: bigint,
185
+ nonce: bigint,
186
+ ): Hex.Hex {
187
+ return Hex.fromBytes(
188
+ Hash.keccak256(
189
+ Bytes.concat(
190
+ Bytes.fromNumber(Number(chainId), { size: 32 }),
191
+ Bytes.fromNumber(Number(space), { size: 32 }),
192
+ Bytes.fromNumber(Number(nonce), { size: 32 }),
193
+ Bytes.fromHex(Payload.hashCall(call)),
194
+ ),
195
+ ),
196
+ )
197
+ }