@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.
- package/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE +202 -0
- package/dist/address.d.ts +5 -0
- package/dist/address.d.ts.map +1 -0
- package/dist/address.js +7 -0
- package/dist/address.js.map +1 -0
- package/dist/attestation.d.ts +24 -0
- package/dist/attestation.d.ts.map +1 -0
- package/dist/attestation.js +77 -0
- package/dist/attestation.js.map +1 -0
- package/dist/config.d.ts +85 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +381 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +173 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +31 -0
- package/dist/constants.js.map +1 -0
- package/dist/context.d.ts +9 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +8 -0
- package/dist/context.js.map +1 -0
- package/dist/erc-6492.d.ts +19 -0
- package/dist/erc-6492.d.ts.map +1 -0
- package/dist/erc-6492.js +64 -0
- package/dist/erc-6492.js.map +1 -0
- package/dist/extensions/index.d.ts +9 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +7 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/passkeys.d.ts +31 -0
- package/dist/extensions/passkeys.d.ts.map +1 -0
- package/dist/extensions/passkeys.js +224 -0
- package/dist/extensions/passkeys.js.map +1 -0
- package/dist/extensions/recovery.d.ts +310 -0
- package/dist/extensions/recovery.d.ts.map +1 -0
- package/dist/extensions/recovery.js +444 -0
- package/dist/extensions/recovery.js.map +1 -0
- package/dist/generic-tree.d.ts +14 -0
- package/dist/generic-tree.d.ts.map +1 -0
- package/dist/generic-tree.js +34 -0
- package/dist/generic-tree.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/network.d.ts +15 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +24 -0
- package/dist/network.js.map +1 -0
- package/dist/payload.d.ts +108 -0
- package/dist/payload.d.ts.map +1 -0
- package/dist/payload.js +627 -0
- package/dist/payload.js.map +1 -0
- package/dist/permission.d.ts +73 -0
- package/dist/permission.d.ts.map +1 -0
- package/dist/permission.js +188 -0
- package/dist/permission.js.map +1 -0
- package/dist/session-config.d.ts +113 -0
- package/dist/session-config.d.ts.map +1 -0
- package/dist/session-config.js +554 -0
- package/dist/session-config.js.map +1 -0
- package/dist/session-signature.d.ts +24 -0
- package/dist/session-signature.d.ts.map +1 -0
- package/dist/session-signature.js +141 -0
- package/dist/session-signature.js.map +1 -0
- package/dist/signature.d.ts +108 -0
- package/dist/signature.d.ts.map +1 -0
- package/dist/signature.js +1079 -0
- package/dist/signature.js.map +1 -0
- package/dist/utils.d.ts +45 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +100 -0
- package/dist/utils.js.map +1 -0
- package/eslint.config.mjs +4 -0
- package/package.json +27 -0
- package/src/address.ts +19 -0
- package/src/attestation.ts +114 -0
- package/src/config.ts +521 -0
- package/src/constants.ts +39 -0
- package/src/context.ts +16 -0
- package/src/erc-6492.ts +97 -0
- package/src/extensions/index.ts +14 -0
- package/src/extensions/passkeys.ts +283 -0
- package/src/extensions/recovery.ts +542 -0
- package/src/generic-tree.ts +55 -0
- package/src/index.ts +15 -0
- package/src/network.ts +37 -0
- package/src/payload.ts +825 -0
- package/src/permission.ts +252 -0
- package/src/session-config.ts +681 -0
- package/src/session-signature.ts +197 -0
- package/src/signature.ts +1398 -0
- package/src/utils.ts +114 -0
- 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
|
+
}
|