Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ test('Bob redeems the delegation in order to call increment() on the counter con
expect(targetAddressBalance).toEqual(10n);
});

test('Bob redeems the delegation, and deploys Alices smart account via accountMetadata', async () => {
test('Bob redeems the delegation, and deploys Alices smart account via dependencies', async () => {
await fundAddress(bobSmartAccount.address);

const counterContract = getContract({
Expand Down Expand Up @@ -236,7 +236,7 @@ test('Bob redeems the delegation, and deploys Alices smart account via accountMe
expect(countAfter).toEqual(1n);
});

test('Bob redeems the delegation, with account metadata, even though Alices account is already deployed', async () => {
test('Bob redeems the delegation, with dependencies, even though Alices account is already deployed', async () => {
await fundAddress(bobSmartAccount.address);

const counterContract = getContract({
Expand Down Expand Up @@ -287,7 +287,7 @@ test('Bob redeems the delegation, with account metadata, even though Alices acco
expect(countAfter).toEqual(1n);
});

test('Bob calls sendUserOperationWithDelegation with the same accountMetadata multiple times', async () => {
test('Bob calls sendUserOperationWithDelegation with the same dependencies multiple times', async () => {
await fundAddress(bobSmartAccount.address);

const { factory, factoryData } = await aliceSmartAccount.getFactoryArgs();
Expand All @@ -305,7 +305,7 @@ test('Bob calls sendUserOperationWithDelegation with the same accountMetadata mu
},
],
...gasPrice,
accountMetadata: [
dependencies: [
{ factory, factoryData },
{ factory, factoryData },
],
Expand All @@ -331,7 +331,7 @@ test('Bob calls sendUserOperationWithDelegation with the same accountMetadata mu
expect(aliceSmartAccountBalance).toEqual(10n);
});

// callData is disallowed, because if we attempt to re-encode with additional calls (ie accountMetadata)
// callData is disallowed, because if we attempt to re-encode with additional calls (ie dependencies)
// the inner call will be targetting a function on the smart account, which is likely attributed with
// OnlyEntryPoint. Because it's calling from the smart account, it will fail.
test.skip('Bob attempts to call sendUserOperationWithDelegation with callData specified', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export type SendUserOperationWithDelegationParameters<
TAccount extends SmartAccount | undefined = SmartAccount | undefined,
TAccountOverride extends SmartAccount | undefined = SmartAccount | undefined,
> = SendUserOperationParameters<TAccount, TAccountOverride, DelegatedCall[]> & {
accountMetadata?: { factory: Hex; factoryData: Hex }[];
dependencies?: { factory: Hex; factoryData: Hex }[];
calls: DelegatedCall[];
publicClient: PublicClient<Transport, Chain>;
};
Expand Down Expand Up @@ -131,7 +131,7 @@ export type SendUserOperationWithDelegationParameters<
* delegationManager: '0x...',
* },
* ],
* accountMetadata: [{ factory: '0x...', factoryData: '0x...' }], // Optional: for deploying accounts
* dependencies: [{ factory: '0x...', factoryData: '0x...' }], // Optional: for deploying accounts
* })
*/
export async function sendUserOperationWithDelegationAction<
Expand All @@ -144,7 +144,7 @@ export async function sendUserOperationWithDelegationAction<
TAccountOverride
>,
) {
if (parameters.accountMetadata) {
if (parameters.dependencies) {
const { publicClient } = parameters;

const includedAccountKeys: Record<Hex, boolean> = {};
Expand All @@ -157,29 +157,24 @@ export async function sendUserOperationWithDelegationAction<

const { SimpleFactory } = getSmartAccountsEnvironment(chainId);

const uniqueAccountMetadatas = parameters.accountMetadata.filter(
(accountMetadata) => {
if (!isAddressEqual(accountMetadata.factory, SimpleFactory)) {
throw new Error(
`Invalid accountMetadata: ${accountMetadata.factory} is not allowed.`,
);
}

// ensure that factory calls are not duplicated
const accountKey = concat([
accountMetadata.factory,
accountMetadata.factoryData,
]);
const isDuplicate = includedAccountKeys[accountKey];

includedAccountKeys[accountKey] = true;
return !isDuplicate;
},
);
const uniqueDependencies = parameters.dependencies.filter((dependency) => {
if (!isAddressEqual(dependency.factory, SimpleFactory)) {
throw new Error(
`Invalid dependency: ${dependency.factory} is not allowed.`,
);
}

// ensure that factory calls are not duplicated
const accountKey = concat([dependency.factory, dependency.factoryData]);
const isDuplicate = includedAccountKeys[accountKey];

includedAccountKeys[accountKey] = true;
return !isDuplicate;
});

const factoryCalls = (
await Promise.all(
uniqueAccountMetadatas.map(async ({ factory, factoryData }) => {
uniqueDependencies.map(async ({ factory, factoryData }) => {
const isDeployed = await publicClient
.call({
to: factory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe('erc7710RedeemDelegationAction', () => {
);
});

it('should append factory calls when accountMetadata is provided', async () => {
it('should append factory calls when dependencies is provided', async () => {
const bundlerClient = createBundlerClient({
transport: custom({ request: mockBundlerRequest }),
chain,
Expand All @@ -115,7 +115,7 @@ describe('erc7710RedeemDelegationAction', () => {
},
];

const accountMetadata = [
const dependencies = [
{
factory: simpleFactoryAddress,
factoryData: randomBytes(128),
Expand All @@ -129,7 +129,7 @@ describe('erc7710RedeemDelegationAction', () => {
{
publicClient,
calls,
accountMetadata,
dependencies,
};

await extendedBundlerClient.sendUserOperationWithDelegation(
Expand All @@ -140,21 +140,21 @@ describe('erc7710RedeemDelegationAction', () => {
...sendUserOperationWithDelegationArgs,
calls: [
{
to: accountMetadata[0]?.factory,
data: accountMetadata[0]?.factoryData,
to: dependencies[0]?.factory,
data: dependencies[0]?.factoryData,
value: 0n,
},
{
to: accountMetadata[1]?.factory,
data: accountMetadata[1]?.factoryData,
to: dependencies[1]?.factory,
data: dependencies[1]?.factoryData,
value: 0n,
},
...calls,
],
});
});

it('should throw an error when SimpleFactory is provided as accountMetadata factory', async () => {
it('should throw an error when SimpleFactory is provided as dependencies factory', async () => {
const bundlerClient = createBundlerClient({
transport: custom({ request: mockBundlerRequest }),
chain,
Expand All @@ -170,7 +170,7 @@ describe('erc7710RedeemDelegationAction', () => {
},
];

const accountMetadata = [
const dependencies = [
{
factory: randomAddress(),
factoryData: randomBytes(128),
Expand All @@ -181,10 +181,10 @@ describe('erc7710RedeemDelegationAction', () => {
{
publicClient,
calls,
accountMetadata,
dependencies,
};

const factoryAddress = accountMetadata[0]?.factory;
const factoryAddress = dependencies[0]?.factory;

if (!factoryAddress) {
throw new Error('factoryAddress is not set');
Expand All @@ -195,7 +195,7 @@ describe('erc7710RedeemDelegationAction', () => {
sendUserOperationWithDelegationArgs,
),
).rejects.toThrow(
`Invalid accountMetadata: ${factoryAddress} is not allowed.`,
`Invalid dependency: ${factoryAddress} is not allowed.`,
);
});

Expand All @@ -217,7 +217,7 @@ describe('erc7710RedeemDelegationAction', () => {
},
];

const accountMetadata = [
const dependencies = [
{
factory: simpleFactoryAddress,
factoryData: randomBytes(128),
Expand All @@ -238,16 +238,16 @@ describe('erc7710RedeemDelegationAction', () => {
Chain
>,
calls,
accountMetadata,
dependencies,
};

await extendedBundlerClient.sendUserOperationWithDelegation(
sendUserOperationWithDelegationArgs,
);

expect(mockPublicClient.call.firstCall.args[0]).to.deep.equal({
to: accountMetadata[0]?.factory,
data: accountMetadata[0]?.factoryData,
to: dependencies[0]?.factory,
data: dependencies[0]?.factoryData,
});

expect(sendUserOperationStub.firstCall.args[0]).to.deep.equal({
Expand Down
Loading