Skip to content

Commit

Permalink
batch rpc calls
Browse files Browse the repository at this point in the history
  • Loading branch information
jfschwarz committed Oct 20, 2023
1 parent 9cb0b6c commit cdf331a
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 27 deletions.
28 changes: 18 additions & 10 deletions packages/gelato-web3-function/delay-dispatch/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Web3Function } from "@gelatonetwork/web3-functions-sdk";
import { GelatoRelay } from "@gelatonetwork/relay-sdk";
import { BigNumber, Contract } from "ethers";
import { MulticallWrapper } from "ethers-multicall-provider";
import ky from "ky"; // gelato recommends using ky as axios doesn't support fetch by default

const DELAY_ABI = [
Expand Down Expand Up @@ -41,22 +42,29 @@ Web3Function.onRun(async (context) => {
throw new Error(`Invalid allowanceInterval userArg: ${allowanceInterval}`);
}

const provider = multiChainProvider.default(); // this will be a provider for the chain this function is deployed for (gelatoArgs.chainId)
// This will be a provider for the chain this function is deployed for (gelatoArgs.chainId)
// It will automatically batch calls via the Multicall3 contract
const provider = MulticallWrapper.wrap(multiChainProvider.default());
const delayMod = new Contract(delayModAddress, DELAY_ABI, provider);

if ((await provider.getCode(delayModAddress)) === "0x") {
// Query Delay mod contract for current nonce, cooldown, expiration
let nonce, cooldown, expiration: BigNumber;
let currentBlock: number;
try {
[nonce, cooldown, expiration, currentBlock] = await Promise.all([
delayMod.txNonce() as Promise<BigNumber>,
delayMod.txCooldown() as Promise<BigNumber>,
delayMod.txExpiration() as Promise<BigNumber>,
provider.getBlockNumber(),
]);
} catch (e) {
console.error(e);
return {
canExec: false,
message: `Delay mod contract not deployed at ${delayModAddress}`,
};
}

const delayMod = new Contract(delayModAddress, DELAY_ABI, provider);

// Query Delay mod contract for current nonce, cooldown, expiration
const nonce = (await delayMod.txNonce()) as BigNumber;
const cooldown = (await delayMod.txCooldown()) as BigNumber;
const expiration = (await delayMod.txExpiration()) as BigNumber;

// Query subgraph for upcoming transactions
let transactions: Transaction[] = [];
try {
Expand All @@ -70,7 +78,7 @@ Web3Function.onRun(async (context) => {
}

// Retrieve current & last processed block number
const currentBlock = await provider.getBlockNumber();

const lastBlockStr = await storage.get("lastBlockNumber");
let lastBlock = lastBlockStr ? parseInt(lastBlockStr) : 0;
console.log(
Expand Down
1 change: 1 addition & 0 deletions packages/gelato-web3-function/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@gelatonetwork/relay-sdk": "^5.5.1",
"@gelatonetwork/web3-functions-sdk": "^2.1.7",
"ethers": "^5.7.2",
"ethers-multicall-provider": "3.1.2",
"ky": "^1.1.0"
},
"installConfig": {
Expand Down
31 changes: 17 additions & 14 deletions packages/gelato-web3-function/test/function.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import path from "path";
import { Web3Function } from "@gelatonetwork/web3-functions-sdk";
import { Web3FunctionContextData } from "@gelatonetwork/web3-functions-sdk";
import { Web3FunctionLoader } from "@gelatonetwork/web3-functions-sdk/loader";
import { GelatoRelay } from "@gelatonetwork/relay-sdk";
import { runWeb3Function } from "./run";
import { BigNumber, providers } from "ethers";
import { runWeb3Function } from "./run";

// Mock and spy on Relay SDK sponsoredCall method
const mockImpl: typeof GelatoRelay.prototype.sponsoredCall = async () => {
Expand Down Expand Up @@ -47,6 +43,19 @@ describe("delay-dispatch web3 function", () => {
sponsoredCallSpy.mockClear();
});

let timeDelta = 0;
const now = Date.now;
const setTimeTo = (millis: number) => {
timeDelta = Date.now() - millis;
};

beforeAll(() => {
jest.spyOn(Date, "now").mockImplementation(() => now() - timeDelta);
});
afterEach(() => {
timeDelta = 0;
});

it("throws if the secret or a userArg is not set", async () => {
await expect(
runWeb3Function({ userArgs, secrets: {}, provider })
Expand Down Expand Up @@ -88,9 +97,7 @@ describe("delay-dispatch web3 function", () => {

it("skips over expired transactions to execute executable transactions", async () => {
const timeFirstTxIsExpired = QUEUE[0].createdAt + COOLDOWN + EXPIRATION + 1;
jest
.spyOn(Date, "now")
.mockImplementation(() => timeFirstTxIsExpired * 1000);
setTimeTo(timeFirstTxIsExpired * 1000);

const result = await runWeb3Function({ userArgs, provider });
expect(result).toEqual({ canExec: true, callData: [] });
Expand All @@ -105,9 +112,7 @@ describe("delay-dispatch web3 function", () => {

it("respects the gas allowance", async () => {
const timeFirstTxIsExpired = QUEUE[0].createdAt + COOLDOWN + EXPIRATION + 1;
jest
.spyOn(Date, "now")
.mockImplementation(() => timeFirstTxIsExpired * 1000);
setTimeTo(timeFirstTxIsExpired * 1000);

const result = await runWeb3Function({
userArgs: { ...userArgs, gasAllowance: 300_000 }, // since we hard-code the gas to 123_000, this should only execute 2 txs, but not 3
Expand All @@ -120,9 +125,7 @@ describe("delay-dispatch web3 function", () => {

it("returns `canExec: false` if nothing has been relayed", async () => {
const timeFirstTxIsExpired = QUEUE[0].createdAt + COOLDOWN + EXPIRATION + 1;
jest
.spyOn(Date, "now")
.mockImplementation(() => timeFirstTxIsExpired * 1000);
setTimeTo(timeFirstTxIsExpired * 1000);

const result = await runWeb3Function({
userArgs: { ...userArgs, gasAllowance: 10 }, // not enough for making a single call
Expand Down
2 changes: 1 addition & 1 deletion packages/subgraph/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@
"@graphprotocol/graph-ts": "^0.31.0",
"assemblyscript-json": "^1.1.0"
}
}
}
22 changes: 20 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6041,6 +6041,23 @@ __metadata:
languageName: node
linkType: hard

"ethers-multicall-provider@npm:3.1.2":
version: 3.1.2
resolution: "ethers-multicall-provider@npm:3.1.2"
dependencies:
"@ethersproject/abi": ^5.7.0
"@ethersproject/providers": ^5.7.2
ethers: ^5.0.0
lodash: ^4.17.0
peerDependencies:
"@ethersproject/abi": ^5.7.0
"@ethersproject/providers": ^5.7.2
ethers: ^5.0.0
lodash: ^4.17.0
checksum: 06932858ff0c835d731081513338586d4e78a12568bf5c1ac4972b7c72ac2fe6223c8ba4a96b21757fe2ee9fb6465179e24bc799863eb507b0c7025527308c83
languageName: node
linkType: hard

"ethers@npm:6.7.0":
version: 6.7.0
resolution: "ethers@npm:6.7.0"
Expand All @@ -6056,7 +6073,7 @@ __metadata:
languageName: node
linkType: hard

"ethers@npm:^5.4.6, ethers@npm:^5.7.2":
"ethers@npm:^5.0.0, ethers@npm:^5.4.6, ethers@npm:^5.7.2":
version: 5.7.2
resolution: "ethers@npm:5.7.2"
dependencies:
Expand Down Expand Up @@ -9332,7 +9349,7 @@ __metadata:
languageName: node
linkType: hard

"lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.21":
"lodash@npm:^4.17.0, lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.21":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
Expand Down Expand Up @@ -13687,6 +13704,7 @@ __metadata:
"@typescript-eslint/eslint-plugin": ^5.40.0
"@typescript-eslint/parser": ^5.6.0
ethers: ^5.7.2
ethers-multicall-provider: 3.1.2
jest: ^29.4.2
jest-environment-node: ^29.4.2
ky: ^1.1.0
Expand Down

0 comments on commit cdf331a

Please sign in to comment.