Skip to content

Commit

Permalink
refactor code
Browse files Browse the repository at this point in the history
  • Loading branch information
KannuSingh committed Jul 22, 2024
1 parent 81e7567 commit fdf50ab
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ import {
WalletGrantPermissionsReturnType,
encodeAbiParameters,
encodePacked,
keccak256,
serializeSignature
} from 'viem'
import { publicKeyToAddress, sign } from 'viem/accounts'
import {
MOCK_VALIDATOR_ADDRESS,
PERMISSION_VALIDATOR_ADDRESS,
SAFE7579_USER_OPERATION_BUILDER_ADDRESS,
WALLET_CONNECT_COSIGNER,
YESPOLICY
SAFE7579_USER_OPERATION_BUILDER_ADDRESS
} from '@/utils/permissionValidatorUtils/constants'
import { MultiKeySigner } from 'viem/_types/experimental/erc7715/types/signer'
import { KEY_TYPES, bigIntReplacer, decodeDIDToPublicKey } from '@/utils/HelperUtil'
import { isModuleInstalledAbi } from '@/utils/ERC7579AccountUtils'
import { parsePublicKey as parsePasskeyPublicKey } from 'webauthn-p256'
import { enableSessionAbi } from '@/utils/permissionValidatorUtils/abi'
import {
WebAuthnValidationDataAbi,
enableSessionAbi,
smartSessionAbi
} from '@/utils/permissionValidatorUtils/abi'
generateSignerId,
getDigest,
getEOAAndPasskeySignerInitData,
getPermissionContext,
perpareMockWCCosignerEnableSession
} from '@/utils/permissionValidatorUtils'

export class SafeSmartAccountLib extends SmartAccountLib {
protected ERC_7579_LAUNCHPAD_ADDRESS: Address = '0xEBe001b3D534B9B6E2500FB78E67a1A137f561CE'
Expand Down Expand Up @@ -124,11 +124,8 @@ export class SafeSmartAccountLib extends SmartAccountLib {
if (!requestedSigner || requestedSigner.type !== 'keys') {
throw new Error('Currently only supporting KeySigner and MultiKey Type for permissions')
}
const signerId = this.generatePermissionSignerId(grantPermissionsRequestParams)
console.log({ signerId })
const typeSigner = requestedSigner as MultiKeySigner
const publicKeys = typeSigner.data.ids.map(id => decodeDIDToPublicKey(id))
// const [eoaPublicKey, passkeyPublicKey] = publicKeys
let eoaPublicKey, passkeyPublicKey
publicKeys.forEach(key => {
if (key.keyType === KEY_TYPES.secp256k1) {
Expand All @@ -141,67 +138,24 @@ export class SafeSmartAccountLib extends SmartAccountLib {
if (!eoaPublicKey || !passkeyPublicKey) throw Error('Invalid EOA and passkey signers')
const targetEOAAddress = publicKeyToAddress(eoaPublicKey as `0x${string}`)
const parsedPasskeyPublicKey = parsePasskeyPublicKey(passkeyPublicKey as `0x${string}`)
const encodedSignersInitData = encodeAbiParameters(
[{ type: 'uint256' }, WebAuthnValidationDataAbi],
[
BigInt(targetEOAAddress),
{
pubKeyX: parsedPasskeyPublicKey.x,
pubKeyY: parsedPasskeyPublicKey.y
}
]
)

const userOpPolicies = [
{
initData: '0x' as `0x${string}`,
policy: YESPOLICY
}
]
const actionId = keccak256(signerId) // just a random id
const actions = [
{
actionId: actionId,
actionPolicies: userOpPolicies
}
]

const enableSessionParams = {
isigner: WALLET_CONNECT_COSIGNER as `0x${string}`,
actions: actions,
isignerInitData: encodedSignersInitData,
userOpPolicies: userOpPolicies,
erc1271Policies: [],
permissionEnableSig: '0x' as `0x${string}`
}
const enableSessionHash = await this.publicClient.readContract({
address: PERMISSION_VALIDATOR_ADDRESS,
abi: smartSessionAbi,
functionName: 'getDigest',
args: [signerId, this.client.account.address, enableSessionParams]
const encodedSignersInitData = getEOAAndPasskeySignerInitData(targetEOAAddress, {
pubKeyX: parsedPasskeyPublicKey.x,
pubKeyY: parsedPasskeyPublicKey.y
})
const enableSession = perpareMockWCCosignerEnableSession(encodedSignersInitData)
const signerId = generateSignerId(grantPermissionsRequestParams)
const enableSessionHash = await getDigest(this.publicClient, {
signerId,
accountAddress: this.client.account.address,
enableSession: enableSession
})

console.log({ digest: enableSessionHash })
const signature = await sign({
privateKey: this.getPrivateKey() as `0x${string}`,
hash: enableSessionHash
})
const enableSessionScopeSignature: Hex = serializeSignature(signature)

enableSessionParams.permissionEnableSig = encodePacked(
['address', 'bytes'],
[MOCK_VALIDATOR_ADDRESS, enableSessionScopeSignature] // TODO: MOCK_VALIDATOR_ADDRESS? defaultValidator?
)
const encodedEnableSessionData = encodeAbiParameters(enableSessionAbi, [enableSessionParams])
console.log({ encodedEnableSessionData })
// permissionContext = PermissionValidatorAddress [20bytes] + SignerId[bytes32] + EncodedEnableSessionData[bytes]
const permissionContext = encodePacked(
['address', 'bytes1', 'bytes32', 'bytes'],
[PERMISSION_VALIDATOR_ADDRESS, '0x02', signerId, encodedEnableSessionData]
)

const enableSessionSignature: Hex = serializeSignature(signature)
const permissionContext = getPermissionContext(signerId, enableSession, enableSessionSignature)
console.log({ permissionContext })

console.log('Granting permissions...')

return {
Expand All @@ -215,22 +169,6 @@ export class SafeSmartAccountLib extends SmartAccountLib {
}
}

private generatePermissionSignerId(
grantPermissionsRequestParams: WalletGrantPermissionsParameters
) {
const json = JSON.stringify(grantPermissionsRequestParams, (key, value) => {
// Remove undefined values
if (value === undefined) {
return null
}
return value
})
const jsonBytes = new TextEncoder().encode(json)
const hash = keccak256(jsonBytes)

return hash
}

private async ensureAccountDeployed(): Promise<void> {
if (!this.client?.account) {
throw new Error('Client not initialized')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ export const VALIDATOR_ADDRESS: Address = '0x503b54Ed1E62365F0c9e4caF1479623b08a
export const SECP256K1_SIGNATURE_VALIDATOR_ADDRESS: Address =
'0x033f60A1035E64c96FD511abA61bA8d9276ADB4f'
export const SAFE7579_USER_OPERATION_BUILDER_ADDRESS: Address =
'0xa6cdc0f868c5cd3dbf8cdb47a940fcb5de77e5e0'
'0xCd67aCD5d31969e2c368d6A1cfE1911932C744b1'
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
import { Address, Chain, Hex, encodePacked, keccak256 } from 'viem'
import {
Address,
Chain,
Hex,
PublicClient,
WalletGrantPermissionsParameters,
encodeAbiParameters,
encodePacked,
keccak256,
toBytes
} from 'viem'
import { GrantPermissionsParameters } from 'viem/experimental'
import {
MOCK_VALIDATOR_ADDRESS,
PERMISSION_VALIDATOR_ADDRESS,
WALLET_CONNECT_COSIGNER,
YESPOLICY
} from './constants'
import { enableSessionAbi, smartSessionAbi, WebAuthnValidationDataAbi } from './abi'

export type SingleSignerPermission = {
validUntil: number
Expand All @@ -23,6 +41,128 @@ export type PermissionContext = {
enableSig?: `0x${string}`
}

export type ActionPolicy = {
initData: `0x${string}`
policy: `0x${string}`
}
export type UserOpPolicy = {
initData: `0x${string}`
policy: `0x${string}`
}
export type ERC1271Policy = {
initData: `0x${string}`
policy: `0x${string}`
}
export type ActionId = `0x${string}`

export type Action = {
actionId: ActionId
actionPolicies: ActionPolicy[]
}

export type EnableSession = {
isigner: `0x${string}`
isignerInitData: `0x${string}`
actions: Action[]
userOpPolicies: UserOpPolicy[]
erc1271Policies: ERC1271Policy[]
permissionEnableSig: `0x${string}`
}
export type PasskeyPublicKey = {
pubKeyX: bigint
pubKeyY: bigint
}

export function perpareMockWCCosignerEnableSession(signersInitData: `0x${string}`): EnableSession {
const userOpPolicies: UserOpPolicy[] = [
{
initData: '0x' as `0x${string}`,
policy: YESPOLICY
}
]
const actionId = keccak256(toBytes('MockAction01')) // just a random id
const actions: Action[] = [
{
actionId: actionId,
actionPolicies: userOpPolicies
}
]

const enableSessionParams: EnableSession = {
isigner: WALLET_CONNECT_COSIGNER as `0x${string}`,
actions: actions,
isignerInitData: signersInitData,
userOpPolicies: userOpPolicies,
erc1271Policies: [],
permissionEnableSig: '0x' as `0x${string}`
}
return enableSessionParams
}

export function getEOAAndPasskeySignerInitData(
eoaAddress: Address,
{ pubKeyX, pubKeyY }: PasskeyPublicKey
): `0x${string}` {
return encodeAbiParameters(
[{ type: 'uint256' }, WebAuthnValidationDataAbi],
[
BigInt(eoaAddress),
{
pubKeyX,
pubKeyY
}
]
)
}

export function generateSignerId(grantPermissionsRequestParams: WalletGrantPermissionsParameters) {
const json = JSON.stringify(grantPermissionsRequestParams, (key, value) => {
// Remove undefined values
if (value === undefined) {
return null
}
return value
})
const jsonBytes = new TextEncoder().encode(json)
const hash = keccak256(jsonBytes)

return hash
}

export async function getDigest(
publicClient: PublicClient,
args: {
signerId: `0x${string}`
accountAddress: `0x${string}`
enableSession: EnableSession
}
): Promise<`0x${string}`> {
const { signerId, accountAddress, enableSession } = args
return await publicClient.readContract({
address: PERMISSION_VALIDATOR_ADDRESS,
abi: smartSessionAbi,
functionName: 'getDigest',
args: [signerId, accountAddress, enableSession]
})
}

export function getPermissionContext(
signerId: `0x${string}`,
enableSession: EnableSession,
enableSessionSignature: `0x${string}`
) {
enableSession.permissionEnableSig = encodePacked(
['address', 'bytes'],
[MOCK_VALIDATOR_ADDRESS, enableSessionSignature] // TODO: MOCK_VALIDATOR_ADDRESS? defaultValidator?
)
const encodedEnableSessionData = encodeAbiParameters(enableSessionAbi, [enableSession])

return encodePacked(
['address', 'bytes1', 'bytes32', 'bytes'],
[PERMISSION_VALIDATOR_ADDRESS, '0x02', signerId, encodedEnableSessionData]
)
}

export function getPermissionId(permission: SingleSignerPermission): `0x${string}` {
return keccak256(
encodePacked(
Expand Down

0 comments on commit fdf50ab

Please sign in to comment.