diff --git a/api/dbschema/bootstrap.md b/api/dbschema/bootstrap.md index 11723a9f8..e8b2384e5 100644 --- a/api/dbschema/bootstrap.md +++ b/api/dbschema/bootstrap.md @@ -9,7 +9,7 @@ configure instance set effective_io_concurrency := 1000; configure instance set query_work_mem := "8MiB"; # Memory available to cache data - 50% -configure instance set shared_buffers := "2GiB"; +configure instance set shared_buffers := "4GiB"; # Total memory available to the database for caching - 75% configure instance set effective_cache_size := "6GiB"; \ No newline at end of file diff --git a/api/dbschema/default.esdl b/api/dbschema/default.esdl index cc376d153..87c0057f9 100644 --- a/api/dbschema/default.esdl +++ b/api/dbschema/default.esdl @@ -7,7 +7,7 @@ module default { type Account extending Labelled { overloaded required address: UAddress { constraint exclusive; } required implementation: Address; - required salt: Bytes32; + required initialization: tuple; activationEthFee: decimal { constraint min_value(0); } upgradedAtBlock: bigint { constraint min_value(0); } photo: Url; diff --git a/api/dbschema/edgeql-js/__spec__.ts b/api/dbschema/edgeql-js/__spec__.ts index f7c481684..9b175210f 100644 --- a/api/dbschema/edgeql-js/__spec__.ts +++ b/api/dbschema/edgeql-js/__spec__.ts @@ -59,7 +59,7 @@ spec.set("00000000-0000-0000-0000-000000000130", {"id":"00000000-0000-0000-0000- spec.set("856590de-5dc9-11ef-8a73-398a066c2955", {"id":"856590de-5dc9-11ef-8a73-398a066c2955","name":"default::AbiSource","is_abstract":false,"kind":"scalar","enum_values":["Verified"],"is_seq":false,"material_id":null,"bases":[{"id":"48896eaf-b8af-5f80-9073-0884475d6ee5"}],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[],"range_element_id":null,"multirange_element_id":null} as any); spec.set("8ce8c71e-e4fa-5f73-840c-22d7eaa58588", {"id":"8ce8c71e-e4fa-5f73-840c-22d7eaa58588","name":"std::Object","is_abstract":true,"kind":"object","enum_values":null,"is_seq":false,"material_id":null,"bases":[{"id":"0d14e49f-d9f9-51f0-b8f4-c432982cbac2"}],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[],"range_element_id":null,"multirange_element_id":null} as any); spec.set("7cfa189d-5dc9-11ef-973a-278bac96429c", {"id":"7cfa189d-5dc9-11ef-973a-278bac96429c","name":"default::Labelled","is_abstract":true,"kind":"object","enum_values":null,"is_seq":false,"material_id":null,"bases":[{"id":"8ce8c71e-e4fa-5f73-840c-22d7eaa58588"}],"union_of":[],"intersection_of":[],"pointers":[{"card":"One","name":"address","target_id":"7cf2ae3c-5dc9-11ef-abc3-3fb8f98ac630","kind":"property","is_exclusive":false,"is_computed":false,"is_readonly":false,"has_default":false,"pointers":[]},{"card":"One","name":"chain","target_id":"00000000-0000-0000-0000-000000000101","kind":"property","is_exclusive":false,"is_computed":true,"is_readonly":false,"has_default":false,"pointers":[]},{"card":"One","name":"name","target_id":"00000000-0000-0000-0000-000000000101","kind":"property","is_exclusive":false,"is_computed":false,"is_readonly":false,"has_default":false,"pointers":[]}],"exclusives":[],"backlinks":[{"card":"Many","name":"","is_abstract":true,"kind":"tuple","enum_values":null,"is_seq":false,"material_id":null,"bases":[],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[{"target_id":"00000000-0000-0000-0000-000000000003","name":"object"},{"target_id":"00000000-0000-0000-0000-000000000106","name":"score"}],"range_element_id":null,"multirange_element_id":null} as any); spec.set("7d751bb1-5dc9-11ef-ae8b-6739e287931c", {"id":"7d751bb1-5dc9-11ef-ae8b-6739e287931c","name":"tuple","is_abstract":false,"kind":"tuple","enum_values":null,"is_seq":false,"material_id":null,"bases":[],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[{"target_id":"7d73002a-5dc9-11ef-b7c6-1b1869917cb5","name":"provider"},{"target_id":"00000000-0000-0000-0000-000000000101","name":"subject"}],"range_element_id":null,"multirange_element_id":null} as any); spec.set("7d1cd047-5dc9-11ef-88b6-0b7d767899e7", {"id":"7d1cd047-5dc9-11ef-88b6-0b7d767899e7","name":"tuple","is_abstract":false,"kind":"tuple","enum_values":null,"is_seq":false,"material_id":null,"bases":[],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[{"target_id":"00000000-0000-0000-0000-000000000101","name":"reason"},{"target_id":"00000000-0000-0000-0000-000000000104","name":"operation"}],"range_element_id":null,"multirange_element_id":null} as any); +spec.set("53c4dd1e-5f55-11ef-a2b2-536adfa4a88a", {"id":"53c4dd1e-5f55-11ef-a2b2-536adfa4a88a","name":"tuple","is_abstract":false,"kind":"tuple","enum_values":null,"is_seq":false,"material_id":null,"bases":[],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[{"target_id":"7cf8dc43-5dc9-11ef-98ec-bdba499db282","name":"salt"},{"target_id":"7cf8dc43-5dc9-11ef-98ec-bdba499db282","name":"bytecodeHash"},{"target_id":"7cf4cbaa-5dc9-11ef-b2d0-b905e934d50a","name":"aaVersion"}],"range_element_id":null,"multirange_element_id":null} as any); spec.set("e34cf562-ee0c-58d3-a1ee-ff9fbb35bfc3", {"id":"e34cf562-ee0c-58d3-a1ee-ff9fbb35bfc3","name":"tuple","is_abstract":true,"kind":"tuple","enum_values":null,"is_seq":false,"material_id":null,"bases":[],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[{"target_id":"00000000-0000-0000-0000-000000000105","name":"0"},{"target_id":"00000000-0000-0000-0000-000000000001","name":"1"}],"range_element_id":null,"multirange_element_id":null} as any); spec.set("b20a2c38-2942-5085-88a3-1bbb1eea755f", {"id":"b20a2c38-2942-5085-88a3-1bbb1eea755f","name":"tuple","is_abstract":false,"kind":"tuple","enum_values":null,"is_seq":false,"material_id":null,"bases":[],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[{"target_id":"00000000-0000-0000-0000-000000000105","name":"0"},{"target_id":"00000000-0000-0000-0000-000000000105","name":"1"}],"range_element_id":null,"multirange_element_id":null} as any); spec.set("416fe1a6-d62c-5481-80cd-2102a37b3415", {"id":"416fe1a6-d62c-5481-80cd-2102a37b3415","name":"tuple","is_abstract":false,"kind":"tuple","enum_values":null,"is_seq":false,"material_id":null,"bases":[],"union_of":[],"intersection_of":[],"pointers":[],"exclusives":[],"backlinks":[],"backlink_stubs":[],"array_element_id":null,"tuple_elements":[{"target_id":"00000000-0000-0000-0000-000000000101","name":"0"},{"target_id":"00000000-0000-0000-0000-00000000010f","name":"1"}],"range_element_id":null,"multirange_element_id":null} as any); diff --git a/api/dbschema/edgeql-js/modules/default.ts b/api/dbschema/edgeql-js/modules/default.ts index f4994a8f8..22d73d797 100644 --- a/api/dbschema/edgeql-js/modules/default.ts +++ b/api/dbschema/edgeql-js/modules/default.ts @@ -96,13 +96,13 @@ export type $AccountλShape = $.typeutil.flatten; "implementation": $.PropertyDesc<$Address, $.Cardinality.One, false, false, false, false>; "photo": $.PropertyDesc<$Url, $.Cardinality.AtMostOne, false, false, false, false>; - "salt": $.PropertyDesc<$Bytes32, $.Cardinality.One, false, false, false, false>; "policies": $.LinkDesc<$Policy, $.Cardinality.Many, {}, false, true, false, false>; "approvers": $.LinkDesc<$Approver, $.Cardinality.Many, {}, false, true, false, false>; "messages": $.LinkDesc<$Message, $.Cardinality.Many, {}, false, true, false, false>; "proposals": $.LinkDesc<$Proposal, $.Cardinality.Many, {}, false, true, false, false>; "transactions": $.LinkDesc<$Transaction, $.Cardinality.Many, {}, false, true, false, false>; "transfers": $.LinkDesc<$Transfer, $.Cardinality.Many, {}, false, true, false, false>; + "initialization": $.PropertyDesc<$.NamedTupleType<{salt: $Bytes32, bytecodeHash: $Bytes32, aaVersion: $uint16}>, $.Cardinality.One, false, false, false, false>; "; "; "; diff --git a/api/dbschema/interfaces.ts b/api/dbschema/interfaces.ts index 074bd82a4..e4adfa1bf 100644 --- a/api/dbschema/interfaces.ts +++ b/api/dbschema/interfaces.ts @@ -87,13 +87,13 @@ export namespace $default { "active": boolean; "implementation": string; "photo"?: string | null; - "salt": string; "policies": Policy[]; "approvers": Approver[]; "messages": Message[]; "proposals": Proposal[]; "transactions": Transaction[]; "transfers": Transfer[]; + "initialization": {salt: string, bytecodeHash: string, aaVersion: number}; } export interface Action extends std.$Object { "functions": ActionFunction[]; diff --git a/api/dbschema/migrations/00006-m13y2dt.edgeql b/api/dbschema/migrations/00006-m13y2dt.edgeql new file mode 100644 index 000000000..bc1abee88 --- /dev/null +++ b/api/dbschema/migrations/00006-m13y2dt.edgeql @@ -0,0 +1,16 @@ +CREATE MIGRATION m13y2dtmcrd7yvmorrgn62mp2cakpvrcbz7p7g2rr4wk34b6ow7m7q + ONTO m174x3tft7rqwxzekegp7qad4qlscof7tojfcmw4wielhp7h4mqsya +{ + ALTER TYPE default::Account { + CREATE REQUIRED PROPERTY initialization: tuple { + SET REQUIRED USING (( + salt := .salt, + bytecodeHash := '0x0100007b3eebe76a9052ad76c1efe68151404a98aee77b96cbdbc62df0660b27', + aaVersion := 1 + )); + }; + }; + ALTER TYPE default::Account { + DROP PROPERTY salt; + }; +}; diff --git a/api/src/feat/accounts/accounts.service.spec.ts b/api/src/feat/accounts/accounts.service.spec.ts index 522d24707..6fe8ec1e1 100644 --- a/api/src/feat/accounts/accounts.service.spec.ts +++ b/api/src/feat/accounts/accounts.service.spec.ts @@ -1,8 +1,8 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test } from '@nestjs/testing'; import { UserContext, asUser, getUserCtx } from '~/core/context'; -import { randomLabel, randomAddress, randomUAddress, randomUser } from '~/util/test'; -import { getProxyAddress, UAddress } from 'lib'; +import { randomAddress, randomLabel, randomUAddress, randomUser } from '~/util/test'; +import { UAddress } from 'lib'; import { PoliciesService } from '../policies/policies.service'; import { BullModule, getQueueToken } from '@nestjs/bullmq'; import { ActivationsQueue } from '../activations/activations.queue'; @@ -12,13 +12,14 @@ import e from '~/edgeql-js'; import { uuid } from 'edgedb/dist/codecs/ifaces'; import { AccountsCacheService } from '../auth/accounts.cache.service'; import { TypedQueue } from '~/core/bull/bull.util'; +import { create2Address } from 'zksync-ethers/build/utils'; -jest.mock('lib', () => ({ - ...jest.requireActual('lib'), - getProxyAddress: jest.fn(), +jest.mock('zksync-ethers/build/utils', () => ({ + ...jest.requireActual('zksync-ethers/build/utils'), + create2Address: jest.fn(), })); -const getProxyAddressMock = jest.mocked(getProxyAddress); +const create2AddressMock = jest.mocked(create2Address); describe(AccountsService.name, () => { let service: AccountsService; @@ -51,7 +52,7 @@ describe(AccountsService.name, () => { const createAccount = async () => { const userCtx = getUserCtx(); - getProxyAddressMock.mockReturnValue(randomAddress()); + create2AddressMock.mockReturnValue(randomAddress()); return service.createAccount({ chain: 'zksync-local', diff --git a/api/src/feat/accounts/accounts.service.ts b/api/src/feat/accounts/accounts.service.ts index c51dc6f1b..6fd85eecb 100644 --- a/api/src/feat/accounts/accounts.service.ts +++ b/api/src/feat/accounts/accounts.service.ts @@ -4,13 +4,14 @@ import e from '~/edgeql-js'; import { asPolicyKey, randomDeploySalt, - getProxyAddress, Address, UAddress, asAddress, ACCOUNT_IMPLEMENTATION, asUAddress, PLACEHOLDER_ACCOUNT_ADDRESS, + ACCOUNT_PROXY, + encodeProxyConstructorArgs, } from 'lib'; import { CREATE2_FACTORY } from 'lib/dapps'; import { ShapeFunc } from '~/core/database'; @@ -32,6 +33,8 @@ import { v4 as uuid } from 'uuid'; import { selectAccount2 } from './accounts.util'; import { AccountEvent } from './accounts.model'; import { PolicyInput } from '../policies/policies.input'; +import { utils as zkUtils } from 'zksync-ethers'; +import { toHex } from 'viem'; const accountTrigger = (account: UAddress) => `account.updated:${account}`; const accountApproverTrigger = (approver: Address) => `account.updated:approver:${approver}`; @@ -107,13 +110,17 @@ export class AccountsService { throw new UserInputError('Duplicate policy keys'); const implementation = ACCOUNT_IMPLEMENTATION.address[chain]; + const bytecodeHash = toHex(zkUtils.hashBytecode(ACCOUNT_PROXY.bytecode)); const address = asUAddress( - getProxyAddress({ - deployer: CREATE2_FACTORY.address, - implementation, + zkUtils.create2Address( + CREATE2_FACTORY.address, + bytecodeHash, salt, - policies: policies.map((p) => inputAsPolicy(p.key, p)), - }), + encodeProxyConstructorArgs({ + implementation, + policies: policies.map((p) => inputAsPolicy(p.key, p)), + }), + ), chain, ); @@ -147,7 +154,7 @@ export class AccountsService { address, name, implementation, - salt, + initialization: { salt, bytecodeHash, aaVersion: 1 }, }), ); diff --git a/api/src/feat/accounts/insert-account.edgeql b/api/src/feat/accounts/insert-account.edgeql index 18d720e6b..3bf2d3beb 100644 --- a/api/src/feat/accounts/insert-account.edgeql +++ b/api/src/feat/accounts/insert-account.edgeql @@ -3,5 +3,5 @@ insert Account { address := $address, name := $name, implementation :=
$implementation, - salt := $salt + initialization := >$initialization } \ No newline at end of file diff --git a/api/src/feat/accounts/insert-account.query.ts b/api/src/feat/accounts/insert-account.query.ts index 2fc99d57a..fd6a48d21 100644 --- a/api/src/feat/accounts/insert-account.query.ts +++ b/api/src/feat/accounts/insert-account.query.ts @@ -7,7 +7,11 @@ export type InsertAccountArgs = { readonly "address": string; readonly "name": string; readonly "implementation": string; - readonly "salt": string; + readonly "initialization": { + readonly "salt": string; + readonly "bytecodeHash": string; + readonly "aaVersion": number; + }; }; export type InsertAccountReturns = { @@ -21,7 +25,7 @@ insert Account { address := $address, name := $name, implementation :=
$implementation, - salt := $salt + initialization := >$initialization }`, args); } diff --git a/api/src/feat/activations/activations.service.ts b/api/src/feat/activations/activations.service.ts index 0cb1062a0..8c1dfa3dd 100644 --- a/api/src/feat/activations/activations.service.ts +++ b/api/src/feat/activations/activations.service.ts @@ -9,7 +9,6 @@ import { replaceSelfAddress, PLACEHOLDER_ACCOUNT_ADDRESS, UUID, - ACCOUNT_PROXY, encodeProxyConstructorArgs, } from 'lib'; import { CREATE2_FACTORY } from 'lib/dapps'; @@ -21,13 +20,6 @@ import { FlowJob } from 'bullmq'; import { ConfirmationQueue } from '../system-txs/confirmations.queue'; import Decimal from 'decimal.js'; import { SimulationsQueue } from '../simulations/simulations.worker'; -import { toHex } from 'viem'; -import { utils as zkUtils } from 'zksync-ethers'; - -interface FeeParams { - account: UAddress; - feePerGas: Decimal; -} @Injectable() export class ActivationsService { @@ -61,15 +53,15 @@ export class ActivationsService { } satisfies FlowJob; } - async fee({ account, feePerGas }: FeeParams): Promise { - const a = await this.db.queryWith( + async fee(account: UAddress): Promise { + const a = await this.db.queryWith2( { address: e.UAddress }, + { address: account }, ({ address }) => e.select(e.Account, () => ({ filter_single: { address }, activationEthFee: true, })), - { address: account }, ); if (!a) return null; if (a.activationEthFee) return new Decimal(a.activationEthFee); @@ -79,8 +71,11 @@ export class ActivationsService { const network = this.networks.get(account); try { - const gas = await network.estimateContractGas(request); - return feePerGas.mul(gas.toString()); + const [gas, maxFeePerGas] = await Promise.all([ + network.estimateContractGas(request), + network.maxFeePerGas(), + ]); + return maxFeePerGas.mul(gas.toString()); } catch (e) { const isDeployed = !!(await network.getCode({ address: asAddress(account) }))?.length; if (isDeployed) return null; @@ -97,7 +92,7 @@ export class ActivationsService { filter_single: { address }, active: true, implementation: true, - salt: true, + initialization: true, initPolicies: e.select(a.policies, (p) => ({ filter: p.initState, ...PolicyShape, @@ -126,10 +121,10 @@ export class ActivationsService { address: CREATE2_FACTORY.address, functionName: 'create2Account' as const, args: [ - asHex(account.salt), - toHex(zkUtils.hashBytecode(ACCOUNT_PROXY.bytecode)), + asHex(account.initialization.salt), + asHex(account.initialization.bytecodeHash), constructorArgs, - 1, // AccountAbstractionVersion.Version1 + account.initialization.aaVersion, ] as const, // factoryDeps: [ACCOUNT_PROXY.bytecode], // Throws "rpc method is not whitelisted" if provided; bytecode must be deployed using SystemContractDeployer first // gas: 3_000_000n * BigInt(params.policies.length), // ~1M per policy; gas estimation panics if not provided diff --git a/api/src/feat/activations/activations.worker.ts b/api/src/feat/activations/activations.worker.ts index c1a5d84a0..53c77ebdd 100644 --- a/api/src/feat/activations/activations.worker.ts +++ b/api/src/feat/activations/activations.worker.ts @@ -8,6 +8,8 @@ import { ActivationsQueue } from './activations.queue'; import { DatabaseService } from '~/core/database'; import e from '~/edgeql-js'; import { selectTransaction2 } from '../transactions/transactions.util'; +import { UnrecoverableError } from 'bullmq'; +import { asAddress } from 'lib'; @Injectable() @Processor(ActivationsQueue.name, { autorun: false }) @@ -42,7 +44,11 @@ export class ActivationsWorker extends Worker { const request = await this.activations.request(account); if (!request) return null; - await network.simulateContract(request); // Throws on error + const sim = await network.simulateContract(request); // Throws on error + if (sim.result !== asAddress(account)) + throw new UnrecoverableError( + `Simulated deployment address ${sim.result} doesn't match expected address ${asAddress(account)}`, + ); const { account: _, ...req } = request; const receipt = await network.useWallet((wallet) => wallet.writeContract(req)); diff --git a/api/src/feat/paymasters/paymasters.service.ts b/api/src/feat/paymasters/paymasters.service.ts index 080b235ac..b5d7975b8 100644 --- a/api/src/feat/paymasters/paymasters.service.ts +++ b/api/src/feat/paymasters/paymasters.service.ts @@ -39,9 +39,7 @@ export class PaymastersService implements OnModuleInit { } async paymasterFees({ account }: PaymasterFeesParams): Promise { - const feePerGas = await this.networks.get(account).maxFeePerGas(); - - const activation = await this.activations.fee({ account, feePerGas }); + const activation = await this.activations.fee(account); return { activation: activation ?? new Decimal(0) }; } diff --git a/api/src/feat/policies/policies.service.spec.ts b/api/src/feat/policies/policies.service.spec.ts index b728deb16..e0ade18dc 100644 --- a/api/src/feat/policies/policies.service.spec.ts +++ b/api/src/feat/policies/policies.service.spec.ts @@ -1,15 +1,7 @@ import { Test } from '@nestjs/testing'; import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { PoliciesService, ProposePoliciesParams } from './policies.service'; -import { - asPolicyKey, - asSelector, - asUUID, - randomDeploySalt, - randomHex, - UAddress, - ZERO_ADDR, -} from 'lib'; +import { asPolicyKey, asSelector, asUUID, randomHex, UAddress, ZERO_ADDR } from 'lib'; import { UserContext } from '~/core/context'; import { asUser, getUserCtx } from '~/core/context'; import { randomAddress, randomLabel, randomUAddress, randomUser } from '~/util/test'; @@ -20,6 +12,7 @@ import { inputAsPolicy, policyStateAsPolicy, PolicyShape, selectPolicy } from '. import { PolicyInput } from './policies.input'; import { v1 as uuidv1 } from 'uuid'; import { selectAccount } from '../accounts/accounts.util'; +import { zeroHash } from 'viem'; describe(PoliciesService.name, () => { let service: PoliciesService; @@ -58,8 +51,8 @@ describe(PoliciesService.name, () => { id: accountId, address: account, name: randomLabel(), - implementation: randomAddress(), - salt: randomDeploySalt(), + implementation: ZERO_ADDR, + initialization: { salt: zeroHash, bytecodeHash: zeroHash, aaVersion: 1 }, }), ); diff --git a/api/src/feat/transactions/transactions.service.spec.ts b/api/src/feat/transactions/transactions.service.spec.ts index 897194e01..1d1977b19 100644 --- a/api/src/feat/transactions/transactions.service.spec.ts +++ b/api/src/feat/transactions/transactions.service.spec.ts @@ -2,7 +2,7 @@ import { Test } from '@nestjs/testing'; import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { asUser, getUserCtx, UserContext } from '~/core/context'; import { DeepPartial, randomAddress, randomLabel, randomUAddress, randomUser } from '~/util/test'; -import { randomDeploySalt, Hex, UAddress, ZERO_ADDR, asUUID, asPolicyKey } from 'lib'; +import { Hex, UAddress, ZERO_ADDR, asUUID, asPolicyKey } from 'lib'; import { Network, NetworksService } from '~/core/networks/networks.service'; import { ProposeTransactionInput } from './transactions.input'; import { DatabaseService } from '~/core/database'; @@ -112,8 +112,8 @@ describe(TransactionsService.name, () => { id: accountId, address: account, name: randomLabel(), - implementation: randomAddress(), - salt: randomDeploySalt(), + implementation: ZERO_ADDR, + initialization: { salt: zeroHash, bytecodeHash: zeroHash, aaVersion: 1 }, upgradedAtBlock: 1n, }) .unlessConflict(), diff --git a/api/src/feat/transfers/transfers.service.spec.ts b/api/src/feat/transfers/transfers.service.spec.ts index 531fa9522..afc554192 100644 --- a/api/src/feat/transfers/transfers.service.spec.ts +++ b/api/src/feat/transfers/transfers.service.spec.ts @@ -13,13 +13,13 @@ import { asChain, asUAddress, asUUID, - randomDeploySalt, } from 'lib'; -import { randomAddress, randomLabel, randomUAddress, randomUser } from '~/util/test'; +import { randomLabel, randomUAddress, randomUser } from '~/util/test'; import e from '~/edgeql-js'; import { v1 as uuidv1 } from 'uuid'; import { InsertShape } from '~/edgeql-js/insert'; import { $Transfer } from '~/edgeql-js/modules/default'; +import { zeroHash } from 'viem'; describe(TransfersService.name, () => { let service: TransfersService; @@ -45,8 +45,8 @@ describe(TransfersService.name, () => { id, address, name: randomLabel(), - implementation: randomAddress(), - salt: randomDeploySalt(), + implementation: ZERO_ADDR, + initialization: { salt: zeroHash, bytecodeHash: zeroHash, aaVersion: 1 }, upgradedAtBlock: 1n, }) .unlessConflict() diff --git a/contracts/script/deployProxy.ts b/contracts/script/deployProxy.ts index e1c71cd96..42a31fdd7 100644 --- a/contracts/script/deployProxy.ts +++ b/contracts/script/deployProxy.ts @@ -4,7 +4,7 @@ import { TASK_COMPILE } from 'hardhat/builtin-tasks/task-names'; import AccountProxy from './contracts/AccountProxy'; import { deploy } from './util/deploy'; -const ACCOUNT = '0xc0c1c0692F1aCd4FA91ccc73fB9aCFCd60Dd571a'; +const ACCOUNT = '0x696532D64a358a4CC2eCDBE698a4a08c7841af8c'; // Deploys an uninitialized proxy // Used for first-time proxy bytecode deployment diff --git a/packages/lib/src/deploy.ts b/packages/lib/src/deploy.ts index a216527d9..f764572dd 100644 --- a/packages/lib/src/deploy.ts +++ b/packages/lib/src/deploy.ts @@ -1,18 +1,8 @@ -import { Address, asAddress } from './address'; -import { utils as zkUtils } from 'zksync-ethers'; +import { Address } from './address'; import { Policy, encodePolicyStruct } from './policy'; -import { Network, NetworkWallet } from 'chains'; import { ACCOUNT_ABI, ACCOUNT_PROXY } from './contract'; -import { - Hex, - encodeAbiParameters, - encodeFunctionData, - ContractFunctionParameters, - toHex, -} from 'viem'; -import { err, ok } from 'neverthrow'; +import { encodeAbiParameters, encodeFunctionData } from 'viem'; import { randomHex } from './bytes'; -import { CREATE2_FACTORY } from './dapps'; export const randomDeploySalt = () => randomHex(32); @@ -41,75 +31,3 @@ export const encodeProxyConstructorArgs = ({ policies, implementation }: ProxyCo encodedInitializeCall, ]); }; - -export interface GetProxyAddressArgs extends ProxyConstructorArgs { - deployer: Address; - salt: Hex; -} - -export function getProxyAddress({ deployer, salt, ...constructorArgs }: GetProxyAddressArgs) { - const address = zkUtils.create2Address( - deployer, - toHex(zkUtils.hashBytecode(ACCOUNT_PROXY.bytecode)), - salt, - encodeProxyConstructorArgs(constructorArgs), - ); - - return asAddress(address); -} - -export interface DeployAccountProxyRequestParams extends ProxyConstructorArgs { - deployer: Address; - salt: Hex; -} - -export function deployAccountProxyRequest({ - deployer, - salt, - ...constructorArgs -}: DeployAccountProxyRequestParams) { - return { - abi: CREATE2_FACTORY.abi, - address: deployer, - functionName: 'create2Account' as const, - args: [ - salt, - toHex(zkUtils.hashBytecode(ACCOUNT_PROXY.bytecode)), - encodeProxyConstructorArgs(constructorArgs), - 1, // AccountAbstractionVersion.Version1 - ] as const, - gas: 3_000_000n * BigInt(constructorArgs.policies.length), // ~1M per policy; gas estimation panics if not provided - } satisfies ContractFunctionParameters & { gas: bigint }; -} - -export interface SimulateDeployAccountProxyArgs extends DeployAccountProxyRequestParams { - network: Network; -} - -export async function simulateDeployAccountProxy({ - network, - deployer, - salt, - ...constructorArgs -}: SimulateDeployAccountProxyArgs) { - const proxy = getProxyAddress({ deployer, salt, ...constructorArgs }); - - const params = deployAccountProxyRequest({ deployer, salt, ...constructorArgs }); - const sim = await network.simulateContract(params); - if (sim.result !== proxy) return err({ proxy, simulated: sim.result }); - - return ok({ proxy, params, ...sim }); -} - -export interface DeployAccountProxyArgs extends SimulateDeployAccountProxyArgs { - wallet: NetworkWallet; -} - -export const deployAccountProxy = async ({ wallet, ...args }: DeployAccountProxyArgs) => { - const sim = await simulateDeployAccountProxy(args); - - return sim.asyncMap(async ({ proxy, request }) => { - const transactionHash = await wallet.writeContract(request); - return { proxy, transactionHash }; - }); -};