@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.
- package/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +9 -0
- package/LICENSE +202 -0
- package/dist/envelope.d.ts +34 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +96 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/relayer/index.d.ts +4 -0
- package/dist/relayer/index.d.ts.map +1 -0
- package/dist/relayer/index.js +3 -0
- package/dist/relayer/local.d.ts +28 -0
- package/dist/relayer/local.d.ts.map +1 -0
- package/dist/relayer/local.js +101 -0
- package/dist/relayer/pk-relayer.d.ts +18 -0
- package/dist/relayer/pk-relayer.d.ts.map +1 -0
- package/dist/relayer/pk-relayer.js +88 -0
- package/dist/relayer/relayer.d.ts +39 -0
- package/dist/relayer/relayer.d.ts.map +1 -0
- package/dist/relayer/relayer.js +1 -0
- package/dist/signers/index.d.ts +23 -0
- package/dist/signers/index.d.ts.map +1 -0
- package/dist/signers/index.js +10 -0
- package/dist/signers/passkey.d.ts +41 -0
- package/dist/signers/passkey.d.ts.map +1 -0
- package/dist/signers/passkey.js +196 -0
- package/dist/signers/pk/encrypted.d.ts +37 -0
- package/dist/signers/pk/encrypted.d.ts.map +1 -0
- package/dist/signers/pk/encrypted.js +123 -0
- package/dist/signers/pk/index.d.ts +35 -0
- package/dist/signers/pk/index.d.ts.map +1 -0
- package/dist/signers/pk/index.js +51 -0
- package/dist/signers/session/explicit.d.ts +18 -0
- package/dist/signers/session/explicit.d.ts.map +1 -0
- package/dist/signers/session/explicit.js +126 -0
- package/dist/signers/session/implicit.d.ts +20 -0
- package/dist/signers/session/implicit.d.ts.map +1 -0
- package/dist/signers/session/implicit.js +120 -0
- package/dist/signers/session/index.d.ts +4 -0
- package/dist/signers/session/index.d.ts.map +1 -0
- package/dist/signers/session/index.js +3 -0
- package/dist/signers/session/session.d.ts +11 -0
- package/dist/signers/session/session.d.ts.map +1 -0
- package/dist/signers/session/session.js +1 -0
- package/dist/signers/session-manager.d.ts +33 -0
- package/dist/signers/session-manager.d.ts.map +1 -0
- package/dist/signers/session-manager.js +181 -0
- package/dist/state/cached.d.ts +59 -0
- package/dist/state/cached.d.ts.map +1 -0
- package/dist/state/cached.js +157 -0
- package/dist/state/index.d.ts +61 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +4 -0
- package/dist/state/local/index.d.ts +98 -0
- package/dist/state/local/index.d.ts.map +1 -0
- package/dist/state/local/index.js +247 -0
- package/dist/state/local/indexed-db.d.ts +41 -0
- package/dist/state/local/indexed-db.d.ts.map +1 -0
- package/dist/state/local/indexed-db.js +149 -0
- package/dist/state/local/memory.d.ts +41 -0
- package/dist/state/local/memory.d.ts.map +1 -0
- package/dist/state/local/memory.js +77 -0
- package/dist/state/remote/dev-http.d.ts +57 -0
- package/dist/state/remote/dev-http.d.ts.map +1 -0
- package/dist/state/remote/dev-http.js +162 -0
- package/dist/state/remote/index.d.ts +2 -0
- package/dist/state/remote/index.d.ts.map +1 -0
- package/dist/state/remote/index.js +1 -0
- package/dist/state/utils.d.ts +12 -0
- package/dist/state/utils.d.ts.map +1 -0
- package/dist/state/utils.js +29 -0
- package/dist/wallet.d.ts +58 -0
- package/dist/wallet.d.ts.map +1 -0
- package/dist/wallet.js +306 -0
- package/package.json +33 -0
- package/src/envelope.ts +148 -0
- package/src/index.ts +6 -0
- package/src/relayer/index.ts +3 -0
- package/src/relayer/local.ts +125 -0
- package/src/relayer/pk-relayer.ts +110 -0
- package/src/relayer/relayer.ts +52 -0
- package/src/signers/index.ts +44 -0
- package/src/signers/passkey.ts +284 -0
- package/src/signers/pk/encrypted.ts +153 -0
- package/src/signers/pk/index.ts +77 -0
- package/src/signers/session/explicit.ts +173 -0
- package/src/signers/session/implicit.ts +145 -0
- package/src/signers/session/index.ts +3 -0
- package/src/signers/session/session.ts +26 -0
- package/src/signers/session-manager.ts +241 -0
- package/src/state/cached.ts +233 -0
- package/src/state/index.ts +85 -0
- package/src/state/local/index.ts +422 -0
- package/src/state/local/indexed-db.ts +204 -0
- package/src/state/local/memory.ts +126 -0
- package/src/state/remote/dev-http.ts +253 -0
- package/src/state/remote/index.ts +1 -0
- package/src/state/utils.ts +50 -0
- package/src/wallet.ts +390 -0
- package/test/constants.ts +15 -0
- package/test/session-manager.test.ts +451 -0
- package/test/setup.ts +63 -0
- package/test/wallet.test.ts +90 -0
- package/tsconfig.json +10 -0
- package/vitest.config.ts +9 -0
package/src/wallet.ts
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Config,
|
|
3
|
+
Constants,
|
|
4
|
+
Context,
|
|
5
|
+
Erc6492,
|
|
6
|
+
Payload,
|
|
7
|
+
Address as SequenceAddress,
|
|
8
|
+
Signature as SequenceSignature,
|
|
9
|
+
} from '@0xsequence/wallet-primitives'
|
|
10
|
+
import { AbiFunction, Address, Bytes, Hex, Provider, TypedData } from 'ox'
|
|
11
|
+
import * as Envelope from './envelope.js'
|
|
12
|
+
import * as State from './state/index.js'
|
|
13
|
+
|
|
14
|
+
export type WalletOptions = {
|
|
15
|
+
context: Context.Context
|
|
16
|
+
stateProvider: State.Provider
|
|
17
|
+
guest: Address.Address
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const DefaultWalletOptions: WalletOptions = {
|
|
21
|
+
context: Context.Dev1,
|
|
22
|
+
stateProvider: new State.Local.Provider(),
|
|
23
|
+
guest: Constants.DefaultGuest,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type WalletStatus = {
|
|
27
|
+
address: Address.Address
|
|
28
|
+
isDeployed: boolean
|
|
29
|
+
implementation?: Address.Address
|
|
30
|
+
stage?: 'stage1' | 'stage2'
|
|
31
|
+
configuration: Config.Config
|
|
32
|
+
imageHash: Hex.Hex
|
|
33
|
+
/** Pending updates in reverse chronological order (newest first) */
|
|
34
|
+
pendingUpdates: Array<{ imageHash: Hex.Hex; signature: SequenceSignature.RawSignature }>
|
|
35
|
+
chainId?: bigint
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type WalletStatusWithOnchain = WalletStatus & {
|
|
39
|
+
onChainImageHash: Hex.Hex
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class Wallet {
|
|
43
|
+
public readonly context: Context.Context
|
|
44
|
+
public readonly guest: Address.Address
|
|
45
|
+
public readonly stateProvider: State.Provider
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
readonly address: Address.Address,
|
|
49
|
+
options?: Partial<WalletOptions>,
|
|
50
|
+
) {
|
|
51
|
+
const combinedOptions = { ...DefaultWalletOptions, ...options }
|
|
52
|
+
this.context = combinedOptions.context
|
|
53
|
+
this.guest = combinedOptions.guest
|
|
54
|
+
this.stateProvider = combinedOptions.stateProvider
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static async fromConfiguration(configuration: Config.Config, options?: Partial<WalletOptions>): Promise<Wallet> {
|
|
58
|
+
const merged = { ...DefaultWalletOptions, ...options }
|
|
59
|
+
//FIXME Validate configuration (weights not too large, total weights above threshold, etc)
|
|
60
|
+
await merged.stateProvider.saveWallet(configuration, merged.context)
|
|
61
|
+
return new Wallet(SequenceAddress.from(configuration, merged.context), merged)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async isDeployed(provider: Provider.Provider): Promise<boolean> {
|
|
65
|
+
return (await provider.request({ method: 'eth_getCode', params: [this.address, 'pending'] })) !== '0x'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async buildDeployTransaction(): Promise<{ to: Address.Address; data: Hex.Hex }> {
|
|
69
|
+
const deployInformation = await this.stateProvider.getDeploy(this.address)
|
|
70
|
+
if (!deployInformation) {
|
|
71
|
+
throw new Error(`cannot find deploy information for ${this.address}`)
|
|
72
|
+
}
|
|
73
|
+
return Erc6492.deploy(deployInformation.imageHash, deployInformation.context)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async prepareUpdate(configuration: Config.Config): Promise<Envelope.Envelope<Payload.ConfigUpdate>> {
|
|
77
|
+
const imageHash = Config.hashConfiguration(configuration)
|
|
78
|
+
const blankEvelope = (
|
|
79
|
+
await Promise.all([
|
|
80
|
+
this.prepareBlankEnvelope(0n),
|
|
81
|
+
// TODO: Add save configuration
|
|
82
|
+
this.stateProvider.saveWallet(configuration, this.context),
|
|
83
|
+
])
|
|
84
|
+
)[0]
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
...blankEvelope,
|
|
88
|
+
payload: Payload.fromConfigUpdate(Bytes.toHex(imageHash)),
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async submitUpdate(
|
|
93
|
+
envelope: Envelope.Signed<Payload.ConfigUpdate>,
|
|
94
|
+
options?: { validateSave?: boolean },
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
const [status, newConfig] = await Promise.all([
|
|
97
|
+
this.getStatus(),
|
|
98
|
+
this.stateProvider.getConfiguration(envelope.payload.imageHash),
|
|
99
|
+
])
|
|
100
|
+
|
|
101
|
+
if (!newConfig) {
|
|
102
|
+
throw new Error(`cannot find configuration details for ${envelope.payload.imageHash}`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Verify the new configuration is valid
|
|
106
|
+
const updatedEnvelope = { ...envelope, configuration: status.configuration }
|
|
107
|
+
const { weight, threshold } = Envelope.weightOf(updatedEnvelope)
|
|
108
|
+
if (weight < threshold) {
|
|
109
|
+
throw new Error('insufficient weight in envelope')
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const signature = Envelope.encodeSignature(updatedEnvelope)
|
|
113
|
+
await this.stateProvider.saveUpdate(this.address, newConfig, signature)
|
|
114
|
+
|
|
115
|
+
if (options?.validateSave) {
|
|
116
|
+
const status = await this.getStatus()
|
|
117
|
+
if (Hex.from(Config.hashConfiguration(status.configuration)) !== envelope.payload.imageHash) {
|
|
118
|
+
throw new Error('configuration not saved')
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async getStatus<T extends Provider.Provider | undefined = undefined>(
|
|
123
|
+
provider?: T,
|
|
124
|
+
): Promise<T extends Provider.Provider ? WalletStatusWithOnchain : WalletStatus> {
|
|
125
|
+
let isDeployed = false
|
|
126
|
+
let implementation: Address.Address | undefined
|
|
127
|
+
let stage: 'stage1' | 'stage2' | undefined
|
|
128
|
+
let chainId: bigint | undefined
|
|
129
|
+
let imageHash: Hex.Hex
|
|
130
|
+
let updates: Array<{ imageHash: Hex.Hex; signature: SequenceSignature.RawSignature }> = []
|
|
131
|
+
let onChainImageHash: Hex.Hex | undefined
|
|
132
|
+
|
|
133
|
+
if (provider) {
|
|
134
|
+
// Get chain ID, deployment status, and implementation
|
|
135
|
+
const requests = await Promise.all([
|
|
136
|
+
provider.request({ method: 'eth_chainId' }),
|
|
137
|
+
this.isDeployed(provider),
|
|
138
|
+
provider
|
|
139
|
+
.request({
|
|
140
|
+
method: 'eth_call',
|
|
141
|
+
params: [{ to: this.address, data: AbiFunction.encodeData(Constants.GET_IMPLEMENTATION) }],
|
|
142
|
+
})
|
|
143
|
+
.then((res) => {
|
|
144
|
+
const address = `0x${res.slice(-40)}`
|
|
145
|
+
Address.assert(address, { strict: false })
|
|
146
|
+
return address
|
|
147
|
+
})
|
|
148
|
+
.catch(() => undefined),
|
|
149
|
+
])
|
|
150
|
+
|
|
151
|
+
chainId = BigInt(requests[0])
|
|
152
|
+
isDeployed = requests[1]
|
|
153
|
+
implementation = requests[2]
|
|
154
|
+
|
|
155
|
+
// Determine stage based on implementation address
|
|
156
|
+
if (implementation) {
|
|
157
|
+
if (Address.isEqual(implementation, this.context.stage1)) {
|
|
158
|
+
stage = 'stage1'
|
|
159
|
+
} else if (Address.isEqual(implementation, this.context.stage2)) {
|
|
160
|
+
stage = 'stage2'
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Get image hash and updates
|
|
165
|
+
if (isDeployed && stage === 'stage2') {
|
|
166
|
+
// For deployed stage2 wallets, get the image hash from the contract
|
|
167
|
+
onChainImageHash = await provider.request({
|
|
168
|
+
method: 'eth_call',
|
|
169
|
+
params: [{ to: this.address, data: AbiFunction.encodeData(Constants.IMAGE_HASH) }],
|
|
170
|
+
})
|
|
171
|
+
} else {
|
|
172
|
+
// For non-deployed or stage1 wallets, get the deploy hash
|
|
173
|
+
const deployInformation = await this.stateProvider.getDeploy(this.address)
|
|
174
|
+
if (!deployInformation) {
|
|
175
|
+
throw new Error(`cannot find deploy information for ${this.address}`)
|
|
176
|
+
}
|
|
177
|
+
onChainImageHash = deployInformation.imageHash
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Get configuration updates
|
|
181
|
+
updates = await this.stateProvider.getConfigurationUpdates(this.address, onChainImageHash)
|
|
182
|
+
imageHash = updates[updates.length - 1]?.imageHash ?? onChainImageHash
|
|
183
|
+
} else {
|
|
184
|
+
// Without a provider, we can only get information from the state provider
|
|
185
|
+
const deployInformation = await this.stateProvider.getDeploy(this.address)
|
|
186
|
+
if (!deployInformation) {
|
|
187
|
+
throw new Error(`cannot find deploy information for ${this.address}`)
|
|
188
|
+
}
|
|
189
|
+
updates = await this.stateProvider.getConfigurationUpdates(this.address, deployInformation.imageHash)
|
|
190
|
+
imageHash = updates[updates.length - 1]?.imageHash ?? deployInformation.imageHash
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Get the current configuration
|
|
194
|
+
const configuration = await this.stateProvider.getConfiguration(imageHash)
|
|
195
|
+
if (!configuration) {
|
|
196
|
+
throw new Error(`cannot find configuration details for ${this.address}`)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (provider) {
|
|
200
|
+
return {
|
|
201
|
+
address: this.address,
|
|
202
|
+
isDeployed,
|
|
203
|
+
implementation,
|
|
204
|
+
stage,
|
|
205
|
+
configuration,
|
|
206
|
+
imageHash,
|
|
207
|
+
pendingUpdates: [...updates].reverse(),
|
|
208
|
+
chainId,
|
|
209
|
+
onChainImageHash: onChainImageHash!,
|
|
210
|
+
} as T extends Provider.Provider ? WalletStatusWithOnchain : WalletStatus
|
|
211
|
+
} else {
|
|
212
|
+
return {
|
|
213
|
+
address: this.address,
|
|
214
|
+
isDeployed,
|
|
215
|
+
implementation,
|
|
216
|
+
stage,
|
|
217
|
+
configuration,
|
|
218
|
+
imageHash,
|
|
219
|
+
pendingUpdates: [...updates].reverse(),
|
|
220
|
+
chainId,
|
|
221
|
+
} as T extends Provider.Provider ? WalletStatusWithOnchain : WalletStatus
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async getNonce(provider: Provider.Provider, space: bigint): Promise<bigint> {
|
|
226
|
+
const result = await provider.request({
|
|
227
|
+
method: 'eth_call',
|
|
228
|
+
params: [{ to: this.address, data: AbiFunction.encodeData(Constants.READ_NONCE, [space]) }],
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
if (result === '0x' || result.length === 0) {
|
|
232
|
+
return 0n
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return BigInt(result)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async prepareTransaction(
|
|
239
|
+
provider: Provider.Provider,
|
|
240
|
+
calls: Payload.Call[],
|
|
241
|
+
options?: { space?: bigint; noConfigUpdate?: boolean },
|
|
242
|
+
): Promise<Envelope.Envelope<Payload.Calls>> {
|
|
243
|
+
const space = options?.space ?? 0n
|
|
244
|
+
|
|
245
|
+
const [chainId, nonce] = await Promise.all([
|
|
246
|
+
provider.request({ method: 'eth_chainId' }),
|
|
247
|
+
this.getNonce(provider, space),
|
|
248
|
+
])
|
|
249
|
+
|
|
250
|
+
// If the latest configuration does not match the onchain configuration
|
|
251
|
+
// then we bundle the update into the transaction envelope
|
|
252
|
+
if (!options?.noConfigUpdate) {
|
|
253
|
+
const status = await this.getStatus(provider)
|
|
254
|
+
if (status.imageHash !== status.onChainImageHash) {
|
|
255
|
+
calls.push({
|
|
256
|
+
to: this.address,
|
|
257
|
+
value: 0n,
|
|
258
|
+
data: AbiFunction.encodeData(Constants.UPDATE_IMAGE_HASH, [status.imageHash]),
|
|
259
|
+
gasLimit: 0n,
|
|
260
|
+
delegateCall: false,
|
|
261
|
+
onlyFallback: false,
|
|
262
|
+
behaviorOnError: 'revert',
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
payload: {
|
|
269
|
+
type: 'call',
|
|
270
|
+
space,
|
|
271
|
+
nonce,
|
|
272
|
+
calls,
|
|
273
|
+
},
|
|
274
|
+
...(await this.prepareBlankEnvelope(BigInt(chainId))),
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async buildTransaction(provider: Provider.Provider, envelope: Envelope.Signed<Payload.Calls>) {
|
|
279
|
+
const status = await this.getStatus(provider)
|
|
280
|
+
|
|
281
|
+
const updatedEnvelope = { ...envelope, configuration: status.configuration }
|
|
282
|
+
const { weight, threshold } = Envelope.weightOf(updatedEnvelope)
|
|
283
|
+
if (weight < threshold) {
|
|
284
|
+
throw new Error('insufficient weight in envelope')
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const signature = Envelope.encodeSignature(updatedEnvelope)
|
|
288
|
+
|
|
289
|
+
if (status.isDeployed) {
|
|
290
|
+
return {
|
|
291
|
+
to: this.address,
|
|
292
|
+
data: AbiFunction.encodeData(Constants.EXECUTE, [
|
|
293
|
+
Bytes.toHex(Payload.encode(envelope.payload)),
|
|
294
|
+
Bytes.toHex(
|
|
295
|
+
SequenceSignature.encodeSignature({
|
|
296
|
+
...signature,
|
|
297
|
+
suffix: status.pendingUpdates.map(({ signature }) => signature),
|
|
298
|
+
}),
|
|
299
|
+
),
|
|
300
|
+
]),
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
const deploy = await this.buildDeployTransaction()
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
to: this.guest,
|
|
307
|
+
data: Bytes.toHex(
|
|
308
|
+
Payload.encode({
|
|
309
|
+
type: 'call',
|
|
310
|
+
space: 0n,
|
|
311
|
+
nonce: 0n,
|
|
312
|
+
calls: [
|
|
313
|
+
{
|
|
314
|
+
to: deploy.to,
|
|
315
|
+
value: 0n,
|
|
316
|
+
data: deploy.data,
|
|
317
|
+
gasLimit: 0n,
|
|
318
|
+
delegateCall: false,
|
|
319
|
+
onlyFallback: false,
|
|
320
|
+
behaviorOnError: 'revert',
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
to: this.address,
|
|
324
|
+
value: 0n,
|
|
325
|
+
data: AbiFunction.encodeData(Constants.EXECUTE, [
|
|
326
|
+
Bytes.toHex(Payload.encode(envelope.payload)),
|
|
327
|
+
Bytes.toHex(
|
|
328
|
+
SequenceSignature.encodeSignature({
|
|
329
|
+
...signature,
|
|
330
|
+
suffix: status.pendingUpdates.map(({ signature }) => signature),
|
|
331
|
+
}),
|
|
332
|
+
),
|
|
333
|
+
]),
|
|
334
|
+
gasLimit: 0n,
|
|
335
|
+
delegateCall: false,
|
|
336
|
+
onlyFallback: false,
|
|
337
|
+
behaviorOnError: 'revert',
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
}),
|
|
341
|
+
),
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async prepareMessageSignature(
|
|
347
|
+
message: string | Hex.Hex | Payload.TypedDataToSign,
|
|
348
|
+
chainId: bigint,
|
|
349
|
+
): Promise<Envelope.Envelope<Payload.Message>> {
|
|
350
|
+
let encodedMessage: Hex.Hex
|
|
351
|
+
if (typeof message !== 'string') {
|
|
352
|
+
encodedMessage = TypedData.encode(message)
|
|
353
|
+
} else {
|
|
354
|
+
let hexMessage = Hex.validate(message) ? message : Hex.fromString(message)
|
|
355
|
+
const messageSize = Hex.size(hexMessage)
|
|
356
|
+
encodedMessage = Hex.concat(Hex.fromString(`${`\x19Ethereum Signed Message:\n${messageSize}`}`), hexMessage)
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
...(await this.prepareBlankEnvelope(chainId)),
|
|
360
|
+
payload: Payload.fromMessage(encodedMessage),
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async buildMessageSignature(
|
|
365
|
+
envelope: Envelope.Signed<Payload.Message>,
|
|
366
|
+
provider?: Provider.Provider,
|
|
367
|
+
): Promise<Bytes.Bytes> {
|
|
368
|
+
const status = await this.getStatus(provider)
|
|
369
|
+
const signature = Envelope.encodeSignature(envelope)
|
|
370
|
+
if (!status.isDeployed) {
|
|
371
|
+
const deployTransaction = await this.buildDeployTransaction()
|
|
372
|
+
signature.erc6492 = { to: deployTransaction.to, data: Bytes.fromHex(deployTransaction.data) }
|
|
373
|
+
}
|
|
374
|
+
const encoded = SequenceSignature.encodeSignature({
|
|
375
|
+
...signature,
|
|
376
|
+
suffix: status.pendingUpdates.map(({ signature }) => signature),
|
|
377
|
+
})
|
|
378
|
+
return encoded
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
private async prepareBlankEnvelope(chainId: bigint) {
|
|
382
|
+
const status = await this.getStatus()
|
|
383
|
+
|
|
384
|
+
return {
|
|
385
|
+
wallet: this.address,
|
|
386
|
+
chainId: chainId,
|
|
387
|
+
configuration: status.configuration,
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { config as dotenvConfig } from 'dotenv'
|
|
2
|
+
import { Abi, AbiEvent, Address } from 'ox'
|
|
3
|
+
|
|
4
|
+
const envFile = process.env.CI ? '.env.test' : '.env.test.local'
|
|
5
|
+
dotenvConfig({ path: envFile })
|
|
6
|
+
|
|
7
|
+
export const EMITTER_ADDRESS: Address.Address = '0x7F6e420Ed3017A36bE6e1DA8e3AFE61569eb4840'
|
|
8
|
+
export const EMITTER_FUNCTIONS = Abi.from(['function explicitEmit()', 'function implicitEmit()'])
|
|
9
|
+
export const EMITTER_EVENT_TOPICS = [
|
|
10
|
+
AbiEvent.encode(AbiEvent.from('event Explicit(address sender)')).topics[0],
|
|
11
|
+
AbiEvent.encode(AbiEvent.from('event Implicit(address sender)')).topics[0],
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
// Environment variables
|
|
15
|
+
export const LOCAL_RPC_URL = process.env.LOCAL_RPC_URL || 'http://localhost:8545'
|