Skip to content
This repository has been archived by the owner on Nov 5, 2023. It is now read-only.

Add ExpanderEntryPoint to avoid solidity abi #590

Merged
merged 2 commits into from
May 2, 2023
Merged
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
6 changes: 3 additions & 3 deletions aggregator/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type {
PublicKey,
Signature,
VerificationGateway,
} from "https://esm.sh/bls-wallet-clients@0.8.3-bee2034";
} from "https://esm.sh/bls-wallet-clients@0.8.3-dc488ec";

export {
Aggregator as AggregatorClient,
Expand All @@ -70,10 +70,10 @@ export {
getConfig,
MockERC20Factory,
VerificationGatewayFactory,
} from "https://esm.sh/bls-wallet-clients@0.8.3-bee2034";
} from "https://esm.sh/bls-wallet-clients@0.8.3-dc488ec";

// Workaround for esbuild's export-star bug
import blsWalletClients from "https://esm.sh/bls-wallet-clients@0.8.3-bee2034";
import blsWalletClients from "https://esm.sh/bls-wallet-clients@0.8.3-dc488ec";
const { bundleFromDto, bundleToDto, initBlsWalletSigner } = blsWalletClients;
export { bundleFromDto, bundleToDto, initBlsWalletSigner };

Expand Down
26 changes: 12 additions & 14 deletions aggregator/src/app/AggregationStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -683,24 +683,22 @@ export default class AggregationStrategy {

const bundleOverheadGas = oneOpGasEstimate.sub(opMarginalGasEstimate);

const [oneOpTx, twoOpTx] = await Promise.all([
es.bundleCompressor.blsExpanderDelegator.populateTransaction.run(
await es.bundleCompressor.compress(bundle1),
),
es.bundleCompressor.blsExpanderDelegator.populateTransaction.run(
await es.bundleCompressor.compress(
this.blsWalletSigner.aggregate([bundle1, bundle2]),
),
const [compressedBundle1, compressedBundle12] = await Promise.all([
es.bundleCompressor.compress(bundle1),
es.bundleCompressor.compress(
this.blsWalletSigner.aggregate([bundle1, bundle2]),
),
]);

const [oneOpLen, twoOpLen] = await Promise.all([
es.wallet.signTransaction(oneOpTx).then((tx) =>
ethers.utils.hexDataLength(tx)
),
es.wallet.signTransaction(twoOpTx).then((tx) =>
ethers.utils.hexDataLength(tx)
),
es.wallet.signTransaction({
to: es.expanderEntryPoint.address,
data: compressedBundle1,
}).then((tx) => ethers.utils.hexDataLength(tx)),
es.wallet.signTransaction({
to: es.expanderEntryPoint.address,
data: compressedBundle12,
}).then((tx) => ethers.utils.hexDataLength(tx)),
]);

const opMarginalLen = twoOpLen - oneOpLen;
Expand Down
40 changes: 23 additions & 17 deletions aggregator/src/app/EthereumService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ type DecodeReturnType<
Method extends keyof Contract["callStatic"],
> = EnforceArray<AsyncReturnType<Contract["callStatic"][Method]>>;

type ExpanderEntryPoint = AsyncReturnType<
ContractsConnector["ExpanderEntryPoint"]
>;

export default class EthereumService {
constructor(
public emit: (evt: AppEvent) => void,
Expand All @@ -76,6 +80,7 @@ export default class EthereumService {
public blsWalletSigner: BlsWalletSigner,
public verificationGateway: VerificationGateway,
public aggregatorUtilities: AggregatorUtilities,
public expanderEntryPoint: ExpanderEntryPoint,
public bundleCompressor: BundleCompressor,
public nextNonce: BigNumber,
) {}
Expand Down Expand Up @@ -103,13 +108,15 @@ export default class EthereumService {
erc20Expander,
blsRegistration,
fallbackExpander,
expanderEntryPoint,
] = await Promise.all([
contractsConnector.VerificationGateway(),
contractsConnector.AggregatorUtilities(),
contractsConnector.BLSExpanderDelegator(),
contractsConnector.ERC20Expander(),
contractsConnector.BLSRegistration(),
contractsConnector.FallbackExpander(),
contractsConnector.ExpanderEntryPoint(),
]);

const blsWalletWrapper = await BlsWalletWrapper.connect(
Expand Down Expand Up @@ -166,6 +173,7 @@ export default class EthereumService {
blsWalletSigner,
verificationGateway,
aggregatorUtilities,
expanderEntryPoint,
bundleCompressor,
nextNonce,
);
Expand Down Expand Up @@ -316,30 +324,27 @@ export default class EthereumService {
this.verificationGateway.populateTransaction.processBundle(bundle).then(
(tx) => this.wallet.signTransaction(tx),
),
this.bundleCompressor.blsExpanderDelegator.populateTransaction
.run(compressedBundle).then((tx) => this.wallet.signTransaction(tx)),
this.wallet.signTransaction({
to: this.expanderEntryPoint.address,
data: compressedBundle,
}),
]);

const txLen = ethers.utils.hexDataLength(rawTx);
const compressedTxLen = ethers.utils.hexDataLength(rawCompressedTx);

const processBundleArgs: Parameters<
(typeof this.bundleCompressor.blsExpanderDelegator)["run"]
> = [
compressedBundle,
{
nonce: this.NextNonce(),
...await this.GasConfig(),
},
];
const txRequest: ethers.providers.TransactionRequest = {
to: this.expanderEntryPoint.address,
data: compressedBundle,
nonce: this.NextNonce(),
...await this.GasConfig(),
};

const attempt = async () => {
let txResponse: ethers.providers.TransactionResponse;

try {
txResponse = await this.bundleCompressor.blsExpanderDelegator.run(
...processBundleArgs,
);
txResponse = await this.wallet.sendTransaction(txRequest);
} catch (error) {
if (/\binvalid transaction nonce\b/.test(error.message)) {
// This can occur when the nonce is in the future, which can
Expand Down Expand Up @@ -403,9 +408,10 @@ export default class EthereumService {
async estimateCompressedGas(bundle: Bundle): Promise<BigNumber> {
const compressedBundle = await this.bundleCompressor.compress(bundle);

return this.bundleCompressor.blsExpanderDelegator.estimateGas.run(
compressedBundle,
);
return await this.wallet.estimateGas({
to: this.expanderEntryPoint.address,
data: compressedBundle,
});
}

async GasConfig() {
Expand Down
9 changes: 9 additions & 0 deletions contracts/clients/src/ContractsConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
BLSRegistration__factory as BLSRegistrationFactory,
BNPairingPrecompileCostEstimator__factory as BNPairingPrecompileCostEstimatorFactory,
ERC20Expander__factory as ERC20ExpanderFactory,
ExpanderEntryPoint__factory as ExpanderEntryPointFactory,
FallbackExpander__factory as FallbackExpanderFactory,
VerificationGateway__factory as VerificationGatewayFactory,
} from "../typechain-types";
Expand Down Expand Up @@ -140,6 +141,14 @@ export default class ContractsConnector {
this.salt,
),
);

ExpanderEntryPoint = once(async () =>
this.factoryViewer.connectOrThrow(
ExpanderEntryPointFactory,
[(await this.BLSExpanderDelegator()).address],
this.salt,
),
);
}

function once<T extends {}>(fn: () => T): () => T {
Expand Down
53 changes: 42 additions & 11 deletions contracts/clients/src/OperationResults.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { BigNumber, ContractReceipt, utils } from "ethers";
import assert from "./helpers/assert";
import { ActionData } from "./signer";
import { Result } from "ethers/lib/utils";
import { VerificationGateway__factory as VerificationGatewayFactory } from "../typechain-types";

export const errorSelectors = {
Error: calculateAndCheckSelector("Error(string)", "0x08c379a0"),
Expand Down Expand Up @@ -117,22 +119,49 @@ const getError = (
export const getOperationResults = (
txnReceipt: ContractReceipt,
): OperationResult[] => {
const walletOpProcessedEvents = txnReceipt.events?.filter(
(e) => e.event === "WalletOperationProcessed",
);
if (!walletOpProcessedEvents?.length) {
let walletOpProcessedEvents: Result[];

if (txnReceipt.events !== undefined) {
walletOpProcessedEvents = txnReceipt.events
.filter((e) => e.event === "WalletOperationProcessed")
.map(({ args }) => {
if (!args) {
throw new Error("WalletOperationProcessed event missing args");
}

return args;
});
} else if (txnReceipt.logs !== undefined) {
const vgInterface = VerificationGatewayFactory.createInterface();

const WalletOperationProcessed = vgInterface.getEvent(
"WalletOperationProcessed",
);

walletOpProcessedEvents = txnReceipt.logs
.filter(
(log) =>
log.topics[0] === vgInterface.getEventTopic(WalletOperationProcessed),
)
.map((log) =>
vgInterface.decodeEventLog(
WalletOperationProcessed,
log.data,
log.topics,
),
);
} else {
walletOpProcessedEvents = [];
}

if (walletOpProcessedEvents.length === 0) {
throw new Error(
`no WalletOperationProcessed events found in transaction ${txnReceipt.transactionHash}`,
);
}

return walletOpProcessedEvents.reduce<OperationResult[]>(
(opResults, { args }) => {
if (!args) {
throw new Error("WalletOperationProcessed event missing args");
}
const { wallet, nonce, actions: rawActions, success, results } = args;

(opResults, { wallet, nonce, actions: rawActions, success, results }) => {
const actions = rawActions.map(
({
ethValue,
Expand All @@ -150,7 +179,7 @@ export const getOperationResults = (
);
const error = getError(success, results);

return [
const ret = [
...opResults,
{
walletAddress: wallet,
Expand All @@ -161,6 +190,8 @@ export const getOperationResults = (
error,
},
];

return ret;
},
[],
);
Expand Down
24 changes: 24 additions & 0 deletions contracts/contracts/ExpanderEntryPoint.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//SPDX-License-Identifier: Unlicense
pragma solidity >=0.7.0 <0.9.0;
pragma abicoder v2;

interface IExpanderDelegator {
function run(
bytes calldata stream
) external returns (bool[] memory successes, bytes[][] memory results);
}

contract ExpanderEntryPoint {
IExpanderDelegator expanderDelegator;

constructor(IExpanderDelegator expanderDelegatorParam) {
expanderDelegator = expanderDelegatorParam;
}

fallback(bytes calldata stream) external returns (bytes memory) {
(bool[] memory successes, bytes[][] memory results) = expanderDelegator
.run{ gas: type(uint256).max }(stream);

return abi.encode(successes, results);
}
}
10 changes: 10 additions & 0 deletions contracts/shared/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
BLSRegistration,
ERC20Expander,
ERC20Expander__factory as ERC20ExpanderFactory,
ExpanderEntryPoint,
ExpanderEntryPoint__factory as ExpanderEntryPointFactory,
} from "../typechain-types";

import { SafeSingletonFactory } from "../clients/src";
Expand All @@ -40,6 +42,7 @@ export type Deployment = {
blsExpanderDelegator: BLSExpanderDelegator;
aggregatorUtilities: AggregatorUtilities;
blsRegistration: BLSRegistration;
expanderEntryPoint: ExpanderEntryPoint;
};

export default async function deploy(
Expand Down Expand Up @@ -89,6 +92,12 @@ export default async function deploy(
salt,
);

const expanderEntryPoint = await singletonFactory.connectOrDeploy(
ExpanderEntryPointFactory,
[blsExpanderDelegator.address],
salt,
);

return {
singletonFactory,
precompileCostEstimator,
Expand All @@ -102,6 +111,7 @@ export default async function deploy(
blsExpanderDelegator,
aggregatorUtilities,
blsRegistration,
expanderEntryPoint,
};
}

Expand Down
Loading