Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #229 from getwax/wax-215-add-compression
Browse files Browse the repository at this point in the history
Add compression to bundler
  • Loading branch information
jacque006 authored Jun 19, 2024
2 parents a63aa91 + 809d8df commit dfce55d
Show file tree
Hide file tree
Showing 14 changed files with 293 additions and 115 deletions.
5 changes: 5 additions & 0 deletions packages/demos/inpage/demo/config/ConfigType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ type ConfigType = {
addFundsEthAmount?: string;
deployerSeedPhrase: string;
requirePermission?: boolean;
externalContracts?: {
entryPoint: string;
blsSignatureAggregator: string;
addressRegistry: string;
};
};

export default ConfigType;
13 changes: 13 additions & 0 deletions packages/demos/inpage/demo/config/config.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,24 @@ const config: ConfigType = {
rpcUrl: 'http://127.0.0.1:8545',
deployerSeedPhrase:
'test test test test test test test test test test test junk',

// Uncomment this with the url of a bundler to enable using an external
// bundler (sometimes this is the same as rpcUrl). Otherwise, a bundler will
// be simulated inside the library.
// bundlerRpcUrl: '',

requirePermission: false,

// These contracts will be deployed deterministically by default. However,
// if you need to interop with a specific existing deployment, you'll need
// to specify the contracts here:
// externalContracts: {
// entryPoint: '0x...',
// blsSignatureAggregator: '0x...',
// addressRegistry: '0x...',
// }
// (Other contracts will still be deterministically deployed, but they
// shouldn't be required for interop purposes.)
};

export default config;
1 change: 1 addition & 0 deletions packages/demos/inpage/demo/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ WaxInPage.addStylesheet();
const waxInPage = new WaxInPage({
rpcUrl: config.rpcUrl,
bundlerRpcUrl: config.bundlerRpcUrl,
externalContracts: config.externalContracts,
});

waxInPage.attachGlobals();
Expand Down
24 changes: 23 additions & 1 deletion packages/demos/inpage/scripts/dev.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
#!/usr/bin/env tsx

/* eslint-disable no-console */

import concurrently from 'concurrently';
import config from '../demo/config/config.ts';

const tasks = ['vite'];

let externalNode: boolean;

if (config.rpcUrl === 'http://127.0.0.1:8545') {
tasks.push('yarn --cwd hardhat hardhat node');
try {
await fetch(config.rpcUrl);
externalNode = true;
} catch (e) {
if ((e as { code: string }).code !== 'ECONNREFUSED') {
throw e;
}

externalNode = false;
tasks.push('yarn --cwd hardhat hardhat node');
}
} else {
externalNode = true;
}

if (externalNode) {
console.log(`Relying on external node: ${config.rpcUrl}`);
} else {
console.log('Starting dev node');
}

await concurrently(tasks, { killOthers: 'failure' }).result;
4 changes: 4 additions & 0 deletions packages/demos/inpage/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ const Button = ({
return;
}

if ('key' in e && e.key !== 'Enter' && e.key !== ' ') {
return;
}

runAsync(async () => {
try {
setLoading(true);
Expand Down
24 changes: 19 additions & 5 deletions packages/demos/inpage/src/EthereumApi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import { roundUpPseudoFloat } from './helpers/encodeUtils';

// We need a UserOperation in order to estimate the gas fields of a
// UserOperation, so we use these values as placeholders.
const temporaryEstimationGas = '0x012345';
const temporaryEstimationGas = '0x01234567';
const temporarySignature = [
'0x',
'123456fe2807660c417ca1a38760342fa70135fcab89a8c7c879a77da8ce7a0b5a3805735e',
'95170906b11c6f30dcc74e463e1e6990c68a3998a7271b728b123456',
].join('');
const verificationGasLimitBuffer = 2000n;
const preVerificationGasBuffer = 1000n;

type StrictUserOperation = {
sender: string;
Expand Down Expand Up @@ -183,9 +185,15 @@ export default class EthereumApi {

return {
...userOp,
callGasLimit: roundUpPseudoFloat(userOp.callGasLimit),
verificationGasLimit: `0x${roundUpPseudoFloat(
BigInt(userOp.verificationGasLimit),
).toString(16)}`,
preVerificationGas: `0x${roundUpPseudoFloat(
BigInt(userOp.preVerificationGas),
).toString(16)}`,
maxFeePerGas: roundUpPseudoFloat(userOp.maxFeePerGas),
maxPriorityFeePerGas: roundUpPseudoFloat(userOp.maxPriorityFeePerGas),
callGasLimit: roundUpPseudoFloat(userOp.callGasLimit),
};
}

Expand Down Expand Up @@ -342,7 +350,7 @@ export default class EthereumApi {
callData,
callGasLimit: actions.map((a) => BigInt(a.gas)).reduce((a, b) => a + b),
verificationGasLimit: temporaryEstimationGas,
preVerificationGas: temporaryEstimationGas,
preVerificationGas: '0x0',
maxFeePerGas,
maxPriorityFeePerGas,
paymasterAndData: '0x',
Expand All @@ -360,8 +368,14 @@ export default class EthereumApi {
params: [userOp, await contracts.entryPoint.getAddress()],
});

userOp.verificationGasLimit = verificationGasLimit;
userOp.preVerificationGas = preVerificationGas;
userOp.verificationGasLimit = `0x${(
BigInt(verificationGasLimit) + verificationGasLimitBuffer
).toString(16)}`;
userOp.preVerificationGas = `0x${(
BigInt(preVerificationGas) + preVerificationGasBuffer
).toString(16)}`;

userOp = this.#maybeRoundUpPseudoFloats(userOp);

userOpHash = await this.#calculateUserOpHash(userOp);

Expand Down
4 changes: 2 additions & 2 deletions packages/demos/inpage/src/JsonRpcError.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import z from 'zod';

class JsonRpcError extends Error {
code: number;
code: number | string;
data: unknown;

constructor({ code, data, message }: RawJsonRpcError) {
Expand All @@ -17,7 +17,7 @@ class JsonRpcError extends Error {
}

const RawJsonRpcError = z.object({
code: z.number().int(),
code: z.union([z.number().int(), z.string()]),
data: z.unknown(),
message: z.string(),
});
Expand Down
133 changes: 93 additions & 40 deletions packages/demos/inpage/src/WaxInPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import measureCalldataGas from './measureCalldataGas';
import DeterministicDeployer, {
DeterministicDeploymentViewer,
} from '../lib-ts/deterministic-deployer/DeterministicDeployer';
import ConfigType from '../demo/config/ConfigType';

type Config = {
logRequests?: boolean;
Expand All @@ -58,6 +59,7 @@ type Config = {
deployContractsIfNeeded: boolean;
ethersPollingInterval?: number;
useTopLevelCompression?: boolean;
externalContracts?: ConfigType['externalContracts'];
};

const defaultConfig: Config = {
Expand All @@ -71,6 +73,7 @@ let ethersDefaultPollingInterval = 4000;
type ConstructorOptions = {
rpcUrl: string;
bundlerRpcUrl?: string;
externalContracts?: ConfigType['externalContracts'];
storage?: WaxStorage;
};

Expand Down Expand Up @@ -103,6 +106,7 @@ export default class WaxInPage {
constructor({
rpcUrl,
bundlerRpcUrl,
externalContracts,
storage = makeLocalWaxStorage(),
}: ConstructorOptions) {
let bundler: IBundler;
Expand All @@ -113,6 +117,8 @@ export default class WaxInPage {
bundler = new NetworkBundler(bundlerRpcUrl);
}

this.#config.externalContracts =
externalContracts ?? this.#config.externalContracts;
this.ethereum = new EthereumApi(rpcUrl, this, bundler);
this.storage = storage;
this.ethersProvider = new ethers.BrowserProvider(this.ethereum);
Expand Down Expand Up @@ -194,15 +200,48 @@ export default class WaxInPage {
chainId,
);

const assumedEntryPoint = viewer.connectAssume(EntryPoint__factory, []);

const assumedAddressRegistry = viewer.connectAssume(
AddressRegistry__factory,
[],
);
const wallet = await this.requestAdminAccount('deploy-contracts');

const assumedBlsOpen = viewer.connectAssume(BLSOpen__factory, []);

let assumedEntryPoint: EntryPoint;
let assumedAddressRegistry: AddressRegistry;
let assumedBlsSignatureAggregator: BLSSignatureAggregator;

if (this.#config.externalContracts) {
assumedEntryPoint = EntryPoint__factory.connect(
this.#config.externalContracts.entryPoint,
wallet,
);

assumedBlsSignatureAggregator = BLSSignatureAggregator__factory.connect(
this.#config.externalContracts.blsSignatureAggregator,
wallet,
);

assumedAddressRegistry = AddressRegistry__factory.connect(
this.#config.externalContracts.addressRegistry,
wallet,
);
} else {
assumedEntryPoint = viewer.connectAssume(EntryPoint__factory, []);

assumedAddressRegistry = viewer.connectAssume(
AddressRegistry__factory,
[],
);

assumedBlsSignatureAggregator = viewer.connectAssume(
DeterministicDeployer.link(BLSSignatureAggregator__factory, [
{
'account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen':
await assumedBlsOpen.getAddress(),
},
]),
[],
);
}

const contracts: Contracts = {
greeter: viewer.connectAssume(Greeter__factory, ['']).connect(runner),
entryPoint: assumedEntryPoint,
Expand All @@ -226,15 +265,7 @@ export default class WaxInPage {
[],
),
testToken: viewer.connectAssume(ERC20Mock__factory, []),
blsSignatureAggregator: viewer.connectAssume(
DeterministicDeployer.link(BLSSignatureAggregator__factory, [
{
'account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen':
await assumedBlsOpen.getAddress(),
},
]),
[],
),
blsSignatureAggregator: assumedBlsSignatureAggregator,
};

if (this.#contractsDeployed) {
Expand All @@ -250,18 +281,48 @@ export default class WaxInPage {
throw new Error('Contracts not deployed');
}

const wallet = await this.requestAdminAccount('deploy-contracts');

const factory = await DeterministicDeployer.init(wallet);

const entryPoint = await factory.connectOrDeploy(EntryPoint__factory, []);
const blsOpen = await factory.connectOrDeploy(BLSOpen__factory, []);

const addressRegistry = await factory.connectOrDeploy(
AddressRegistry__factory,
[],
);
let entryPoint: EntryPoint;
let blsSignatureAggregator: BLSSignatureAggregator;
let addressRegistry: AddressRegistry;

if (this.#config.externalContracts) {
entryPoint = assumedEntryPoint;
blsSignatureAggregator = assumedBlsSignatureAggregator;
addressRegistry = assumedAddressRegistry;

await Promise.all(
[entryPoint, blsSignatureAggregator, addressRegistry].map(
async (contract) => {
if (!(await this.#checkDeployed(await contract.getAddress()))) {
throw new Error(
`External contract not deployed: ${await contract.getAddress()}`,
);
}
},
),
);
} else {
entryPoint = await factory.connectOrDeploy(EntryPoint__factory, []);

const blsOpen = await factory.connectOrDeploy(BLSOpen__factory, []);
blsSignatureAggregator = await factory.connectOrDeploy(
DeterministicDeployer.link(BLSSignatureAggregator__factory, [
{
'account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen':
await blsOpen.getAddress(),
},
]),
[],
);

addressRegistry = await factory.connectOrDeploy(
AddressRegistry__factory,
[],
);
}

const deployments: {
[C in keyof Contracts]: () => Promise<Contracts[C]>;
Expand All @@ -285,16 +346,7 @@ export default class WaxInPage {
safeECDSARecoveryPlugin: () =>
factory.connectOrDeploy(SafeECDSARecoveryPlugin__factory, []),
testToken: () => factory.connectOrDeploy(ERC20Mock__factory, []),
blsSignatureAggregator: async () =>
factory.connectOrDeploy(
DeterministicDeployer.link(BLSSignatureAggregator__factory, [
{
'account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen':
await blsOpen.getAddress(),
},
]),
[],
),
blsSignatureAggregator: () => Promise.resolve(blsSignatureAggregator),
};

for (const deployment of Object.values(deployments)) {
Expand All @@ -306,18 +358,19 @@ export default class WaxInPage {

async #checkDeployments(contracts: Contracts): Promise<boolean> {
const deployFlags = await Promise.all(
Object.values(contracts).map(async (contract) => {
const existingCode = await this.ethersProvider.getCode(
contract.getAddress(),
);

return existingCode !== '0x';
}),
Object.values(contracts).map(
async (contract) =>
await this.#checkDeployed(await contract.getAddress()),
),
);

return deployFlags.every((flag) => flag);
}

async #checkDeployed(address: string): Promise<boolean> {
return (await this.ethersProvider.getCode(address)) !== '0x';
}

async requestAdminAccount(purpose: AdminPurpose): Promise<ethers.Wallet> {
if (this.#adminAccount) {
return this.#adminAccount;
Expand Down
Loading

0 comments on commit dfce55d

Please sign in to comment.