Skip to content

Recovery extension #735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/wallet/core/src/state/cached.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,28 @@ export class Cached implements Provider {
saveDeploy(imageHash: Hex.Hex, context: Context.Context): MaybePromise<void> {
return this.args.source.saveDeploy(imageHash, context)
}

async getPayload(opHash: Hex.Hex): Promise<
| {
chainId: bigint
payload: Payload.Parented
wallet: Address.Address
}
| undefined
> {
const cached = await this.args.cache.getPayload(opHash)
if (cached) {
return cached
}

const source = await this.args.source.getPayload(opHash)
if (source) {
await this.args.cache.savePayload(source.wallet, source.payload, source.chainId)
}
return source
}

savePayload(wallet: Address.Address, payload: Payload.Parented, chainId: bigint): MaybePromise<void> {
return this.args.source.savePayload(wallet, payload, chainId)
}
}
4 changes: 4 additions & 0 deletions packages/wallet/core/src/state/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export interface Reader {
): MaybePromise<Array<{ imageHash: Hex.Hex; signature: Signature.RawSignature }>>

getTree(rootHash: Hex.Hex): MaybePromise<GenericTree.Tree | undefined>
getPayload(
opHash: Hex.Hex,
): MaybePromise<{ chainId: bigint; payload: Payload.Parented; wallet: Address.Address } | undefined>
}

export interface Writer {
Expand All @@ -71,6 +74,7 @@ export interface Writer {

saveConfiguration(config: Config.Config): MaybePromise<void>
saveDeploy(imageHash: Hex.Hex, context: Context.Context): MaybePromise<void>
savePayload(wallet: Address.Address, payload: Payload.Parented, chainId: bigint): MaybePromise<void>
}

export type MaybePromise<T> = T | Promise<T>
Expand Down
12 changes: 12 additions & 0 deletions packages/wallet/core/src/state/local/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,18 @@ export class Provider implements ProviderInterface {
context,
)
}

async getPayload(
opHash: Hex.Hex,
): Promise<{ chainId: bigint; payload: Payload.Parented; wallet: Address.Address } | undefined> {
const data = await this.store.loadPayloadOfSubdigest(opHash)
return data ? { chainId: data.chainId, payload: data.content, wallet: data.wallet } : undefined
}

savePayload(wallet: Address.Address, payload: Payload.Parented, chainId: bigint): Promise<void> {
const subdigest = Hex.fromBytes(Payload.hash(wallet, chainId, payload))
return this.store.savePayloadOfSubdigest(subdigest, { content: payload, chainId, wallet })
}
}

export * from './memory.js'
Expand Down
22 changes: 22 additions & 0 deletions packages/wallet/core/src/state/remote/dev-http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,26 @@ export class DevHttpProvider implements Provider {
saveDeploy(imageHash: Hex.Hex, context: Context.Context): Promise<void> {
return this.request<void>('POST', '/deploy', { imageHash, context })
}

async getPayload(opHash: Hex.Hex): Promise<
| {
chainId: bigint
payload: Payload.Parented
wallet: Address.Address
}
| undefined
> {
return this.request<
| {
chainId: bigint
payload: Payload.Parented
wallet: Address.Address
}
| undefined
>('GET', `/payload/${opHash}`)
}

async savePayload(wallet: Address.Address, payload: Payload.Parented, chainId: bigint): Promise<void> {
return this.request<void>('POST', '/payload', { wallet, payload, chainId })
}
}
100 changes: 5 additions & 95 deletions packages/wallet/primitives-cli/src/subcommands/payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,6 @@ import type { CommandModule } from 'yargs'
import { Payload } from '@0xsequence/wallet-primitives'
import { fromPosOrStdin } from '../utils.js'

export const KIND_TRANSACTIONS = 0x00
const KIND_MESSAGE = 0x01
const KIND_CONFIG_UPDATE = 0x02
const KIND_DIGEST = 0x03

const BEHAVIOR_IGNORE_ERROR = 0x00
const BEHAVIOR_REVERT_ON_ERROR = 0x01
const BEHAVIOR_ABORT_ON_ERROR = 0x02

const CallAbi = [
{ type: 'address', name: 'to' },
{ type: 'uint256', name: 'value' },
Expand All @@ -38,98 +29,17 @@ export const DecodedAbi = [
{ type: 'address[]', name: 'parentWallets' },
]

export interface SolidityDecoded {
kind: number
noChainId: boolean
calls: SolidityCall[]
space: bigint
nonce: bigint
message: string
imageHash: string
digest: string
parentWallets: string[]
}

interface SolidityCall {
to: string
value: bigint
data: string
gasLimit: bigint
delegateCall: boolean
onlyFallback: boolean
behaviorOnError: bigint
}

function behaviorOnError(behavior: number): 'ignore' | 'revert' | 'abort' {
switch (behavior) {
case BEHAVIOR_IGNORE_ERROR:
return 'ignore'
case BEHAVIOR_REVERT_ON_ERROR:
return 'revert'
case BEHAVIOR_ABORT_ON_ERROR:
return 'abort'
default:
throw new Error(`Unknown behavior: ${behavior}`)
}
}

export async function doConvertToAbi(_payload: string): Promise<string> {
// Not implemented yet, but following the pattern
throw new Error('Not implemented')
}

export function solidityEncodedToParentedPayload(decoded: SolidityDecoded): Payload.Parented {
if (decoded.kind === KIND_TRANSACTIONS) {
return {
type: 'call',
nonce: decoded.nonce,
space: decoded.space,
calls: decoded.calls.map((call) => ({
to: Address.from(call.to),
value: call.value,
data: call.data as `0x${string}`,
gasLimit: call.gasLimit,
delegateCall: call.delegateCall,
onlyFallback: call.onlyFallback,
behaviorOnError: behaviorOnError(Number(call.behaviorOnError)),
})),
parentWallets: decoded.parentWallets.map((wallet) => Address.from(wallet)),
}
}

if (decoded.kind === KIND_MESSAGE) {
return {
type: 'message',
message: decoded.message as `0x${string}`,
parentWallets: decoded.parentWallets.map((wallet) => Address.from(wallet)),
}
}

if (decoded.kind === KIND_CONFIG_UPDATE) {
return {
type: 'config-update',
imageHash: decoded.imageHash as `0x${string}`,
parentWallets: decoded.parentWallets.map((wallet) => Address.from(wallet)),
}
}

if (decoded.kind === KIND_DIGEST) {
return {
type: 'digest',
digest: decoded.digest as `0x${string}`,
parentWallets: decoded.parentWallets.map((wallet) => Address.from(wallet)),
}
}

throw new Error('Not implemented')
}

export async function doConvertToPacked(payload: string, wallet?: string): Promise<string> {
const decodedPayload = solidityEncodedToParentedPayload(
const decodedPayload = Payload.fromAbiFormat(
AbiParameters.decode(
[{ type: 'tuple', name: 'payload', components: DecodedAbi }],
payload as Hex.Hex,
)[0] as unknown as SolidityDecoded,
)[0] as unknown as Payload.SolidityDecoded,
)

if (Payload.isCalls(decodedPayload)) {
Expand All @@ -144,7 +54,7 @@ export async function doConvertToJson(payload: string): Promise<string> {
const decoded = AbiParameters.decode(
[{ type: 'tuple', name: 'payload', components: DecodedAbi }],
payload as Hex.Hex,
)[0] as unknown as SolidityDecoded
)[0] as unknown as Payload.SolidityDecoded

const json = JSON.stringify(decoded)
return json
Expand All @@ -154,9 +64,9 @@ export async function doHash(wallet: string, chainId: bigint, payload: string):
const decoded = AbiParameters.decode(
[{ type: 'tuple', name: 'payload', components: DecodedAbi }],
payload as Hex.Hex,
)[0] as unknown as SolidityDecoded
)[0] as unknown as Payload.SolidityDecoded

return Hex.from(Payload.hash(Address.from(wallet), chainId, solidityEncodedToParentedPayload(decoded)))
return Hex.from(Payload.hash(Address.from(wallet), chainId, Payload.fromAbiFormat(decoded)))
}

const payloadCommand: CommandModule = {
Expand Down
4 changes: 2 additions & 2 deletions packages/wallet/primitives/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@ export function findSignerLeaf(
}

export function getWeight(
topology: RawTopology | RawConfig,
topology: RawTopology | RawConfig | Config,
canSign: (signer: SignerLeaf | SapientSignerLeaf) => boolean,
): { weight: bigint; maxWeight: bigint } {
topology = isRawConfig(topology) ? topology.topology : topology
topology = isRawConfig(topology) || isConfig(topology) ? topology.topology : topology

if (isSignedSignerLeaf(topology)) {
return { weight: topology.weight, maxWeight: topology.weight }
Expand Down
2 changes: 2 additions & 0 deletions packages/wallet/primitives/src/extensions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { Address } from 'ox'

export type Extensions = {
passkeys: Address.Address
recovery: Address.Address
}

export const Dev1: Extensions = {
passkeys: '0x8f26281dB84C18aAeEa8a53F94c835393229d296',
recovery: '0xd98da48C4FF9c19742eA5856A277424557C863a6',
}

export * as Passkeys from './passkeys.js'
Expand Down
Loading
Loading