Skip to content

Commit

Permalink
Fix biconomy account address (#299)
Browse files Browse the repository at this point in the history
* Fix biconomy account address

* fix build and add tests

* add more info

* fix test

* chore: format

* Add changeset

---------

Co-authored-by: plusminushalf <[email protected]>
  • Loading branch information
plusminushalf and plusminushalf authored Oct 9, 2024
1 parent 8a7b39b commit e8d4f35
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 36 deletions.
5 changes: 5 additions & 0 deletions .changeset/small-bears-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"permissionless": patch
---

Fix: Biconomy sender address calculation post deploy
Binary file modified bun.lockb
Binary file not shown.
8 changes: 1 addition & 7 deletions packages/permissionless-test/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,5 @@ export type AAParamType<entryPointVersion extends "0.6" | "0.7"> = {
anvilRpc: string
altoRpc: string
paymasterRpc: string
}

// param used when testing with a already deployed contract
export type ExistingSignerParamType = {
publicClient: PublicClient
privateKey: Hex
existingAddress: Address
privateKey?: Hex
}
30 changes: 18 additions & 12 deletions packages/permissionless-test/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ export const getSimpleAccountClient = async <
entryPointVersion extends "0.6" | "0.7"
>({
entryPoint,
anvilRpc
anvilRpc,
privateKey
}: AAParamType<entryPointVersion>): Promise<
ToSimpleSmartAccountReturnType<entryPointVersion>
> => {
Expand All @@ -223,7 +224,7 @@ export const getSimpleAccountClient = async <
? "0.6"
: "0.7") as entryPointVersion
},
owner: privateKeyToAccount(generatePrivateKey())
owner: privateKeyToAccount(privateKey ?? generatePrivateKey())
})
}

Expand All @@ -232,7 +233,8 @@ export const getLightAccountClient = async <
>({
entryPoint,
anvilRpc,
version
version,
privateKey
}: AAParamType<entryPointVersion> & {
version?: LightAccountVersion<entryPointVersion>
}) => {
Expand All @@ -246,19 +248,20 @@ export const getLightAccountClient = async <
},
client: getPublicClient(anvilRpc),
version: version ?? "1.1.0",
owner: privateKeyToAccount(generatePrivateKey())
owner: privateKeyToAccount(privateKey ?? generatePrivateKey())
})
}

// Only supports v0.6 for now
export const getTrustAccountClient = async <
entryPointVersion extends "0.6" | "0.7"
>({
anvilRpc
anvilRpc,
privateKey
}: AAParamType<entryPointVersion>) => {
return toTrustSmartAccount({
client: getPublicClient(anvilRpc),
owner: privateKeyToAccount(generatePrivateKey()),
owner: privateKeyToAccount(privateKey ?? generatePrivateKey()),
entryPoint: {
address: entryPoint06Address,
version: "0.6"
Expand All @@ -270,11 +273,12 @@ export const getTrustAccountClient = async <
export const getBiconomyClient = async <
entryPointVersion extends "0.6" | "0.7"
>({
anvilRpc
anvilRpc,
privateKey
}: AAParamType<entryPointVersion>) => {
return toBiconomySmartAccount({
client: getPublicClient(anvilRpc),
owners: [privateKeyToAccount(generatePrivateKey())],
owners: [privateKeyToAccount(privateKey ?? generatePrivateKey())],
entryPoint: {
address: entryPoint06Address,
version: "0.6"
Expand All @@ -287,7 +291,8 @@ export const getKernelEcdsaClient = async <
>({
entryPoint,
anvilRpc,
version
version,
privateKey
}: AAParamType<entryPointVersion> & {
version?: KernelVersion<entryPointVersion>
}) => {
Expand All @@ -309,15 +314,16 @@ export const getKernelEcdsaClient = async <
: entryPoint07Address,
version: entryPoint.version === "0.6" ? "0.6" : "0.7"
},
owners: [privateKeyToAccount(generatePrivateKey())],
owners: [privateKeyToAccount(privateKey ?? generatePrivateKey())],
version
})
}

export const getSafeClient = async <entryPointVersion extends "0.6" | "0.7">({
entryPoint,
anvilRpc,
erc7579
erc7579,
privateKey
}: {
erc7579?: boolean
} & AAParamType<entryPointVersion>) => {
Expand All @@ -332,7 +338,7 @@ export const getSafeClient = async <entryPointVersion extends "0.6" | "0.7">({
: entryPoint07Address,
version: entryPoint.version === "0.6" ? "0.6" : "0.7"
},
owners: [privateKeyToAccount(generatePrivateKey())],
owners: [privateKeyToAccount(privateKey ?? generatePrivateKey())],
version: "1.4.1",
saltNonce: 420n,
safe4337ModuleAddress: erc7579
Expand Down
101 changes: 85 additions & 16 deletions packages/permissionless/accounts/biconomy/toBiconomySmartAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import {
type LocalAccount,
encodeAbiParameters,
encodeFunctionData,
encodePacked,
getContractAddress,
hexToBigInt,
keccak256,
parseAbiParameters
} from "viem"
import {
Expand All @@ -27,10 +31,12 @@ import {
} from "viem/account-abstraction"
import { signMessage } from "viem/actions"
import { getAccountNonce } from "../../actions/public/getAccountNonce"
import { getSenderAddress } from "../../actions/public/getSenderAddress"
import { toOwner } from "../../utils/toOwner"
import { BiconomyAbi, FactoryAbi } from "./abi/BiconomySmartAccountAbi"

const BICONOMY_PROXY_CREATION_CODE =
"0x6080346100aa57601f61012038819003918201601f19168301916001600160401b038311848410176100af578084926020946040528339810103126100aa57516001600160a01b0381168082036100aa5715610065573055604051605a90816100c68239f35b60405162461bcd60e51b815260206004820152601e60248201527f496e76616c696420696d706c656d656e746174696f6e206164647265737300006044820152606490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060405230546000808092368280378136915af43d82803e156020573d90f35b3d90fdfea2646970667358221220a03b18dce0be0b4c9afe58a9eb85c35205e2cf087da098bbf1d23945bf89496064736f6c63430008110033"

/**
* The account creation ABI for Biconomy Smart Account (from the biconomy SmartAccountFactory)
*/
Expand All @@ -41,10 +47,15 @@ import { BiconomyAbi, FactoryAbi } from "./abi/BiconomySmartAccountAbi"
const BICONOMY_ADDRESSES: {
ECDSA_OWNERSHIP_REGISTRY_MODULE: Address
FACTORY_ADDRESS: Address
ACCOUNT_V2_0_LOGIC: Address
DEFAULT_FALLBACK_HANDLER_ADDRESS: Address
} = {
ECDSA_OWNERSHIP_REGISTRY_MODULE:
"0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e",
FACTORY_ADDRESS: "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5"
FACTORY_ADDRESS: "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5",
ACCOUNT_V2_0_LOGIC: "0x0000002512019Dafb59528B82CB92D3c5D2423aC",
DEFAULT_FALLBACK_HANDLER_ADDRESS:
"0x0bBa6d96BD616BedC6BFaa341742FD43c60b83C1"
}

/**
Expand Down Expand Up @@ -98,6 +109,8 @@ export type ToBiconomySmartAccountParameters = Prettify<{
index?: bigint
factoryAddress?: Address
ecdsaModuleAddress?: Address
accountLogicAddress?: Address
fallbackHandlerAddress?: Address
}>

export type BiconomySmartAccountImplementation = Assign<
Expand All @@ -109,6 +122,59 @@ export type ToBiconomySmartAccountReturnType = Prettify<
SmartAccount<BiconomySmartAccountImplementation>
>

const getAccountAddress = async ({
factoryAddress,
accountLogicAddress,
fallbackHandlerAddress,
ecdsaModuleAddress,
owner,
index = BigInt(0)
}: {
factoryAddress: Address
accountLogicAddress: Address
fallbackHandlerAddress: Address
ecdsaModuleAddress: Address
owner: Address
index?: bigint
}): Promise<Address> => {
// Build the module setup data
const ecdsaOwnershipInitData = encodeFunctionData({
abi: BiconomyAbi,
functionName: "initForSmartAccount",
args: [owner]
})

// Build account init code
const initialisationData = encodeFunctionData({
abi: BiconomyAbi,
functionName: "init",
args: [
fallbackHandlerAddress,
ecdsaModuleAddress,
ecdsaOwnershipInitData
]
})

const deploymentCode = encodePacked(
["bytes", "uint256"],
[BICONOMY_PROXY_CREATION_CODE, hexToBigInt(accountLogicAddress)]
)

const salt = keccak256(
encodePacked(
["bytes32", "uint256"],
[keccak256(encodePacked(["bytes"], [initialisationData])), index]
)
)

return getContractAddress({
from: factoryAddress,
salt,
bytecode: deploymentCode,
opcode: "CREATE2"
})
}

/**
* Build a Biconomy modular smart account from a private key, that use the ECDSA signer behind the scene
* @param client
Expand All @@ -122,7 +188,16 @@ export type ToBiconomySmartAccountReturnType = Prettify<
export async function toBiconomySmartAccount(
parameters: ToBiconomySmartAccountParameters
): Promise<ToBiconomySmartAccountReturnType> {
const { owners, client, index = 0n, address } = parameters
const {
owners,
client,
index = 0n,
address,
accountLogicAddress = BICONOMY_ADDRESSES.ACCOUNT_V2_0_LOGIC,
fallbackHandlerAddress = BICONOMY_ADDRESSES.DEFAULT_FALLBACK_HANDLER_ADDRESS,
ecdsaModuleAddress = BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE,
factoryAddress = BICONOMY_ADDRESSES.FACTORY_ADDRESS
} = parameters

const localOwner = await toOwner({ owner: owners[0] })

Expand All @@ -132,15 +207,8 @@ export async function toBiconomySmartAccount(
version: parameters.entryPoint?.version ?? "0.6"
}

const factoryAddress =
parameters.factoryAddress ?? BICONOMY_ADDRESSES.FACTORY_ADDRESS

let accountAddress: Address | undefined = address

const ecdsaModuleAddress =
parameters.ecdsaModuleAddress ??
BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE

const getFactoryArgs = async () => {
return {
factory: factoryAddress,
Expand All @@ -159,13 +227,14 @@ export async function toBiconomySmartAccount(
async getAddress() {
if (accountAddress) return accountAddress

const { factory, factoryData } = await getFactoryArgs()

// Get the sender address based on the init code
accountAddress = await getSenderAddress(client, {
factory,
factoryData,
entryPointAddress: entryPoint.address
accountAddress = await getAccountAddress({
owner: localOwner.address,
ecdsaModuleAddress,
factoryAddress,
accountLogicAddress,
fallbackHandlerAddress,
index
})

return accountAddress
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,6 @@ export type ToSafeSmartAccountParameters<
version: entryPointVersion
}
safe4337ModuleAddress?: Address
erc7569LaunchpadAddress?: Address
erc7579LaunchpadAddress?: TErc7579
safeProxyFactoryAddress?: Address
safeSingletonAddress?: Address
Expand Down
Loading

0 comments on commit e8d4f35

Please sign in to comment.