Skip to content

Commit 2333faa

Browse files
authored
fix(monitor-v2): ignore disputed requests for alerts (#4813)
Signed-off-by: david <david@umaproject.org>
1 parent f01fdb1 commit 2333faa

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

packages/monitor-v2/src/monitor-polymarket/common.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import { GraphQLClient } from "graphql-request";
99
import { BigNumber, Event, ethers } from "ethers";
1010

1111
import { OptimisticOracleEthers, OptimisticOracleV2Ethers } from "@uma/contracts-node";
12-
import { ProposePriceEvent } from "@uma/contracts-node/dist/packages/contracts-node/typechain/core/ethers/OptimisticOracleV2";
12+
import {
13+
ProposePriceEvent,
14+
DisputePriceEvent,
15+
} from "@uma/contracts-node/dist/packages/contracts-node/typechain/core/ethers/OptimisticOracleV2";
1316
import { getContractInstanceWithProvider } from "../utils/contracts";
1417

1518
import { Logger } from "@uma/financial-templates-lib";
@@ -146,24 +149,50 @@ export const getPolymarketProposedPriceRequestsOO = async (
146149
params.provider
147150
);
148151

149-
const events = await paginatedEventQuery<ProposePriceEvent>(
152+
const proposeEvents = await paginatedEventQuery<ProposePriceEvent>(
150153
oo,
151154
oo.filters.ProposePrice(null, null, null, null, null, null, null, null),
152155
searchConfig
153156
);
154157

158+
const disputeEvents = await paginatedEventQuery<DisputePriceEvent>(
159+
oo,
160+
oo.filters.DisputePrice(null, null, null, null, null, null, null),
161+
searchConfig
162+
);
163+
164+
const disputedRequestIds = new Set(
165+
disputeEvents.map((event) =>
166+
ethers.utils.keccak256(
167+
ethers.utils.defaultAbiCoder.encode(
168+
["address", "bytes32", "uint256", "bytes"],
169+
[event.args.requester, event.args.identifier, event.args.timestamp, event.args.ancillaryData]
170+
)
171+
)
172+
)
173+
);
174+
155175
const currentTime = Math.floor(Date.now() / 1000);
156176
const currentTimeBN = BigNumber.from(currentTime);
157177
const threshold = BigNumber.from(params.checkBeforeExpirationSeconds);
158178

159-
return events
179+
return proposeEvents
160180
.filter((event) => requesterAddresses.map((r) => r.toLowerCase()).includes(event.args.requester.toLowerCase()))
161181
.filter((event) => {
162182
const expirationTime = event.args.expirationTimestamp;
163183
const thresholdTime = expirationTime.sub(threshold);
164184
// Only keep if current time is greater than (expiration - threshold) but less than expiration.
165185
return currentTimeBN.gt(thresholdTime) && currentTimeBN.lt(expirationTime);
166186
})
187+
.filter((event) => {
188+
const requestId = ethers.utils.keccak256(
189+
ethers.utils.defaultAbiCoder.encode(
190+
["address", "bytes32", "uint256", "bytes"],
191+
[event.args.requester, event.args.identifier, event.args.timestamp, event.args.ancillaryData]
192+
)
193+
);
194+
return !disputedRequestIds.has(requestId);
195+
})
167196
.map((event) => {
168197
return {
169198
requestHash: event.transactionHash,

packages/monitor-v2/test/PolymarketMonitor.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -660,12 +660,15 @@ describe("PolymarketNotifier", function () {
660660

661661
describe("getPolymarketProposedPriceRequestsOO Filtering", function () {
662662
it("should return only events that are close enough to expiration (current time > expirationTimestamp - checkBeforeExpirationSeconds)", async function () {
663-
const fakeRequester = "0xFAKE_REQUESTER";
663+
const fakeRequester = "0x0000000000000000000000000000000000000000"; // Address 0
664664
// Set a fixed current time (in seconds)
665665
const fakeTime = 1600000000;
666666
// Stub Date.now() to return fakeTime * 1000
667667
const dateNowStub = sandbox.stub(Date, "now").returns(fakeTime * 1000);
668668

669+
const identifier = formatBytes32String("TEST_IDENTIFIER");
670+
const ancillaryData = formatBytes32String("data");
671+
669672
// Create two fake events:
670673
// Event 1: expires at fakeTime + 100 seconds.
671674
// Calculation: (fakeTime + 100) - 120 = fakeTime - 20, so current time (fakeTime) > fakeTime - 20 => condition satisfied.
@@ -677,8 +680,9 @@ describe("PolymarketNotifier", function () {
677680
requester: fakeRequester,
678681
expirationTimestamp: ethers.BigNumber.from(fakeTime + 100),
679682
timestamp: ethers.BigNumber.from(fakeTime - 50),
680-
ancillaryData: "data",
683+
ancillaryData,
681684
proposedPrice: ethers.BigNumber.from(123),
685+
identifier,
682686
},
683687
};
684688
// Event 2: expires at fakeTime + 200 seconds.
@@ -691,15 +695,21 @@ describe("PolymarketNotifier", function () {
691695
requester: fakeRequester,
692696
expirationTimestamp: ethers.BigNumber.from(fakeTime + 200),
693697
timestamp: ethers.BigNumber.from(fakeTime - 50),
694-
ancillaryData: "data",
698+
ancillaryData,
695699
proposedPrice: ethers.BigNumber.from(456),
700+
identifier,
696701
},
697702
};
698703

699-
// Stub paginatedEventQuery to return both fake events.
704+
// Stub paginatedEventQuery to return different results based on the filter type.
700705
const paginatedEventQueryStub = sandbox
701706
.stub(commonModule, "paginatedEventQuery")
702-
.callsFake(async () => [fakeEventBelow as any, fakeEventAbove as any]);
707+
.callsFake(async (oo, filter) => {
708+
if (filter.topics?.[0] === oo.filters.DisputePrice(null, null, null, null, null, null, null).topics?.[0]) {
709+
return []; // Return an empty array for DisputePrice filter
710+
}
711+
return [fakeEventBelow as any, fakeEventAbove as any]; // Return existing data for ProposePrice filter
712+
});
703713

704714
const params = await createMonitoringParams();
705715
// Set the parameter to 120 seconds.

0 commit comments

Comments
 (0)