diff --git a/packages/monitor-v2/src/bot-oo/SettleOOv1Requests.ts b/packages/monitor-v2/src/bot-oo/SettleOOv1Requests.ts index ca4bf4eb3f..5eb8a09111 100644 --- a/packages/monitor-v2/src/bot-oo/SettleOOv1Requests.ts +++ b/packages/monitor-v2/src/bot-oo/SettleOOv1Requests.ts @@ -9,8 +9,13 @@ import { tryHexToUtf8String } from "../utils/contracts"; import { logSettleRequest } from "./BotLogger"; import { getContractInstanceWithProvider, Logger, MonitoringParams, OptimisticOracleEthers } from "./common"; import { requestKey } from "./requestKey"; +import type { GasEstimator } from "@uma/financial-templates-lib"; -export async function settleOOv1Requests(logger: typeof Logger, params: MonitoringParams): Promise { +export async function settleOOv1Requests( + logger: typeof Logger, + params: MonitoringParams, + gasEstimator: GasEstimator +): Promise { const oov1 = await getContractInstanceWithProvider("OptimisticOracle", params.provider); // Override with the test contract address const oov1WithAddress = oov1.attach(params.contractAddress); @@ -103,7 +108,7 @@ export async function settleOOv1Requests(logger: typeof Logger, params: Monitori req.args.identifier, req.args.timestamp, req.args.ancillaryData, - { gasLimit: gasLimitOverride } + { ...gasEstimator.getCurrentFastPriceEthers(), gasLimit: gasLimitOverride } ); const receipt = await tx.wait(); const event = receipt.events?.find((e) => e.event === "Settle"); diff --git a/packages/monitor-v2/src/bot-oo/SettleOOv2Requests.ts b/packages/monitor-v2/src/bot-oo/SettleOOv2Requests.ts index f8a424b117..06ca4a7f64 100644 --- a/packages/monitor-v2/src/bot-oo/SettleOOv2Requests.ts +++ b/packages/monitor-v2/src/bot-oo/SettleOOv2Requests.ts @@ -8,8 +8,13 @@ import { computeEventSearch } from "../bot-utils/events"; import { logSettleRequest } from "./BotLogger"; import { getContractInstanceWithProvider, Logger, MonitoringParams, OptimisticOracleV2Ethers } from "./common"; import { requestKey } from "./requestKey"; +import type { GasEstimator } from "@uma/financial-templates-lib"; -export async function settleOOv2Requests(logger: typeof Logger, params: MonitoringParams): Promise { +export async function settleOOv2Requests( + logger: typeof Logger, + params: MonitoringParams, + gasEstimator: GasEstimator +): Promise { const oo = await getContractInstanceWithProvider( "OptimisticOracleV2", params.provider, @@ -77,7 +82,7 @@ export async function settleOOv2Requests(logger: typeof Logger, params: Monitori req.args.identifier, req.args.timestamp, req.args.ancillaryData, - { gasLimit: gasLimitOverride } + { ...gasEstimator.getCurrentFastPriceEthers(), gasLimit: gasLimitOverride } ); const receipt = await tx.wait(); const event = receipt.events?.find((e) => e.event === "Settle"); diff --git a/packages/monitor-v2/src/bot-oo/SettleRequests.ts b/packages/monitor-v2/src/bot-oo/SettleRequests.ts index 1e2418f59e..f3e31469e2 100644 --- a/packages/monitor-v2/src/bot-oo/SettleRequests.ts +++ b/packages/monitor-v2/src/bot-oo/SettleRequests.ts @@ -2,8 +2,13 @@ import { Logger, MonitoringParams } from "./common"; import { settleOOv1Requests } from "./SettleOOv1Requests"; import { settleSkinnyOORequests } from "./SettleSkinnyOORequests"; import { settleOOv2Requests } from "./SettleOOv2Requests"; +import type { GasEstimator } from "@uma/financial-templates-lib"; -export async function settleRequests(logger: typeof Logger, params: MonitoringParams): Promise { +export async function settleRequests( + logger: typeof Logger, + params: MonitoringParams, + gasEstimator: GasEstimator +): Promise { logger.debug({ at: "OracleBot", message: `Starting settlement for ${params.oracleType}`, @@ -13,11 +18,11 @@ export async function settleRequests(logger: typeof Logger, params: MonitoringPa switch (params.oracleType) { case "OptimisticOracle": - return settleOOv1Requests(logger, params); + return settleOOv1Requests(logger, params, gasEstimator); case "SkinnyOptimisticOracle": - return settleSkinnyOORequests(logger, params); + return settleSkinnyOORequests(logger, params, gasEstimator); case "OptimisticOracleV2": - return settleOOv2Requests(logger, params); + return settleOOv2Requests(logger, params, gasEstimator); default: throw new Error(`Unsupported oracle type: ${params.oracleType}`); } diff --git a/packages/monitor-v2/src/bot-oo/SettleSkinnyOORequests.ts b/packages/monitor-v2/src/bot-oo/SettleSkinnyOORequests.ts index 60006181d5..fb057fc0f2 100644 --- a/packages/monitor-v2/src/bot-oo/SettleSkinnyOORequests.ts +++ b/packages/monitor-v2/src/bot-oo/SettleSkinnyOORequests.ts @@ -10,6 +10,7 @@ import { tryHexToUtf8String } from "../utils/contracts"; import { logSettleRequest } from "./BotLogger"; import { getContractInstanceWithProvider, Logger, MonitoringParams, SkinnyOptimisticOracleEthers } from "./common"; import { requestKey } from "./requestKey"; +import type { GasEstimator } from "@uma/financial-templates-lib"; const toRequestKeyArgs = (args: ProposePriceEvent["args"] | DisputePriceEvent["args"] | SettleEvent["args"]) => ({ requester: args.requester, @@ -18,7 +19,11 @@ const toRequestKeyArgs = (args: ProposePriceEvent["args"] | DisputePriceEvent["a ancillaryData: args.ancillaryData, }); -export async function settleSkinnyOORequests(logger: typeof Logger, params: MonitoringParams): Promise { +export async function settleSkinnyOORequests( + logger: typeof Logger, + params: MonitoringParams, + gasEstimator: GasEstimator +): Promise { const skinnyOO = await getContractInstanceWithProvider( "SkinnyOptimisticOracle", params.provider @@ -190,7 +195,7 @@ export async function settleSkinnyOORequests(logger: typeof Logger, params: Moni bond: request.bond, customLiveness: request.customLiveness, }, - { gasLimit: gasLimitOverride } + { ...gasEstimator.getCurrentFastPriceEthers(), gasLimit: gasLimitOverride } ); const receipt = await tx.wait(); const event = receipt.events?.find((e) => e.event === "Settle"); diff --git a/packages/monitor-v2/src/bot-oo/index.ts b/packages/monitor-v2/src/bot-oo/index.ts index 1fff49d5df..1906b64914 100644 --- a/packages/monitor-v2/src/bot-oo/index.ts +++ b/packages/monitor-v2/src/bot-oo/index.ts @@ -1,4 +1,4 @@ -import { delay, waitForLogger } from "@uma/financial-templates-lib"; +import { delay, waitForLogger, GasEstimator } from "@uma/financial-templates-lib"; import { BotModes, initMonitoringParams, Logger, startupLogLevel } from "./common"; import { settleRequests } from "./SettleRequests"; @@ -15,14 +15,18 @@ async function main() { botModes: params.botModes, }); + const gasEstimator = new GasEstimator(logger, undefined, params.chainId, params.provider); + const cmds = { settleRequestsEnabled: settleRequests, }; for (;;) { + await gasEstimator.update(); + const runCmds = Object.entries(cmds) .filter(([mode]) => params.botModes[mode as keyof BotModes]) - .map(([, cmd]) => cmd(logger, { ...params })); + .map(([, cmd]) => cmd(logger, { ...params }, gasEstimator)); await Promise.all(runCmds); diff --git a/packages/monitor-v2/test/OptimisticOracleV1Bot.ts b/packages/monitor-v2/test/OptimisticOracleV1Bot.ts index 0d03a9e928..0ba198ee9c 100644 --- a/packages/monitor-v2/test/OptimisticOracleV1Bot.ts +++ b/packages/monitor-v2/test/OptimisticOracleV1Bot.ts @@ -1,6 +1,6 @@ import "@nomiclabs/hardhat-ethers"; import { ExpandedERC20Ethers, MockOracleAncillaryEthers, TimerEthers } from "@uma/contracts-node"; -import { spyLogIncludes, spyLogLevel } from "@uma/financial-templates-lib"; +import { spyLogIncludes, spyLogLevel, GasEstimator } from "@uma/financial-templates-lib"; import { assert } from "chai"; import { OracleType } from "../src/bot-oo/common"; import { settleRequests } from "../src/bot-oo/SettleRequests"; @@ -25,9 +25,18 @@ describe("OptimisticOracleV1Bot", function () { let proposer: Signer; let disputer: Signer; let mockOracle: MockOracleAncillaryEthers; + let gasEstimator: GasEstimator; const ancillaryData = toUtf8Bytes("This is just a test question"); + before(async function () { + // Create a single GasEstimator for this file using the global provider/chainId + const { logger } = makeSpyLogger(); + const network = await ethers.provider.getNetwork(); + gasEstimator = new GasEstimator(logger, undefined, network.chainId, ethers.provider); + await gasEstimator.update(); + }); + beforeEach(async function () { [requester, proposer, disputer] = (await ethers.getSigners()) as Signer[]; @@ -75,8 +84,9 @@ describe("OptimisticOracleV1Bot", function () { await advanceTimerPastLiveness(timer, proposeReceipt.blockNumber!, defaultLiveness); const { spy, logger } = makeSpyLogger(); - - await settleRequests(logger, await createParams("OptimisticOracle", optimisticOracleV1.address)); + const params = await createParams("OptimisticOracle", optimisticOracleV1.address); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); const settledIndex = spy .getCalls() @@ -91,7 +101,11 @@ describe("OptimisticOracleV1Bot", function () { // Subsequent run should produce no settlement logs (but may have debug logs). spy.resetHistory(); - await settleRequests(logger, await createParams("OptimisticOracle", optimisticOracleV1.address)); + { + const params2 = await createParams("OptimisticOracle", optimisticOracleV1.address); + await gasEstimator.update(); + await settleRequests(logger, params2, gasEstimator); + } // Check that no settlement warning logs were generated const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); @@ -122,7 +136,9 @@ describe("OptimisticOracleV1Bot", function () { ).wait(); const { spy, logger } = makeSpyLogger(); - await settleRequests(logger, await createParams("OptimisticOracle", optimisticOracleV1.address)); + const params = await createParams("OptimisticOracle", optimisticOracleV1.address); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); // Check that no settlement warning logs were generated (but debug logs are OK). const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); @@ -172,7 +188,11 @@ describe("OptimisticOracleV1Bot", function () { const { spy, logger } = makeSpyLogger(); - await settleRequests(logger, await createParams("OptimisticOracle", optimisticOracleV1.address)); + { + const params2 = await createParams("OptimisticOracle", optimisticOracleV1.address); + await gasEstimator.update(); + await settleRequests(logger, params2, gasEstimator); + } const settledIndex = spy .getCalls() @@ -187,7 +207,11 @@ describe("OptimisticOracleV1Bot", function () { // No additional settlement logs on subsequent run spy.resetHistory(); - await settleRequests(logger, await createParams("OptimisticOracle", optimisticOracleV1.address)); + { + const params3 = await createParams("OptimisticOracle", optimisticOracleV1.address); + await gasEstimator.update(); + await settleRequests(logger, params3, gasEstimator); + } const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); assert.equal(settlementLogs.length, 0, "No settlement logs should be generated on subsequent runs"); }); diff --git a/packages/monitor-v2/test/OptimisticOracleV2Bot.ts b/packages/monitor-v2/test/OptimisticOracleV2Bot.ts index 3dce80acea..cfee45628e 100644 --- a/packages/monitor-v2/test/OptimisticOracleV2Bot.ts +++ b/packages/monitor-v2/test/OptimisticOracleV2Bot.ts @@ -5,7 +5,7 @@ import { OptimisticOracleV2Ethers, TimerEthers, } from "@uma/contracts-node"; -import { spyLogIncludes, spyLogLevel } from "@uma/financial-templates-lib"; +import { spyLogIncludes, spyLogLevel, GasEstimator } from "@uma/financial-templates-lib"; import { assert } from "chai"; import { OracleType } from "../src/bot-oo/common"; import { settleRequests } from "../src/bot-oo/SettleRequests"; @@ -30,6 +30,7 @@ describe("OptimisticOracleV2Bot", function () { let proposer: Signer; let disputer: Signer; let mockOracle: MockOracleAncillaryEthers; + let gasEstimator: GasEstimator; const ancillaryData = toUtf8Bytes("This is just a test question"); @@ -53,6 +54,13 @@ describe("OptimisticOracleV2Bot", function () { await bondToken.connect(disputer).approve(optimisticOracleV2.address, bond); }); + before(async function () { + const { logger } = makeSpyLogger(); + const network = await ethers.provider.getNetwork(); + gasEstimator = new GasEstimator(logger, undefined, network.chainId, ethers.provider); + await gasEstimator.update(); + }); + it("Settle price request happy path", async function () { await ( await optimisticOracleV2.requestPrice(defaultOptimisticOracleV2Identifier, 0, ancillaryData, bondToken.address, 0) @@ -74,8 +82,9 @@ describe("OptimisticOracleV2Bot", function () { await advanceTimerPastLiveness(timer, proposeReceipt.blockNumber!, defaultLiveness); const { spy, logger } = makeSpyLogger(); - - await settleRequests(logger, await createParams("OptimisticOracleV2", optimisticOracleV2.address)); + const params = await createParams("OptimisticOracleV2", optimisticOracleV2.address); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); const settledIndex = spy .getCalls() @@ -90,7 +99,11 @@ describe("OptimisticOracleV2Bot", function () { // Subsequent run should produce no settlement logs (but may have debug logs). spy.resetHistory(); - await settleRequests(logger, await createParams("OptimisticOracleV2", optimisticOracleV2.address)); + { + const params2 = await createParams("OptimisticOracleV2", optimisticOracleV2.address); + await gasEstimator.update(); + await settleRequests(logger, params2, gasEstimator); + } // Check that no settlement warning logs were generated const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); @@ -115,7 +128,9 @@ describe("OptimisticOracleV2Bot", function () { ).wait(); const { spy, logger } = makeSpyLogger(); - await settleRequests(logger, await createParams("OptimisticOracleV2", optimisticOracleV2.address)); + const params = await createParams("OptimisticOracleV2", optimisticOracleV2.address); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); // Check that no settlement warning logs were generated (but debug logs are OK). const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); @@ -153,8 +168,9 @@ describe("OptimisticOracleV2Bot", function () { ).wait(); const { spy, logger } = makeSpyLogger(); - - await settleRequests(logger, await createParams("OptimisticOracleV2", optimisticOracleV2.address)); + const params = await createParams("OptimisticOracleV2", optimisticOracleV2.address); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); const settledIndex = spy .getCalls() @@ -169,7 +185,11 @@ describe("OptimisticOracleV2Bot", function () { // No additional settlement logs on subsequent run spy.resetHistory(); - await settleRequests(logger, await createParams("OptimisticOracleV2", optimisticOracleV2.address)); + { + const params2 = await createParams("OptimisticOracleV2", optimisticOracleV2.address); + await gasEstimator.update(); + await settleRequests(logger, params2, gasEstimator); + } const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); assert.equal(settlementLogs.length, 0, "No settlement logs should be generated on subsequent runs"); }); diff --git a/packages/monitor-v2/test/SkinnyOptimisticOracleBot.ts b/packages/monitor-v2/test/SkinnyOptimisticOracleBot.ts index a735a4bca9..72ff4afcc5 100644 --- a/packages/monitor-v2/test/SkinnyOptimisticOracleBot.ts +++ b/packages/monitor-v2/test/SkinnyOptimisticOracleBot.ts @@ -1,6 +1,6 @@ import "@nomiclabs/hardhat-ethers"; import { ExpandedERC20Ethers, MockOracleAncillaryEthers, TimerEthers } from "@uma/contracts-node"; -import { spyLogIncludes, spyLogLevel } from "@uma/financial-templates-lib"; +import { spyLogIncludes, spyLogLevel, GasEstimator } from "@uma/financial-templates-lib"; import { assert } from "chai"; import { OracleType } from "../src/bot-oo/common"; import { settleRequests } from "../src/bot-oo/SettleRequests"; @@ -25,6 +25,7 @@ describe("SkinnyOptimisticOracleBot", function () { let proposer: Signer; let disputer: Signer; let mockOracle: MockOracleAncillaryEthers; + let gasEstimator: GasEstimator; const ancillaryData = toUtf8Bytes("This is just a test question"); @@ -48,6 +49,13 @@ describe("SkinnyOptimisticOracleBot", function () { await bondToken.connect(disputer).approve(skinnyOptimisticOracle.address, bond); }); + before(async function () { + const { logger } = makeSpyLogger(); + const network = await ethers.provider.getNetwork(); + gasEstimator = new GasEstimator(logger, undefined, network.chainId, ethers.provider); + await gasEstimator.update(); + }); + it("Settle price request happy path", async function () { // SkinnyOptimisticOracle uses 32-bit timestamps - use blockchain time const timestamp = (await timer.getCurrentTime()).toNumber(); @@ -97,8 +105,9 @@ describe("SkinnyOptimisticOracleBot", function () { await advanceTimerPastLiveness(timer, proposeReceipt.blockNumber!, defaultLiveness); const { spy, logger } = makeSpyLogger(); - - await settleRequests(logger, await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address)); + const params = await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); const settledIndex = spy .getCalls() @@ -113,7 +122,11 @@ describe("SkinnyOptimisticOracleBot", function () { // Subsequent run should produce no settlement logs (but may have debug logs). spy.resetHistory(); - await settleRequests(logger, await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address)); + await settleRequests( + logger, + await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address), + new GasEstimator(logger) + ); // Check that no settlement warning logs were generated const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); @@ -164,7 +177,9 @@ describe("SkinnyOptimisticOracleBot", function () { ).wait(); const { spy, logger } = makeSpyLogger(); - await settleRequests(logger, await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address)); + const params = await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); // Check that no settlement warning logs were generated (but debug logs are OK). const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); @@ -238,8 +253,9 @@ describe("SkinnyOptimisticOracleBot", function () { ).wait(); const { spy, logger } = makeSpyLogger(); - - await settleRequests(logger, await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address)); + const params = await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); const settledIndex = spy .getCalls() @@ -254,7 +270,11 @@ describe("SkinnyOptimisticOracleBot", function () { // No additional settlement logs on subsequent run spy.resetHistory(); - await settleRequests(logger, await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address)); + { + const params2 = await createParams("SkinnyOptimisticOracle", skinnyOptimisticOracle.address); + await gasEstimator.update(); + await settleRequests(logger, params2, gasEstimator); + } const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); assert.equal(settlementLogs.length, 0, "No settlement logs should be generated on subsequent runs"); });