From 85fc0e047af26ac260afec7ff632cbd450a9fd05 Mon Sep 17 00:00:00 2001 From: Pablo Maldonado Date: Mon, 1 Jun 2026 15:06:53 +0000 Subject: [PATCH 1/3] feat(bot-oo): add include/exclude proposal lists to OOv2 settler Adds SETTLE_INCLUDE_LIST and SETTLE_EXCLUDE_LIST env vars to the unified OO settlement bot, scoped to OptimisticOracleV2. Proposals are matched by their ProposePrice event identifier (:). When an include list is set the bot settles only those proposals (takes precedence over the exclude list); otherwise proposals in the exclude list are skipped. --- packages/monitor-v2/src/bot-oo/README.md | 2 + .../src/bot-oo/SettleOOv2Requests.ts | 39 ++++++++- packages/monitor-v2/src/bot-oo/common.ts | 38 +++++++++ packages/monitor-v2/src/bot-oo/requestKey.ts | 5 ++ .../monitor-v2/test/OptimisticOracleV2Bot.ts | 80 +++++++++++++++++++ 5 files changed, 162 insertions(+), 2 deletions(-) diff --git a/packages/monitor-v2/src/bot-oo/README.md b/packages/monitor-v2/src/bot-oo/README.md index 9a655f7616..38d4a13f56 100644 --- a/packages/monitor-v2/src/bot-oo/README.md +++ b/packages/monitor-v2/src/bot-oo/README.md @@ -36,6 +36,8 @@ node ./packages/monitor-v2/dist/bot-oo/index.js - `SETTLE_MIN_PROPOSAL_AGE_SECONDS`: Minimum proposal age in seconds before settling OOv2 requests (default `8100`, set `0` to disable). - `SETTLE_TIMEOUT`: Timeout in seconds for submitting settlement transactions in serverless mode (default `240`). - `SETTLE_ONLY_DISPUTED`: When `true`, only settle requests that have been disputed (`false` by default). Supported for `OptimisticOracleV2` (including `ManagedOptimisticOracleV2`); ignored for `OptimisticOracle` and `SkinnyOptimisticOracle`. +- `SETTLE_INCLUDE_LIST`: JSON array of `":"` proposal identifiers (the transaction hash and log index of the `ProposePrice` event). When set, the bot settles **only** these proposals. Takes precedence over `SETTLE_EXCLUDE_LIST`. `OptimisticOracleV2` only. Example: `["0xabc...def:5"]`. +- `SETTLE_EXCLUDE_LIST`: JSON array of `":"` proposal identifiers to **skip**. Ignored when `SETTLE_INCLUDE_LIST` is set. `OptimisticOracleV2` only. ## Behavior diff --git a/packages/monitor-v2/src/bot-oo/SettleOOv2Requests.ts b/packages/monitor-v2/src/bot-oo/SettleOOv2Requests.ts index 8458dc1688..dd4da88946 100644 --- a/packages/monitor-v2/src/bot-oo/SettleOOv2Requests.ts +++ b/packages/monitor-v2/src/bot-oo/SettleOOv2Requests.ts @@ -7,7 +7,7 @@ import { ethers } from "ethers"; import { computeEventSearch } from "../bot-utils/events"; import { logSettleRequest } from "./BotLogger"; import { getContractInstanceWithProvider, Logger, MonitoringParams, OptimisticOracleV2Ethers } from "./common"; -import { requestKey } from "./requestKey"; +import { proposalEventId, requestKey } from "./requestKey"; import type { GasEstimator } from "@uma/financial-templates-lib"; import { getSettleTxErrorLogFields, getSettleTxErrorLogLevel } from "../bot-utils/errors"; @@ -21,6 +21,39 @@ function chunk(arr: T[], size: number): T[][] { return chunks; } +// Applies the include/exclude proposal lists. The include list is exclusive and takes precedence: when set, only its +// proposals are settled. Otherwise proposals in the exclude list are skipped. Proposals are matched by the +// transaction hash and log index of their ProposePrice event. +function filterByIncludeExclude( + logger: typeof Logger, + params: MonitoringParams, + requests: ProposePriceEvent[] +): ProposePriceEvent[] { + const { settleIncludeList, settleExcludeList } = params; + if (!settleIncludeList && !settleExcludeList) return requests; + + const kept: ProposePriceEvent[] = []; + const skipped: string[] = []; + for (const req of requests) { + const id = proposalEventId(req.transactionHash, req.logIndex); + const allowed = settleIncludeList ? settleIncludeList.has(id) : !settleExcludeList?.has(id); + if (allowed) kept.push(req); + else skipped.push(id); + } + + logger.debug({ + at: "OOv2Bot", + message: "Applied include/exclude proposal filter", + mode: settleIncludeList ? "include" : "exclude", + listSize: (settleIncludeList ?? settleExcludeList)?.size, + kept: kept.length, + skipped: skipped.length, + skippedIds: skipped, + }); + + return kept; +} + export async function settleOOv2Requests( logger: typeof Logger, params: MonitoringParams, @@ -99,7 +132,9 @@ export async function settleOOv2Requests( const settledKeys = new Set(settlements.map((e) => requestKey(e.args))); - const requestsToSettle = proposals.filter((e) => !settledKeys.has(requestKey(e.args))); + const unsettledRequests = proposals.filter((e) => !settledKeys.has(requestKey(e.args))); + + const requestsToSettle = filterByIncludeExclude(logger, params, unsettledRequests); const requestsToSettleTxCount = params.settleBatchSize > 1 ? Math.ceil(requestsToSettle.length / params.settleBatchSize) : requestsToSettle.length; diff --git a/packages/monitor-v2/src/bot-oo/common.ts b/packages/monitor-v2/src/bot-oo/common.ts index faf1ca56d2..7f3f6f61db 100644 --- a/packages/monitor-v2/src/bot-oo/common.ts +++ b/packages/monitor-v2/src/bot-oo/common.ts @@ -3,17 +3,45 @@ export { Logger } from "@uma/financial-templates-lib"; export { computeEventSearch } from "../bot-utils/events"; export { getContractInstanceWithProvider } from "../utils/contracts"; import { BaseMonitoringParams, startupLogLevel as baseStartup, initBaseMonitoringParams } from "../bot-utils/base"; +import { proposalEventId } from "./requestKey"; export type OracleType = "OptimisticOracle" | "SkinnyOptimisticOracle" | "OptimisticOracleV2"; const DEFAULT_SETTLE_MIN_PROPOSAL_AGE_SECONDS = 2 * 60 * 60 + 15 * 60; +const PROPOSAL_ID_REGEX = /^(0x[0-9a-fA-F]{64}):(\d+)$/; + function getNonNegativeNumber(value: string | undefined, defaultValue: number): number { if (value === undefined) return defaultValue; const parsed = Number(value); return Number.isFinite(parsed) ? Math.max(0, parsed) : defaultValue; } +// Parses a JSON array of ":" strings into a normalized set of proposal event ids. +// Returns undefined when the env var is unset/empty so the bot keeps its default (settle everything) behavior. +function parseProposalIdList(value: string | undefined, envName: string): Set | undefined { + if (value === undefined || value.trim() === "") return undefined; + + let parsed: unknown; + try { + parsed = JSON.parse(value); + } catch { + throw new Error(`${envName} must be a JSON array of ":" strings`); + } + if (!Array.isArray(parsed) || parsed.length === 0) { + throw new Error(`${envName} must be a non-empty JSON array of ":" strings`); + } + + const ids = parsed.map((entry) => { + if (typeof entry !== "string") throw new Error(`${envName} entries must be ":" strings`); + const match = entry.match(PROPOSAL_ID_REGEX); + if (!match) throw new Error(`Invalid ${envName} entry "${entry}"; expected ":"`); + return proposalEventId(match[1], Number(match[2])); + }); + + return new Set(ids); +} + export interface BotModes { settleRequestsEnabled: boolean; settleOnlyDisputed: boolean; // Supported for OptimisticOracleV2 (incl. ManagedOOv2); ignored for OOv1 and SkinnyOO. @@ -27,6 +55,11 @@ export interface MonitoringParams extends BaseMonitoringParams { executionDeadline?: number; // Timestamp in sec for when to stop settling, defaults to 4 minutes from now in serverless settleBatchSize: number; // Number of settle calls to batch via multicall (requires MultiCaller on contract), defaults to 1 settleMinProposalAgeSeconds: number; // Minimum proposal age before settlement, defaults to 2h15m + // Include/exclude lists of proposal event ids (":"). OptimisticOracleV2 only. + // When settleIncludeList is set, only those proposals are settled (it takes precedence over the exclude list). + // Otherwise, proposals in settleExcludeList are skipped. Both undefined means settle everything (default). + settleIncludeList?: Set; + settleExcludeList?: Set; } export const initMonitoringParams = async (env: NodeJS.ProcessEnv): Promise => { @@ -65,6 +98,9 @@ export const initMonitoringParams = async (env: NodeJS.ProcessEnv): Promise [args.requester, args.identifier, args.timestamp, args.ancillaryData] ) ); + +// Identifies a proposal by the transaction hash and log index of its ProposePrice event. This is the +// identifier used by the include/exclude settlement lists (matches how proposals are referenced in the explorer). +export const proposalEventId = (transactionHash: string, logIndex: number): string => + `${transactionHash.toLowerCase()}:${logIndex}`; diff --git a/packages/monitor-v2/test/OptimisticOracleV2Bot.ts b/packages/monitor-v2/test/OptimisticOracleV2Bot.ts index e65a7b7d24..8fb0b28afa 100644 --- a/packages/monitor-v2/test/OptimisticOracleV2Bot.ts +++ b/packages/monitor-v2/test/OptimisticOracleV2Bot.ts @@ -8,6 +8,7 @@ import { import { spyLogIncludes, spyLogLevel, GasEstimator } from "@uma/financial-templates-lib"; import { assert } from "chai"; import { OracleType } from "../src/bot-oo/common"; +import { proposalEventId } from "../src/bot-oo/requestKey"; import { settleRequests } from "../src/bot-oo/SettleRequests"; import { defaultLiveness, defaultOptimisticOracleV2Identifier } from "./constants"; import { optimisticOracleV2Fixture } from "./fixtures/OptimisticOracleV2.Fixture"; @@ -36,6 +37,12 @@ const getLast = (items: T[], message: string) => { return item; }; +const getProposalEventId = (receipt: { events?: { event?: string; transactionHash: string; logIndex: number }[] }) => { + const event = receipt.events?.find((e) => e.event === "ProposePrice"); + if (event === undefined) throw new Error("Expected a ProposePrice event in the receipt"); + return proposalEventId(event.transactionHash, event.logIndex); +}; + describe("OptimisticOracleV2Bot", function () { let bondToken: ExpandedERC20Ethers; let optimisticOracleV2: OptimisticOracleV2Ethers; @@ -473,4 +480,77 @@ describe("OptimisticOracleV2Bot", function () { .findIndex((c) => c.lastArg?.message === "Price Request Settled ✅" && c.lastArg?.at === "OOv2Bot"); assert.isAbove(settledIndex, -1, "Disputed request should be settled when settleOnlyDisputed is true"); }); + + it("Skips proposals in the exclude list", async function () { + await ( + await optimisticOracleV2.requestPrice(defaultOptimisticOracleV2Identifier, 0, ancillaryData, bondToken.address, 0) + ).wait(); + + const proposeReceipt = await ( + await optimisticOracleV2 + .connect(proposer) + .proposePrice( + await requester.getAddress(), + defaultOptimisticOracleV2Identifier, + 0, + ancillaryData, + ethers.utils.parseEther("1") + ) + ).wait(); + + await advanceTimerPastLiveness(timer, getReceiptBlockNumber(proposeReceipt), defaultLiveness); + + const { spy, logger } = makeSpyLogger(); + const params = await createParams("OptimisticOracleV2", optimisticOracleV2.address); + params.settleExcludeList = new Set([getProposalEventId(proposeReceipt)]); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); + + const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); + assert.equal(settlementLogs.length, 0, "Excluded proposal should not be settled"); + }); + + it("Settles only proposals in the include list", async function () { + await ( + await optimisticOracleV2.requestPrice(defaultOptimisticOracleV2Identifier, 0, ancillaryData, bondToken.address, 0) + ).wait(); + + const proposeReceipt = await ( + await optimisticOracleV2 + .connect(proposer) + .proposePrice( + await requester.getAddress(), + defaultOptimisticOracleV2Identifier, + 0, + ancillaryData, + ethers.utils.parseEther("1") + ) + ).wait(); + + await advanceTimerPastLiveness(timer, getReceiptBlockNumber(proposeReceipt), defaultLiveness); + + // An include list that does not contain the proposal: nothing settles. + { + const { spy, logger } = makeSpyLogger(); + const params = await createParams("OptimisticOracleV2", optimisticOracleV2.address); + params.settleIncludeList = new Set([proposalEventId(`0x${"0".repeat(64)}`, 0)]); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); + + const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); + assert.equal(settlementLogs.length, 0, "Proposal absent from the include list should not be settled"); + } + + // An include list containing the proposal: it settles. + { + const { spy, logger } = makeSpyLogger(); + const params = await createParams("OptimisticOracleV2", optimisticOracleV2.address); + params.settleIncludeList = new Set([getProposalEventId(proposeReceipt)]); + await gasEstimator.update(); + await settleRequests(logger, params, gasEstimator); + + const settlementLogs = spy.getCalls().filter((call) => call.lastArg?.message === "Price Request Settled ✅"); + assert.equal(settlementLogs.length, 1, "Proposal present in the include list should be settled"); + } + }); }); From a397008c0c97c11b23a507cb371850ebd387d5b8 Mon Sep 17 00:00:00 2001 From: Pablo Maldonado Date: Wed, 3 Jun 2026 10:23:58 +0000 Subject: [PATCH 2/3] fix(bot-oo): accept explicit empty settle include/exclude lists An explicit [] no longer throws at startup: an empty exclude list behaves like unset, and an empty include list settles nothing (the include list is exclusive). Matches the OG_WHITELIST/ASSERTION_BLACKLIST convention of accepting empty arrays. --- packages/monitor-v2/src/bot-oo/README.md | 4 ++-- packages/monitor-v2/src/bot-oo/common.ts | 8 +++++--- packages/monitor-v2/test/OptimisticOracleV2Bot.ts | 13 ++++++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/monitor-v2/src/bot-oo/README.md b/packages/monitor-v2/src/bot-oo/README.md index 38d4a13f56..dcf9379554 100644 --- a/packages/monitor-v2/src/bot-oo/README.md +++ b/packages/monitor-v2/src/bot-oo/README.md @@ -36,8 +36,8 @@ node ./packages/monitor-v2/dist/bot-oo/index.js - `SETTLE_MIN_PROPOSAL_AGE_SECONDS`: Minimum proposal age in seconds before settling OOv2 requests (default `8100`, set `0` to disable). - `SETTLE_TIMEOUT`: Timeout in seconds for submitting settlement transactions in serverless mode (default `240`). - `SETTLE_ONLY_DISPUTED`: When `true`, only settle requests that have been disputed (`false` by default). Supported for `OptimisticOracleV2` (including `ManagedOptimisticOracleV2`); ignored for `OptimisticOracle` and `SkinnyOptimisticOracle`. -- `SETTLE_INCLUDE_LIST`: JSON array of `":"` proposal identifiers (the transaction hash and log index of the `ProposePrice` event). When set, the bot settles **only** these proposals. Takes precedence over `SETTLE_EXCLUDE_LIST`. `OptimisticOracleV2` only. Example: `["0xabc...def:5"]`. -- `SETTLE_EXCLUDE_LIST`: JSON array of `":"` proposal identifiers to **skip**. Ignored when `SETTLE_INCLUDE_LIST` is set. `OptimisticOracleV2` only. +- `SETTLE_INCLUDE_LIST`: JSON array of `":"` proposal identifiers (the transaction hash and log index of the `ProposePrice` event). When set, the bot settles **only** these proposals. Takes precedence over `SETTLE_EXCLUDE_LIST`, so an explicit empty array (`[]`) settles **nothing**; leave it unset for default behavior. `OptimisticOracleV2` only. Example: `["0xabc...def:5"]`. +- `SETTLE_EXCLUDE_LIST`: JSON array of `":"` proposal identifiers to **skip**. An empty array (`[]`) behaves the same as unset. Ignored when `SETTLE_INCLUDE_LIST` is set. `OptimisticOracleV2` only. ## Behavior diff --git a/packages/monitor-v2/src/bot-oo/common.ts b/packages/monitor-v2/src/bot-oo/common.ts index 7f3f6f61db..0b008551f9 100644 --- a/packages/monitor-v2/src/bot-oo/common.ts +++ b/packages/monitor-v2/src/bot-oo/common.ts @@ -19,7 +19,9 @@ function getNonNegativeNumber(value: string | undefined, defaultValue: number): // Parses a JSON array of ":" strings into a normalized set of proposal event ids. // Returns undefined when the env var is unset/empty so the bot keeps its default (settle everything) behavior. -function parseProposalIdList(value: string | undefined, envName: string): Set | undefined { +// An explicit empty array is accepted: an empty exclude list behaves like unset, while an empty include list +// means settle nothing (the include list is exclusive). +export function parseProposalIdList(value: string | undefined, envName: string): Set | undefined { if (value === undefined || value.trim() === "") return undefined; let parsed: unknown; @@ -28,8 +30,8 @@ function parseProposalIdList(value: string | undefined, envName: string): Set:" strings`); } - if (!Array.isArray(parsed) || parsed.length === 0) { - throw new Error(`${envName} must be a non-empty JSON array of ":" strings`); + if (!Array.isArray(parsed)) { + throw new Error(`${envName} must be a JSON array of ":" strings`); } const ids = parsed.map((entry) => { diff --git a/packages/monitor-v2/test/OptimisticOracleV2Bot.ts b/packages/monitor-v2/test/OptimisticOracleV2Bot.ts index 8fb0b28afa..9d41ef0326 100644 --- a/packages/monitor-v2/test/OptimisticOracleV2Bot.ts +++ b/packages/monitor-v2/test/OptimisticOracleV2Bot.ts @@ -7,7 +7,7 @@ import { } from "@uma/contracts-node"; import { spyLogIncludes, spyLogLevel, GasEstimator } from "@uma/financial-templates-lib"; import { assert } from "chai"; -import { OracleType } from "../src/bot-oo/common"; +import { OracleType, parseProposalIdList } from "../src/bot-oo/common"; import { proposalEventId } from "../src/bot-oo/requestKey"; import { settleRequests } from "../src/bot-oo/SettleRequests"; import { defaultLiveness, defaultOptimisticOracleV2Identifier } from "./constants"; @@ -553,4 +553,15 @@ describe("OptimisticOracleV2Bot", function () { assert.equal(settlementLogs.length, 1, "Proposal present in the include list should be settled"); } }); + + it("Accepts explicit empty include/exclude lists", async function () { + // Templated deployments commonly render optional list env vars as "[]"; this must not throw. + const includeList = parseProposalIdList("[]", "SETTLE_INCLUDE_LIST"); + assert.instanceOf(includeList, Set); + assert.equal(includeList?.size, 0); + + const excludeList = parseProposalIdList("[]", "SETTLE_EXCLUDE_LIST"); + assert.instanceOf(excludeList, Set); + assert.equal(excludeList?.size, 0); + }); }); From 980c45d20448f9581aeb0848d5b9df1e9d4c5a23 Mon Sep 17 00:00:00 2001 From: Pablo Maldonado Date: Wed, 3 Jun 2026 14:19:18 +0000 Subject: [PATCH 3/3] fix(bot-oo): throw when settle lists are set for non-OOv2 oracle types Only the OOv2 settler applies SETTLE_INCLUDE_LIST/SETTLE_EXCLUDE_LIST; silently ignoring them on OptimisticOracle/SkinnyOptimisticOracle would settle proposals the operator intended to skip, so startup now fails fast instead. --- packages/monitor-v2/src/bot-oo/README.md | 4 ++-- packages/monitor-v2/src/bot-oo/common.ts | 17 +++++++++++++++-- .../monitor-v2/test/OptimisticOracleV2Bot.ts | 14 +++++++++++++- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/monitor-v2/src/bot-oo/README.md b/packages/monitor-v2/src/bot-oo/README.md index dcf9379554..2b250b9e5d 100644 --- a/packages/monitor-v2/src/bot-oo/README.md +++ b/packages/monitor-v2/src/bot-oo/README.md @@ -36,8 +36,8 @@ node ./packages/monitor-v2/dist/bot-oo/index.js - `SETTLE_MIN_PROPOSAL_AGE_SECONDS`: Minimum proposal age in seconds before settling OOv2 requests (default `8100`, set `0` to disable). - `SETTLE_TIMEOUT`: Timeout in seconds for submitting settlement transactions in serverless mode (default `240`). - `SETTLE_ONLY_DISPUTED`: When `true`, only settle requests that have been disputed (`false` by default). Supported for `OptimisticOracleV2` (including `ManagedOptimisticOracleV2`); ignored for `OptimisticOracle` and `SkinnyOptimisticOracle`. -- `SETTLE_INCLUDE_LIST`: JSON array of `":"` proposal identifiers (the transaction hash and log index of the `ProposePrice` event). When set, the bot settles **only** these proposals. Takes precedence over `SETTLE_EXCLUDE_LIST`, so an explicit empty array (`[]`) settles **nothing**; leave it unset for default behavior. `OptimisticOracleV2` only. Example: `["0xabc...def:5"]`. -- `SETTLE_EXCLUDE_LIST`: JSON array of `":"` proposal identifiers to **skip**. An empty array (`[]`) behaves the same as unset. Ignored when `SETTLE_INCLUDE_LIST` is set. `OptimisticOracleV2` only. +- `SETTLE_INCLUDE_LIST`: JSON array of `":"` proposal identifiers (the transaction hash and log index of the `ProposePrice` event). When set, the bot settles **only** these proposals. Takes precedence over `SETTLE_EXCLUDE_LIST`, so an explicit empty array (`[]`) settles **nothing**; leave it unset for default behavior. `OptimisticOracleV2` only — setting it for another `ORACLE_TYPE` throws at startup. Example: `["0xabc...def:5"]`. +- `SETTLE_EXCLUDE_LIST`: JSON array of `":"` proposal identifiers to **skip**. An empty array (`[]`) behaves the same as unset. Ignored when `SETTLE_INCLUDE_LIST` is set. `OptimisticOracleV2` only — setting it for another `ORACLE_TYPE` throws at startup. ## Behavior diff --git a/packages/monitor-v2/src/bot-oo/common.ts b/packages/monitor-v2/src/bot-oo/common.ts index 0b008551f9..b5ad158a8b 100644 --- a/packages/monitor-v2/src/bot-oo/common.ts +++ b/packages/monitor-v2/src/bot-oo/common.ts @@ -44,6 +44,20 @@ export function parseProposalIdList(value: string | undefined, envName: string): return new Set(ids); } +// Parses SETTLE_INCLUDE_LIST/SETTLE_EXCLUDE_LIST and throws when either is set for a non-OOv2 oracle type: +// only the OOv2 settler applies them, so silently ignoring a list would settle proposals the operator +// intended to skip. +export function parseSettleProposalIdLists( + env: NodeJS.ProcessEnv, + oracleType: OracleType +): { settleIncludeList?: Set; settleExcludeList?: Set } { + const settleIncludeList = parseProposalIdList(env.SETTLE_INCLUDE_LIST, "SETTLE_INCLUDE_LIST"); + const settleExcludeList = parseProposalIdList(env.SETTLE_EXCLUDE_LIST, "SETTLE_EXCLUDE_LIST"); + if ((settleIncludeList || settleExcludeList) && oracleType !== "OptimisticOracleV2") + throw new Error("SETTLE_INCLUDE_LIST/SETTLE_EXCLUDE_LIST are only supported for OptimisticOracleV2"); + return { settleIncludeList, settleExcludeList }; +} + export interface BotModes { settleRequestsEnabled: boolean; settleOnlyDisputed: boolean; // Supported for OptimisticOracleV2 (incl. ManagedOOv2); ignored for OOv1 and SkinnyOO. @@ -100,8 +114,7 @@ export const initMonitoringParams = async (env: NodeJS.ProcessEnv): Promise parseSettleProposalIdLists(env, "OptimisticOracle"), /only supported for OptimisticOracleV2/); + assert.throws( + () => parseSettleProposalIdLists(env, "SkinnyOptimisticOracle"), + /only supported for OptimisticOracleV2/ + ); + assert.doesNotThrow(() => parseSettleProposalIdLists(env, "OptimisticOracleV2")); + }); });