Skip to content

Commit d304af5

Browse files
nicholaspaigrasphoper
authored andcommitted
feat(MulticallerClient): Allow caller to use PermissionedMulticaller
Can be used to batch txns to contracts that whitelist the msg.sender
1 parent 5f802a2 commit d304af5

File tree

4 files changed

+30
-7
lines changed

4 files changed

+30
-7
lines changed

src/clients/MultiCallerClient.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
getProvider,
1717
Multicall2Call,
1818
assert,
19+
getPermissionedMultisender,
1920
} from "../utils";
2021
import { AugmentedTransaction, TransactionClient } from "./TransactionClient";
2122
import lodash from "lodash";
@@ -260,10 +261,21 @@ export class MultiCallerClient {
260261
return this.baseSigner ? getMultisender(chainId, this.baseSigner.connect(await getProvider(chainId))) : undefined;
261262
}
262263

264+
async _getPermissionedMultisender(chainId: number): Promise<Contract | undefined> {
265+
return this.baseSigner
266+
? getPermissionedMultisender(chainId, this.baseSigner.connect(await getProvider(chainId)))
267+
: undefined;
268+
}
269+
263270
async buildMultiSenderBundle(transactions: AugmentedTransaction[]): Promise<AugmentedTransaction> {
264271
// Validate all transactions have the same chainId and can be sent from multisender.
265272
const { chainId } = transactions[0];
266-
const multisender = await this._getMultisender(chainId);
273+
// If any transactions are to be sent through the permissioned multisender, then we should use that instead
274+
// of the default multisender. This means that the caller must only batch transactions to this chain that can
275+
// be executed from the permissioned multisender.
276+
const multisender = transactions.some((t) => t.sendThroughPermissionedMulticall)
277+
? await this._getPermissionedMultisender(chainId)
278+
: await this._getMultisender(chainId);
267279
if (!multisender) {
268280
throw new Error("Multisender not available for this chain");
269281
}
@@ -272,12 +284,17 @@ export class MultiCallerClient {
272284
const callData: Multicall2Call[] = [];
273285
let gasLimit: BigNumber | undefined = bnZero;
274286
transactions.forEach((txn, idx) => {
275-
if (!txn.unpermissioned || txn.chainId !== chainId) {
287+
if (!txn.unpermissioned || !txn.sendThroughPermissionedMulticall || txn.chainId !== chainId) {
276288
this.logger.error({
277289
at: "MultiCallerClient#buildMultiSenderBundle",
278290
message: "Some transactions in the queue contain different target chain or are permissioned",
279291
transactions: transactions.map(({ contract, chainId, unpermissioned }) => {
280-
return { target: getTarget(contract.address), unpermissioned: Boolean(unpermissioned), chainId };
292+
return {
293+
target: getTarget(contract.address),
294+
unpermissioned: Boolean(unpermissioned),
295+
sendThroughPermissionedMulticall: Boolean(txn.sendThroughPermissionedMulticall),
296+
chainId,
297+
};
281298
}),
282299
notificationPath: "across-error",
283300
});
@@ -380,7 +397,7 @@ export class MultiCallerClient {
380397
multisenderTxns = [],
381398
unsendableTxns = [],
382399
} = lodash.groupBy(txns, (txn) => {
383-
if (txn.unpermissioned) {
400+
if (txn.unpermissioned || txn.sendThroughPermissionedMulticall) {
384401
return "multisenderTxns";
385402
} else if (txn.contract.multicall) {
386403
return "multicallerTxns";

src/clients/TransactionClient.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export interface AugmentedTransaction {
2626
value?: BigNumber;
2727
unpermissioned?: boolean; // If false, the transaction must be sent from the enqueuer of the method.
2828
// If true, then can be sent from the MakerDAO multisender contract.
29+
sendThroughPermissionedMulticall?: boolean;
30+
// If true, then should be sent through the permissioned multisender contract.
2931
canFailInSimulation?: boolean;
3032
// Optional batch ID to use to group transactions
3133
groupId?: string;

src/finalizer/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,8 @@ export async function finalize(
294294
hubChainId,
295295
...configuredChainIds,
296296
]).map(
297-
async (chainId) =>
298-
[chainId, await getMultisender(chainId, spokePoolClients[chainId].spokePool.signer)] as [number, Contract]
297+
(chainId) =>
298+
[chainId, getMultisender(chainId, spokePoolClients[chainId].spokePool.signer)] as [number, Contract]
299299
)
300300
)
301301
);

src/utils/TransactionUtils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,14 @@ export function getNetworkError(err: unknown): string {
5353
return isEthersError(err) ? err.reason : isError(err) ? err.message : "unknown error";
5454
}
5555

56-
export async function getMultisender(chainId: number, baseSigner: Signer): Promise<Contract | undefined> {
56+
export function getMultisender(chainId: number, baseSigner: Signer): Contract | undefined {
5757
return sdkUtils.getMulticall3(chainId, baseSigner);
5858
}
5959

60+
export function getPermissionedMultisender(chainId: number, baseSigner: Signer): Contract | undefined {
61+
return sdkUtils.getPermissionedMulticall3(chainId, baseSigner);
62+
}
63+
6064
// Note that this function will throw if the call to the contract on method for given args reverts. Implementers
6165
// of this method should be considerate of this and catch the response to deal with the error accordingly.
6266
export async function runTransaction(

0 commit comments

Comments
 (0)