diff --git a/apps/agent/src/index.ts b/apps/agent/src/index.ts index 47eedec..4e6669a 100644 --- a/apps/agent/src/index.ts +++ b/apps/agent/src/index.ts @@ -1,6 +1,10 @@ import { inspect } from "util"; -import { EboActorsManager, EboProcessor } from "@ebo-agent/automated-dispute"; -import { ProtocolProvider } from "@ebo-agent/automated-dispute/dist/providers/protocolProvider.js"; +import { + AccountingModules, + EboActorsManager, + EboProcessor, + ProtocolProvider, +} from "@ebo-agent/automated-dispute"; import { BlockNumberService } from "@ebo-agent/blocknumber"; import { Logger } from "@ebo-agent/shared"; @@ -30,6 +34,11 @@ const config = { }, processor: { msBetweenChecks: 1, + accountingModules: { + requestModule: "0x01", + responseModule: "0x02", + escalationModule: "0x03", + } as AccountingModules, }, }; @@ -50,7 +59,13 @@ const main = async (): Promise => { const actorsManager = new EboActorsManager(); - const processor = new EboProcessor(protocolProvider, blockNumberService, actorsManager, logger); + const processor = new EboProcessor( + config.processor.accountingModules, + protocolProvider, + blockNumberService, + actorsManager, + logger, + ); await processor.start(config.processor.msBetweenChecks); }; diff --git a/packages/automated-dispute/src/abis/bondEscalationModule.ts b/packages/automated-dispute/src/abis/bondEscalationModule.ts index 45c9878..915829c 100644 --- a/packages/automated-dispute/src/abis/bondEscalationModule.ts +++ b/packages/automated-dispute/src/abis/bondEscalationModule.ts @@ -580,1131 +580,6 @@ export const bondEscalationModuleAbi = [ }, rawMetadata: '{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"contract IOracle","name":"_oracle","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BondEscalationModule_BondEscalationCantBeSettled","type":"error"},{"inputs":[],"name":"BondEscalationModule_BondEscalationNotOver","type":"error"},{"inputs":[],"name":"BondEscalationModule_BondEscalationOver","type":"error"},{"inputs":[],"name":"BondEscalationModule_CanOnlySurpassByOnePledge","type":"error"},{"inputs":[],"name":"BondEscalationModule_CannotBreakTieDuringTyingBuffer","type":"error"},{"inputs":[],"name":"BondEscalationModule_DisputeDoesNotExist","type":"error"},{"inputs":[],"name":"BondEscalationModule_DisputeWindowOver","type":"error"},{"inputs":[],"name":"BondEscalationModule_InvalidDispute","type":"error"},{"inputs":[],"name":"BondEscalationModule_InvalidEscalationParameters","type":"error"},{"inputs":[],"name":"BondEscalationModule_MaxNumberOfEscalationsReached","type":"error"},{"inputs":[],"name":"BondEscalationModule_NotEscalatable","type":"error"},{"inputs":[],"name":"BondEscalationModule_ShouldBeEscalated","type":"error"},{"inputs":[],"name":"BondEscalationModule_ZeroValue","type":"error"},{"inputs":[],"name":"Module_OnlyOracle","type":"error"},{"inputs":[],"name":"Validator_InvalidDispute","type":"error"},{"inputs":[],"name":"Validator_InvalidResponse","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"_disputeId","type":"bytes32"},{"indexed":false,"internalType":"enum IBondEscalationModule.BondEscalationStatus","name":"_status","type":"uint8"}],"name":"BondEscalationStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_disputeId","type":"bytes32"},{"components":[{"internalType":"address","name":"disputer","type":"address"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"responseId","type":"bytes32"},{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"indexed":false,"internalType":"struct IOracle.Dispute","name":"_dispute","type":"tuple"},{"indexed":false,"internalType":"enum IOracle.DisputeStatus","name":"_status","type":"uint8"}],"name":"DisputeStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_disputeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"_pledger","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"PledgedAgainstDispute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_disputeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"_pledger","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"PledgedForDispute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"response","type":"bytes"}],"indexed":false,"internalType":"struct IOracle.Response","name":"_response","type":"tuple"},{"indexed":false,"internalType":"address","name":"_finalizer","type":"address"}],"name":"RequestFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"_responseId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"_disputeId","type":"bytes32"},{"components":[{"internalType":"address","name":"disputer","type":"address"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"responseId","type":"bytes32"},{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"indexed":false,"internalType":"struct IOracle.Dispute","name":"_dispute","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"_blockNumber","type":"uint256"}],"name":"ResponseDisputed","type":"event"},{"inputs":[],"name":"ORACLE","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"decodeRequestData","outputs":[{"components":[{"internalType":"contract IBondEscalationAccounting","name":"accountingExtension","type":"address"},{"internalType":"contract IERC20","name":"bondToken","type":"address"},{"internalType":"uint256","name":"bondSize","type":"uint256"},{"internalType":"uint256","name":"maxNumberOfEscalations","type":"uint256"},{"internalType":"uint256","name":"bondEscalationDeadline","type":"uint256"},{"internalType":"uint256","name":"tyingBuffer","type":"uint256"},{"internalType":"uint256","name":"disputeWindow","type":"uint256"}],"internalType":"struct IBondEscalationModule.RequestParameters","name":"_params","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"address","name":"requestModule","type":"address"},{"internalType":"address","name":"responseModule","type":"address"},{"internalType":"address","name":"disputeModule","type":"address"},{"internalType":"address","name":"resolutionModule","type":"address"},{"internalType":"address","name":"finalityModule","type":"address"},{"internalType":"bytes","name":"requestModuleData","type":"bytes"},{"internalType":"bytes","name":"responseModuleData","type":"bytes"},{"internalType":"bytes","name":"disputeModuleData","type":"bytes"},{"internalType":"bytes","name":"resolutionModuleData","type":"bytes"},{"internalType":"bytes","name":"finalityModuleData","type":"bytes"}],"internalType":"struct IOracle.Request","name":"_request","type":"tuple"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct IOracle.Response","name":"_response","type":"tuple"},{"components":[{"internalType":"address","name":"disputer","type":"address"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"responseId","type":"bytes32"},{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"internalType":"struct IOracle.Dispute","name":"_dispute","type":"tuple"}],"name":"disputeResponse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"address","name":"requestModule","type":"address"},{"internalType":"address","name":"responseModule","type":"address"},{"internalType":"address","name":"disputeModule","type":"address"},{"internalType":"address","name":"resolutionModule","type":"address"},{"internalType":"address","name":"finalityModule","type":"address"},{"internalType":"bytes","name":"requestModuleData","type":"bytes"},{"internalType":"bytes","name":"responseModuleData","type":"bytes"},{"internalType":"bytes","name":"disputeModuleData","type":"bytes"},{"internalType":"bytes","name":"resolutionModuleData","type":"bytes"},{"internalType":"bytes","name":"finalityModuleData","type":"bytes"}],"internalType":"struct IOracle.Request","name":"_request","type":"tuple"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct IOracle.Response","name":"_response","type":"tuple"},{"internalType":"address","name":"_finalizer","type":"address"}],"name":"finalizeRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_requestId","type":"bytes32"}],"name":"getEscalation","outputs":[{"components":[{"internalType":"bytes32","name":"disputeId","type":"bytes32"},{"internalType":"enum IBondEscalationModule.BondEscalationStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"amountOfPledgesForDispute","type":"uint256"},{"internalType":"uint256","name":"amountOfPledgesAgainstDispute","type":"uint256"}],"internalType":"struct IBondEscalationModule.BondEscalation","name":"_escalation","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"moduleName","outputs":[{"internalType":"string","name":"_moduleName","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_disputeId","type":"bytes32"},{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"address","name":"requestModule","type":"address"},{"internalType":"address","name":"responseModule","type":"address"},{"internalType":"address","name":"disputeModule","type":"address"},{"internalType":"address","name":"resolutionModule","type":"address"},{"internalType":"address","name":"finalityModule","type":"address"},{"internalType":"bytes","name":"requestModuleData","type":"bytes"},{"internalType":"bytes","name":"responseModuleData","type":"bytes"},{"internalType":"bytes","name":"disputeModuleData","type":"bytes"},{"internalType":"bytes","name":"resolutionModuleData","type":"bytes"},{"internalType":"bytes","name":"finalityModuleData","type":"bytes"}],"internalType":"struct IOracle.Request","name":"_request","type":"tuple"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct IOracle.Response","name":"","type":"tuple"},{"components":[{"internalType":"address","name":"disputer","type":"address"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"responseId","type":"bytes32"},{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"internalType":"struct IOracle.Dispute","name":"_dispute","type":"tuple"}],"name":"onDisputeStatusChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"address","name":"requestModule","type":"address"},{"internalType":"address","name":"responseModule","type":"address"},{"internalType":"address","name":"disputeModule","type":"address"},{"internalType":"address","name":"resolutionModule","type":"address"},{"internalType":"address","name":"finalityModule","type":"address"},{"internalType":"bytes","name":"requestModuleData","type":"bytes"},{"internalType":"bytes","name":"responseModuleData","type":"bytes"},{"internalType":"bytes","name":"disputeModuleData","type":"bytes"},{"internalType":"bytes","name":"resolutionModuleData","type":"bytes"},{"internalType":"bytes","name":"finalityModuleData","type":"bytes"}],"internalType":"struct IOracle.Request","name":"_request","type":"tuple"},{"components":[{"internalType":"address","name":"disputer","type":"address"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"responseId","type":"bytes32"},{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"internalType":"struct IOracle.Dispute","name":"_dispute","type":"tuple"}],"name":"pledgeAgainstDispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"address","name":"requestModule","type":"address"},{"internalType":"address","name":"responseModule","type":"address"},{"internalType":"address","name":"disputeModule","type":"address"},{"internalType":"address","name":"resolutionModule","type":"address"},{"internalType":"address","name":"finalityModule","type":"address"},{"internalType":"bytes","name":"requestModuleData","type":"bytes"},{"internalType":"bytes","name":"responseModuleData","type":"bytes"},{"internalType":"bytes","name":"disputeModuleData","type":"bytes"},{"internalType":"bytes","name":"resolutionModuleData","type":"bytes"},{"internalType":"bytes","name":"finalityModuleData","type":"bytes"}],"internalType":"struct IOracle.Request","name":"_request","type":"tuple"},{"components":[{"internalType":"address","name":"disputer","type":"address"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"responseId","type":"bytes32"},{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"internalType":"struct IOracle.Dispute","name":"_dispute","type":"tuple"}],"name":"pledgeForDispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"internalType":"address","name":"_pledger","type":"address"}],"name":"pledgesAgainstDispute","outputs":[{"internalType":"uint256","name":"pledges","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_requestId","type":"bytes32"},{"internalType":"address","name":"_pledger","type":"address"}],"name":"pledgesForDispute","outputs":[{"internalType":"uint256","name":"pledges","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"address","name":"requestModule","type":"address"},{"internalType":"address","name":"responseModule","type":"address"},{"internalType":"address","name":"disputeModule","type":"address"},{"internalType":"address","name":"resolutionModule","type":"address"},{"internalType":"address","name":"finalityModule","type":"address"},{"internalType":"bytes","name":"requestModuleData","type":"bytes"},{"internalType":"bytes","name":"responseModuleData","type":"bytes"},{"internalType":"bytes","name":"disputeModuleData","type":"bytes"},{"internalType":"bytes","name":"resolutionModuleData","type":"bytes"},{"internalType":"bytes","name":"finalityModuleData","type":"bytes"}],"internalType":"struct IOracle.Request","name":"_request","type":"tuple"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct IOracle.Response","name":"_response","type":"tuple"},{"components":[{"internalType":"address","name":"disputer","type":"address"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"bytes32","name":"responseId","type":"bytes32"},{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"internalType":"struct IOracle.Dispute","name":"_dispute","type":"tuple"}],"name":"settleBondEscalation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_encodedParameters","type":"bytes"}],"name":"validateParameters","outputs":[{"internalType":"bool","name":"_valid","type":"bool"}],"stateMutability":"pure","type":"function"}],"devdoc":{"events":{"BondEscalationStatusUpdated(bytes32,bytes32,uint8)":{"params":{"_disputeId":"The id of the dispute going through the bond escalation mechanism.","_requestId":"The id of the request associated with the bond escalation mechanism.","_status":"The new status."}},"DisputeStatusChanged(bytes32,(address,address,bytes32,bytes32),uint8)":{"params":{"_dispute":"The dispute","_disputeId":"The id of the dispute","_status":"The new status of the dispute"}},"PledgedAgainstDispute(bytes32,address,uint256)":{"params":{"_amount":"The amount pledged.","_disputeId":"The id of the dispute the pledger is pledging against.","_pledger":"The address of the pledger."}},"PledgedForDispute(bytes32,address,uint256)":{"params":{"_amount":"The amount pledged.","_disputeId":"The id of the dispute the pledger is pledging in favor of.","_pledger":"The address of the pledger."}},"RequestFinalized(bytes32,(address,bytes32,bytes),address)":{"params":{"_finalizer":"The address that initiated the finalization","_requestId":"The id of the request that was finalized","_response":"The final response"}},"ResponseDisputed(bytes32,bytes32,bytes32,(address,address,bytes32,bytes32),uint256)":{"params":{"_blockNumber":"The current block number","_dispute":"The dispute that is being created","_disputeId":"The id of the dispute","_responseId":"The id of the response disputed"}}},"kind":"dev","methods":{"decodeRequestData(bytes)":{"params":{"_data":"The encoded request parameters"},"returns":{"_params":"The struct containing the parameters for the request"}},"disputeResponse((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))":{"details":"If this is the first dispute of the request and the bond escalation window is not over, it will start the bond escalation process. This function must be called through the Oracle.","params":{"_dispute":"The dispute created by the oracle.","_request":"The request data.","_response":"The response being disputed."}},"finalizeRequest((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),address)":{"params":{"_finalizer":"The address that initiated the finalization","_request":"The request being finalized","_response":"The final response"}},"getEscalation(bytes32)":{"params":{"_requestId":"The id of the request to get its escalation data."},"returns":{"_escalation":"The struct containing the escalation data."}},"moduleName()":{"returns":{"_moduleName":"The name of the module."}},"onDisputeStatusChange(bytes32,(uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))":{"params":{"_dispute":"The dispute data.","_disputeId":"The ID of the dispute to update the status for.","_request":"The request data.","_response":"The disputed response."}},"pledgeAgainstDispute((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,address,bytes32,bytes32))":{"details":"Will revert if the disputeId is not going through the bond escalation process.If the bond escalation is not tied at the end of its deadline, a tying buffer is added to avoid scenarios where one of the parties breaks the tie very last second. During the tying buffer, the losing party can only tie, and once the escalation is tied no further funds can be pledged.","params":{"_dispute":"The dispute data.","_request":"The request data."}},"pledgeForDispute((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,address,bytes32,bytes32))":{"details":"If the bond escalation is not tied at the end of its deadline, a tying buffer is added to avoid scenarios where one of the parties breaks the tie very last second. During the tying buffer, the losing party can only tie, and once the escalation is tied no further funds can be pledged.","params":{"_dispute":"The dispute data.","_request":"The request data."}},"settleBondEscalation((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))":{"details":"Can only be called if after the deadline + tyingBuffer window is over, the pledges weren\'t tied","params":{"_dispute":"The dispute data.","_request":"The request data.","_response":"The response data."}},"validateParameters(bytes)":{"params":{"_encodedParameters":"The encoded parameters for the request"},"returns":{"_valid":"Boolean indicating if the parameters are valid or not"}}},"stateVariables":{"pledgesAgainstDispute":{"params":{"_pledger":"The address of the pledger to get the pledges for.","_requestId":"The id of the request to get the pledges for."},"return":"pledges The number of pledges made by the pledger against the dispute.","returns":{"pledges":"The number of pledges made by the pledger against the dispute."}},"pledgesForDispute":{"params":{"_pledger":"The address of the pledger to get the pledges for.","_requestId":"The id of the request to get the pledges for."},"return":"pledges The number of pledges made by the pledger for the dispute.","returns":{"pledges":"The number of pledges made by the pledger for the dispute."}}},"version":1},"userdoc":{"errors":{"BondEscalationModule_BondEscalationCantBeSettled()":[{"notice":"Thrown when trying to settle a dispute that went through the bond escalation when it\'s not active."}],"BondEscalationModule_BondEscalationNotOver()":[{"notice":"Thrown when trying to escalate a dispute going through the bond escalation module before its deadline."}],"BondEscalationModule_BondEscalationOver()":[{"notice":"Thrown when trying to pledge after the bond escalation deadline."}],"BondEscalationModule_CanOnlySurpassByOnePledge()":[{"notice":"Thrown when trying to surpass the number of pledges of the other side by more than 1 in the bond escalation mechanism."}],"BondEscalationModule_CannotBreakTieDuringTyingBuffer()":[{"notice":"Thrown when trying to break a tie after the tying buffer has started."}],"BondEscalationModule_DisputeDoesNotExist()":[{"notice":"Thrown when trying to pledge for a dispute that does not exist"}],"BondEscalationModule_DisputeWindowOver()":[{"notice":"Thrown when trying to dispute a response after the dispute period expired."}],"BondEscalationModule_InvalidDispute()":[{"notice":"Thrown when trying to pledge for a dispute that is not going through the bond escalation mechanism."}],"BondEscalationModule_InvalidEscalationParameters()":[{"notice":"Thrown when trying to set up a request with invalid bond size or maximum amount of escalations."}],"BondEscalationModule_MaxNumberOfEscalationsReached()":[{"notice":"Thrown when the number of escalation pledges of a given dispute has reached its maximum."}],"BondEscalationModule_NotEscalatable()":[{"notice":"Thrown when trying to escalate a dispute going through the bond escalation process that is not tied or that is not active."}],"BondEscalationModule_ShouldBeEscalated()":[{"notice":"Thrown when trying to settle a bond escalation process that is not tied."}],"BondEscalationModule_ZeroValue()":[{"notice":"Thrown when the max number of escalations or the bond size is set to 0."}],"Module_OnlyOracle()":[{"notice":"Thrown when the caller is not the oracle"}],"Validator_InvalidDispute()":[{"notice":"Thrown when the dispute provided does not exist"}],"Validator_InvalidResponse()":[{"notice":"Thrown when the response provided does not exist"}]},"events":{"BondEscalationStatusUpdated(bytes32,bytes32,uint8)":{"notice":"The status of the bond escalation mechanism has been updated."},"DisputeStatusChanged(bytes32,(address,address,bytes32,bytes32),uint8)":{"notice":"Emitted when a dispute status is updated"},"PledgedAgainstDispute(bytes32,address,uint256)":{"notice":"A pledge has been made against a dispute."},"PledgedForDispute(bytes32,address,uint256)":{"notice":"A pledge has been made in favor of a dispute."},"RequestFinalized(bytes32,(address,bytes32,bytes),address)":{"notice":"Emitted when a request is finalized"},"ResponseDisputed(bytes32,bytes32,bytes32,(address,address,bytes32,bytes32),uint256)":{"notice":"Emitted when a response is disputed"}},"kind":"user","methods":{"ORACLE()":{"notice":"The oracle contract"},"decodeRequestData(bytes)":{"notice":"Returns the decoded data for a request"},"disputeResponse((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))":{"notice":"Disputes a response"},"finalizeRequest((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),address)":{"notice":"Finalizes the request"},"getEscalation(bytes32)":{"notice":"Returns the escalation data for a request."},"moduleName()":{"notice":"Returns the name of the module."},"onDisputeStatusChange(bytes32,(uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))":{"notice":"Updates the status of a given disputeId and pays the proposer and disputer accordingly. If this dispute has gone through the bond escalation mechanism, then it will pay the winning pledgers as well."},"pledgeAgainstDispute((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,address,bytes32,bytes32))":{"notice":"Pledges funds against a given disputeId during its bond escalation process."},"pledgeForDispute((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,address,bytes32,bytes32))":{"notice":"Bonds funds in favor of a given dispute during the bond escalation process."},"pledgesAgainstDispute(bytes32,address)":{"notice":"Returns the amount of pledges that a particular pledger has made against a given dispute."},"pledgesForDispute(bytes32,address)":{"notice":"Returns the amount of pledges that a particular pledger has made for a given dispute."},"settleBondEscalation((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))":{"notice":"Settles the bond escalation process of a given requestId."},"validateParameters(bytes)":{"notice":"Validates parameters prior to creating a request"}},"version":1}},"settings":{"compilationTarget":{"solidity/contracts/modules/dispute/BondEscalationModule.sol":"BondEscalationModule"},"evmVersion":"paris","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":10000},"remappings":[":@defi-wonderland/=node_modules/@defi-wonderland/",":@openzeppelin/=node_modules/@openzeppelin/",":ds-test/=node_modules/ds-test/src/",":forge-std/=node_modules/forge-std/src/",":solmate/=node_modules/solmate/src/"]},"sources":{"node_modules/@defi-wonderland/prophet-core/solidity/contracts/Module.sol":{"keccak256":"0xf1cc2b38026d6ceac64603b09c495703b28bff3bb16759538328771583c55b8f","license":"MIT","urls":["bzz-raw://c494462ff30a687311169777253165ece60a7ab41a10befe5595c2d912610120","dweb:/ipfs/QmfWr8nPriXt6HrxbYx65xA2ACmJBXWBSUjCLrN783vErZ"]},"node_modules/@defi-wonderland/prophet-core/solidity/contracts/Validator.sol":{"keccak256":"0x5a06b99d5dd53c00c76a8195a72c0afaa801e343eae449d00c502571967343aa","license":"MIT","urls":["bzz-raw://f576bcad599cd37f6f34d9760a469dd4948872e38db74946947904d642a52b72","dweb:/ipfs/QmXAyxczdwmSFHoix1zQqdAtANf1uRfqTQZjBkDWfWmRE9"]},"node_modules/@defi-wonderland/prophet-core/solidity/interfaces/IModule.sol":{"keccak256":"0x68ee41846e0dc31a48b9e4fa1056f914748cec29c64e79272d994fcdf74277c9","license":"MIT","urls":["bzz-raw://3d22e0e329c145e6532f7a52baccb26ab3443d74a7d6573f6348fafb27ca91cd","dweb:/ipfs/QmQDx1aTsM7tCvvUAgPSmJp1xVYudvciNEvq6X1nLXwSnM"]},"node_modules/@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol":{"keccak256":"0xe209995220c3a9f21b9dc3ca218551a203b7312585de580f5b35f8056c8a1e43","license":"MIT","urls":["bzz-raw://f892e60fef98e11d7f52540e16b6cc1c0ff9329387ed69a3ac0240efce6c868f","dweb:/ipfs/QmNRXwSzcDCbq8WsjkTaoBFki8ZA1afqRGpsCqVswWmsvY"]},"node_modules/@defi-wonderland/prophet-core/solidity/interfaces/IValidator.sol":{"keccak256":"0x19495833d4bfbe88d44b7576f2b02b5a0bb9ffc2d91a86961b4065df64d054b9","license":"MIT","urls":["bzz-raw://ad23d158629b23dc31b9e2a4e75a4abf4b5cad40ee3e9f4f9efd9ae185ceec75","dweb:/ipfs/QmNWbbQaCS6dGcPiw49cJ7A7VaHUxNbEd5vvd4KcAgSxNX"]},"node_modules/@defi-wonderland/prophet-core/solidity/interfaces/modules/dispute/IDisputeModule.sol":{"keccak256":"0x105959eaa1caf78b7dfcc5685cbbfb0f765ba4ec8eea12af180309dd2c1894c7","license":"MIT","urls":["bzz-raw://e29ea2fe3abe20b25846828970a101ed3f2283f3b842e9dacf44e427f86d75dc","dweb:/ipfs/QmRYCzGN8qSW3RvqvANzFuX2SD1W9W69AcCAYnA1RQ4PU1"]},"node_modules/@defi-wonderland/prophet-core/solidity/libraries/ValidatorLib.sol":{"keccak256":"0x9b4ac36694e207c3b53e0369c8b7340864f807d4e07fb8042ef6ea414fcb4ea0","license":"MIT","urls":["bzz-raw://2e9c9845bcf35cfdf1a3450f46c59461cdc9aee95b98e1b34f11187b1b0ca3be","dweb:/ipfs/QmQJqsMzFN6FQeZvGj894mm7ckTqYkpvxpCHAKuY7PA5Dt"]},"node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol":{"keccak256":"0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305","license":"MIT","urls":["bzz-raw://bd39944e8fc06be6dbe2dd1d8449b5336e23c6a7ba3e8e9ae5ae0f37f35283f5","dweb:/ipfs/QmPV3FGYjVwvKSgAXKUN3r9T9GwniZz83CxBpM7vyj2G53"]},"node_modules/solmate/src/utils/FixedPointMathLib.sol":{"keccak256":"0x1b62af9baf5b8e991ed7531bc87f45550ba9d61e8dbff5caf237ccaf3a3fd843","license":"AGPL-3.0-only","urls":["bzz-raw://b7b38b977c5305b18ceefbeed4c9ceaaaefa419b520de62de6604ea661f8c0a9","dweb:/ipfs/QmecMRzgfMyDVa2pvBqMMDLYBappaj7Aa3qcMoQYEQrhWi"]},"solidity/contracts/modules/dispute/BondEscalationModule.sol":{"keccak256":"0xca5bab50973326f18e773eabf1943a6ba87cb012eaccd8764cb2fe871500bff9","license":"MIT","urls":["bzz-raw://50e1c4811d0e8e95e8955e772c6d081d9bc6447b8517ac946a26ae043077a765","dweb:/ipfs/QmaNYzCmhtkV9voi4G7dxnu7shfmk88iKtdwp8PVdEHZpQ"]},"solidity/interfaces/extensions/IAccountingExtension.sol":{"keccak256":"0xf5a6798f05097db052b75e3863b744acffa3553f360a937769cf48085df03372","license":"MIT","urls":["bzz-raw://941a90aa620ba7f0719adcf816cb3f1cf2614601165f83024f85320f51de0a64","dweb:/ipfs/QmZrHjveVuVBXz8GUBec3tDGNYRrF4YFyfcHCpQTfGVfF4"]},"solidity/interfaces/extensions/IBondEscalationAccounting.sol":{"keccak256":"0xd015b2ae12f7bfaacfeb44a80a110f712e2695c8e4b55e44f198304a49cecc0d","license":"MIT","urls":["bzz-raw://76bd7aba416cb7f6259565477c03f47b1cfd63ff873c9952ddddb10ddd1b1e0e","dweb:/ipfs/QmSwTmwTmgusGrXgcyg5t66y2FR2sqYQwKWcozBLSqmGTo"]},"solidity/interfaces/modules/dispute/IBondEscalationModule.sol":{"keccak256":"0xbb9c791dd188b144632b6cfdc180dd42c4761d6ea2193ed93021a82abd055020","license":"MIT","urls":["bzz-raw://b962d6df377cdb83187d35daf3c7faa8758ec13f6d53a01d8d6c874f9ccb870a","dweb:/ipfs/QmQoadeFhNndmE4JEzxpcr6YgHUKMPUoy1Go22hZWJk36A"]}},"version":1}', - metadata: { - compiler: { version: "0.8.19+commit.7dd6d404" }, - language: "Solidity", - output: { - abi: [ - { - inputs: [ - { internalType: "contract IOracle", name: "_oracle", type: "address" }, - ], - stateMutability: "nonpayable", - type: "constructor", - }, - { - inputs: [], - type: "error", - name: "BondEscalationModule_BondEscalationCantBeSettled", - }, - { - inputs: [], - type: "error", - name: "BondEscalationModule_BondEscalationNotOver", - }, - { inputs: [], type: "error", name: "BondEscalationModule_BondEscalationOver" }, - { - inputs: [], - type: "error", - name: "BondEscalationModule_CanOnlySurpassByOnePledge", - }, - { - inputs: [], - type: "error", - name: "BondEscalationModule_CannotBreakTieDuringTyingBuffer", - }, - { inputs: [], type: "error", name: "BondEscalationModule_DisputeDoesNotExist" }, - { inputs: [], type: "error", name: "BondEscalationModule_DisputeWindowOver" }, - { inputs: [], type: "error", name: "BondEscalationModule_InvalidDispute" }, - { - inputs: [], - type: "error", - name: "BondEscalationModule_InvalidEscalationParameters", - }, - { - inputs: [], - type: "error", - name: "BondEscalationModule_MaxNumberOfEscalationsReached", - }, - { inputs: [], type: "error", name: "BondEscalationModule_NotEscalatable" }, - { inputs: [], type: "error", name: "BondEscalationModule_ShouldBeEscalated" }, - { inputs: [], type: "error", name: "BondEscalationModule_ZeroValue" }, - { inputs: [], type: "error", name: "Module_OnlyOracle" }, - { inputs: [], type: "error", name: "Validator_InvalidDispute" }, - { inputs: [], type: "error", name: "Validator_InvalidResponse" }, - { - inputs: [ - { - internalType: "bytes32", - name: "_requestId", - type: "bytes32", - indexed: true, - }, - { - internalType: "bytes32", - name: "_disputeId", - type: "bytes32", - indexed: true, - }, - { - internalType: "enum IBondEscalationModule.BondEscalationStatus", - name: "_status", - type: "uint8", - indexed: false, - }, - ], - type: "event", - name: "BondEscalationStatusUpdated", - anonymous: false, - }, - { - inputs: [ - { - internalType: "bytes32", - name: "_disputeId", - type: "bytes32", - indexed: true, - }, - { - internalType: "struct IOracle.Dispute", - name: "_dispute", - type: "tuple", - components: [ - { internalType: "address", name: "disputer", type: "address" }, - { internalType: "address", name: "proposer", type: "address" }, - { - internalType: "bytes32", - name: "responseId", - type: "bytes32", - }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - ], - indexed: false, - }, - { - internalType: "enum IOracle.DisputeStatus", - name: "_status", - type: "uint8", - indexed: false, - }, - ], - type: "event", - name: "DisputeStatusChanged", - anonymous: false, - }, - { - inputs: [ - { - internalType: "bytes32", - name: "_disputeId", - type: "bytes32", - indexed: true, - }, - { - internalType: "address", - name: "_pledger", - type: "address", - indexed: true, - }, - { - internalType: "uint256", - name: "_amount", - type: "uint256", - indexed: true, - }, - ], - type: "event", - name: "PledgedAgainstDispute", - anonymous: false, - }, - { - inputs: [ - { - internalType: "bytes32", - name: "_disputeId", - type: "bytes32", - indexed: true, - }, - { - internalType: "address", - name: "_pledger", - type: "address", - indexed: true, - }, - { - internalType: "uint256", - name: "_amount", - type: "uint256", - indexed: true, - }, - ], - type: "event", - name: "PledgedForDispute", - anonymous: false, - }, - { - inputs: [ - { - internalType: "bytes32", - name: "_requestId", - type: "bytes32", - indexed: true, - }, - { - internalType: "struct IOracle.Response", - name: "_response", - type: "tuple", - components: [ - { internalType: "address", name: "proposer", type: "address" }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - { internalType: "bytes", name: "response", type: "bytes" }, - ], - indexed: false, - }, - { - internalType: "address", - name: "_finalizer", - type: "address", - indexed: false, - }, - ], - type: "event", - name: "RequestFinalized", - anonymous: false, - }, - { - inputs: [ - { - internalType: "bytes32", - name: "_requestId", - type: "bytes32", - indexed: true, - }, - { - internalType: "bytes32", - name: "_responseId", - type: "bytes32", - indexed: true, - }, - { - internalType: "bytes32", - name: "_disputeId", - type: "bytes32", - indexed: true, - }, - { - internalType: "struct IOracle.Dispute", - name: "_dispute", - type: "tuple", - components: [ - { internalType: "address", name: "disputer", type: "address" }, - { internalType: "address", name: "proposer", type: "address" }, - { - internalType: "bytes32", - name: "responseId", - type: "bytes32", - }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - ], - indexed: false, - }, - { - internalType: "uint256", - name: "_blockNumber", - type: "uint256", - indexed: false, - }, - ], - type: "event", - name: "ResponseDisputed", - anonymous: false, - }, - { - inputs: [], - stateMutability: "view", - type: "function", - name: "ORACLE", - outputs: [{ internalType: "contract IOracle", name: "", type: "address" }], - }, - { - inputs: [{ internalType: "bytes", name: "_data", type: "bytes" }], - stateMutability: "pure", - type: "function", - name: "decodeRequestData", - outputs: [ - { - internalType: "struct IBondEscalationModule.RequestParameters", - name: "_params", - type: "tuple", - components: [ - { - internalType: "contract IBondEscalationAccounting", - name: "accountingExtension", - type: "address", - }, - { - internalType: "contract IERC20", - name: "bondToken", - type: "address", - }, - { internalType: "uint256", name: "bondSize", type: "uint256" }, - { - internalType: "uint256", - name: "maxNumberOfEscalations", - type: "uint256", - }, - { - internalType: "uint256", - name: "bondEscalationDeadline", - type: "uint256", - }, - { - internalType: "uint256", - name: "tyingBuffer", - type: "uint256", - }, - { - internalType: "uint256", - name: "disputeWindow", - type: "uint256", - }, - ], - }, - ], - }, - { - inputs: [ - { - internalType: "struct IOracle.Request", - name: "_request", - type: "tuple", - components: [ - { internalType: "uint96", name: "nonce", type: "uint96" }, - { internalType: "address", name: "requester", type: "address" }, - { - internalType: "address", - name: "requestModule", - type: "address", - }, - { - internalType: "address", - name: "responseModule", - type: "address", - }, - { - internalType: "address", - name: "disputeModule", - type: "address", - }, - { - internalType: "address", - name: "resolutionModule", - type: "address", - }, - { - internalType: "address", - name: "finalityModule", - type: "address", - }, - { - internalType: "bytes", - name: "requestModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "responseModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "disputeModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "resolutionModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "finalityModuleData", - type: "bytes", - }, - ], - }, - { - internalType: "struct IOracle.Response", - name: "_response", - type: "tuple", - components: [ - { internalType: "address", name: "proposer", type: "address" }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - { internalType: "bytes", name: "response", type: "bytes" }, - ], - }, - { - internalType: "struct IOracle.Dispute", - name: "_dispute", - type: "tuple", - components: [ - { internalType: "address", name: "disputer", type: "address" }, - { internalType: "address", name: "proposer", type: "address" }, - { - internalType: "bytes32", - name: "responseId", - type: "bytes32", - }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - ], - }, - ], - stateMutability: "nonpayable", - type: "function", - name: "disputeResponse", - }, - { - inputs: [ - { - internalType: "struct IOracle.Request", - name: "_request", - type: "tuple", - components: [ - { internalType: "uint96", name: "nonce", type: "uint96" }, - { internalType: "address", name: "requester", type: "address" }, - { - internalType: "address", - name: "requestModule", - type: "address", - }, - { - internalType: "address", - name: "responseModule", - type: "address", - }, - { - internalType: "address", - name: "disputeModule", - type: "address", - }, - { - internalType: "address", - name: "resolutionModule", - type: "address", - }, - { - internalType: "address", - name: "finalityModule", - type: "address", - }, - { - internalType: "bytes", - name: "requestModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "responseModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "disputeModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "resolutionModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "finalityModuleData", - type: "bytes", - }, - ], - }, - { - internalType: "struct IOracle.Response", - name: "_response", - type: "tuple", - components: [ - { internalType: "address", name: "proposer", type: "address" }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - { internalType: "bytes", name: "response", type: "bytes" }, - ], - }, - { internalType: "address", name: "_finalizer", type: "address" }, - ], - stateMutability: "nonpayable", - type: "function", - name: "finalizeRequest", - }, - { - inputs: [{ internalType: "bytes32", name: "_requestId", type: "bytes32" }], - stateMutability: "view", - type: "function", - name: "getEscalation", - outputs: [ - { - internalType: "struct IBondEscalationModule.BondEscalation", - name: "_escalation", - type: "tuple", - components: [ - { internalType: "bytes32", name: "disputeId", type: "bytes32" }, - { - internalType: - "enum IBondEscalationModule.BondEscalationStatus", - name: "status", - type: "uint8", - }, - { - internalType: "uint256", - name: "amountOfPledgesForDispute", - type: "uint256", - }, - { - internalType: "uint256", - name: "amountOfPledgesAgainstDispute", - type: "uint256", - }, - ], - }, - ], - }, - { - inputs: [], - stateMutability: "pure", - type: "function", - name: "moduleName", - outputs: [{ internalType: "string", name: "_moduleName", type: "string" }], - }, - { - inputs: [ - { internalType: "bytes32", name: "_disputeId", type: "bytes32" }, - { - internalType: "struct IOracle.Request", - name: "_request", - type: "tuple", - components: [ - { internalType: "uint96", name: "nonce", type: "uint96" }, - { internalType: "address", name: "requester", type: "address" }, - { - internalType: "address", - name: "requestModule", - type: "address", - }, - { - internalType: "address", - name: "responseModule", - type: "address", - }, - { - internalType: "address", - name: "disputeModule", - type: "address", - }, - { - internalType: "address", - name: "resolutionModule", - type: "address", - }, - { - internalType: "address", - name: "finalityModule", - type: "address", - }, - { - internalType: "bytes", - name: "requestModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "responseModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "disputeModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "resolutionModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "finalityModuleData", - type: "bytes", - }, - ], - }, - { - internalType: "struct IOracle.Response", - name: "", - type: "tuple", - components: [ - { internalType: "address", name: "proposer", type: "address" }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - { internalType: "bytes", name: "response", type: "bytes" }, - ], - }, - { - internalType: "struct IOracle.Dispute", - name: "_dispute", - type: "tuple", - components: [ - { internalType: "address", name: "disputer", type: "address" }, - { internalType: "address", name: "proposer", type: "address" }, - { - internalType: "bytes32", - name: "responseId", - type: "bytes32", - }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - ], - }, - ], - stateMutability: "nonpayable", - type: "function", - name: "onDisputeStatusChange", - }, - { - inputs: [ - { - internalType: "struct IOracle.Request", - name: "_request", - type: "tuple", - components: [ - { internalType: "uint96", name: "nonce", type: "uint96" }, - { internalType: "address", name: "requester", type: "address" }, - { - internalType: "address", - name: "requestModule", - type: "address", - }, - { - internalType: "address", - name: "responseModule", - type: "address", - }, - { - internalType: "address", - name: "disputeModule", - type: "address", - }, - { - internalType: "address", - name: "resolutionModule", - type: "address", - }, - { - internalType: "address", - name: "finalityModule", - type: "address", - }, - { - internalType: "bytes", - name: "requestModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "responseModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "disputeModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "resolutionModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "finalityModuleData", - type: "bytes", - }, - ], - }, - { - internalType: "struct IOracle.Dispute", - name: "_dispute", - type: "tuple", - components: [ - { internalType: "address", name: "disputer", type: "address" }, - { internalType: "address", name: "proposer", type: "address" }, - { - internalType: "bytes32", - name: "responseId", - type: "bytes32", - }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - ], - }, - ], - stateMutability: "nonpayable", - type: "function", - name: "pledgeAgainstDispute", - }, - { - inputs: [ - { - internalType: "struct IOracle.Request", - name: "_request", - type: "tuple", - components: [ - { internalType: "uint96", name: "nonce", type: "uint96" }, - { internalType: "address", name: "requester", type: "address" }, - { - internalType: "address", - name: "requestModule", - type: "address", - }, - { - internalType: "address", - name: "responseModule", - type: "address", - }, - { - internalType: "address", - name: "disputeModule", - type: "address", - }, - { - internalType: "address", - name: "resolutionModule", - type: "address", - }, - { - internalType: "address", - name: "finalityModule", - type: "address", - }, - { - internalType: "bytes", - name: "requestModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "responseModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "disputeModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "resolutionModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "finalityModuleData", - type: "bytes", - }, - ], - }, - { - internalType: "struct IOracle.Dispute", - name: "_dispute", - type: "tuple", - components: [ - { internalType: "address", name: "disputer", type: "address" }, - { internalType: "address", name: "proposer", type: "address" }, - { - internalType: "bytes32", - name: "responseId", - type: "bytes32", - }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - ], - }, - ], - stateMutability: "nonpayable", - type: "function", - name: "pledgeForDispute", - }, - { - inputs: [ - { internalType: "bytes32", name: "_requestId", type: "bytes32" }, - { internalType: "address", name: "_pledger", type: "address" }, - ], - stateMutability: "view", - type: "function", - name: "pledgesAgainstDispute", - outputs: [{ internalType: "uint256", name: "pledges", type: "uint256" }], - }, - { - inputs: [ - { internalType: "bytes32", name: "_requestId", type: "bytes32" }, - { internalType: "address", name: "_pledger", type: "address" }, - ], - stateMutability: "view", - type: "function", - name: "pledgesForDispute", - outputs: [{ internalType: "uint256", name: "pledges", type: "uint256" }], - }, - { - inputs: [ - { - internalType: "struct IOracle.Request", - name: "_request", - type: "tuple", - components: [ - { internalType: "uint96", name: "nonce", type: "uint96" }, - { internalType: "address", name: "requester", type: "address" }, - { - internalType: "address", - name: "requestModule", - type: "address", - }, - { - internalType: "address", - name: "responseModule", - type: "address", - }, - { - internalType: "address", - name: "disputeModule", - type: "address", - }, - { - internalType: "address", - name: "resolutionModule", - type: "address", - }, - { - internalType: "address", - name: "finalityModule", - type: "address", - }, - { - internalType: "bytes", - name: "requestModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "responseModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "disputeModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "resolutionModuleData", - type: "bytes", - }, - { - internalType: "bytes", - name: "finalityModuleData", - type: "bytes", - }, - ], - }, - { - internalType: "struct IOracle.Response", - name: "_response", - type: "tuple", - components: [ - { internalType: "address", name: "proposer", type: "address" }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - { internalType: "bytes", name: "response", type: "bytes" }, - ], - }, - { - internalType: "struct IOracle.Dispute", - name: "_dispute", - type: "tuple", - components: [ - { internalType: "address", name: "disputer", type: "address" }, - { internalType: "address", name: "proposer", type: "address" }, - { - internalType: "bytes32", - name: "responseId", - type: "bytes32", - }, - { internalType: "bytes32", name: "requestId", type: "bytes32" }, - ], - }, - ], - stateMutability: "nonpayable", - type: "function", - name: "settleBondEscalation", - }, - { - inputs: [ - { internalType: "bytes", name: "_encodedParameters", type: "bytes" }, - ], - stateMutability: "pure", - type: "function", - name: "validateParameters", - outputs: [{ internalType: "bool", name: "_valid", type: "bool" }], - }, - ], - devdoc: { - kind: "dev", - methods: { - "decodeRequestData(bytes)": { - params: { _data: "The encoded request parameters" }, - returns: { - _params: "The struct containing the parameters for the request", - }, - }, - "disputeResponse((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))": - { - details: - "If this is the first dispute of the request and the bond escalation window is not over, it will start the bond escalation process. This function must be called through the Oracle.", - params: { - _dispute: "The dispute created by the oracle.", - _request: "The request data.", - _response: "The response being disputed.", - }, - }, - "finalizeRequest((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),address)": - { - params: { - _finalizer: "The address that initiated the finalization", - _request: "The request being finalized", - _response: "The final response", - }, - }, - "getEscalation(bytes32)": { - params: { - _requestId: "The id of the request to get its escalation data.", - }, - returns: { _escalation: "The struct containing the escalation data." }, - }, - "moduleName()": { returns: { _moduleName: "The name of the module." } }, - "onDisputeStatusChange(bytes32,(uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))": - { - params: { - _dispute: "The dispute data.", - _disputeId: "The ID of the dispute to update the status for.", - _request: "The request data.", - _response: "The disputed response.", - }, - }, - "pledgeAgainstDispute((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,address,bytes32,bytes32))": - { - details: - "Will revert if the disputeId is not going through the bond escalation process.If the bond escalation is not tied at the end of its deadline, a tying buffer is added to avoid scenarios where one of the parties breaks the tie very last second. During the tying buffer, the losing party can only tie, and once the escalation is tied no further funds can be pledged.", - params: { - _dispute: "The dispute data.", - _request: "The request data.", - }, - }, - "pledgeForDispute((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,address,bytes32,bytes32))": - { - details: - "If the bond escalation is not tied at the end of its deadline, a tying buffer is added to avoid scenarios where one of the parties breaks the tie very last second. During the tying buffer, the losing party can only tie, and once the escalation is tied no further funds can be pledged.", - params: { - _dispute: "The dispute data.", - _request: "The request data.", - }, - }, - "settleBondEscalation((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))": - { - details: - "Can only be called if after the deadline + tyingBuffer window is over, the pledges weren't tied", - params: { - _dispute: "The dispute data.", - _request: "The request data.", - _response: "The response data.", - }, - }, - "validateParameters(bytes)": { - params: { - _encodedParameters: "The encoded parameters for the request", - }, - returns: { - _valid: "Boolean indicating if the parameters are valid or not", - }, - }, - }, - version: 1, - }, - userdoc: { - kind: "user", - methods: { - "ORACLE()": { notice: "The oracle contract" }, - "decodeRequestData(bytes)": { - notice: "Returns the decoded data for a request", - }, - "disputeResponse((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))": - { notice: "Disputes a response" }, - "finalizeRequest((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),address)": - { notice: "Finalizes the request" }, - "getEscalation(bytes32)": { - notice: "Returns the escalation data for a request.", - }, - "moduleName()": { notice: "Returns the name of the module." }, - "onDisputeStatusChange(bytes32,(uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))": - { - notice: "Updates the status of a given disputeId and pays the proposer and disputer accordingly. If this dispute has gone through the bond escalation mechanism, then it will pay the winning pledgers as well.", - }, - "pledgeAgainstDispute((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,address,bytes32,bytes32))": - { - notice: "Pledges funds against a given disputeId during its bond escalation process.", - }, - "pledgeForDispute((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,address,bytes32,bytes32))": - { - notice: "Bonds funds in favor of a given dispute during the bond escalation process.", - }, - "pledgesAgainstDispute(bytes32,address)": { - notice: "Returns the amount of pledges that a particular pledger has made against a given dispute.", - }, - "pledgesForDispute(bytes32,address)": { - notice: "Returns the amount of pledges that a particular pledger has made for a given dispute.", - }, - "settleBondEscalation((uint96,address,address,address,address,address,address,bytes,bytes,bytes,bytes,bytes),(address,bytes32,bytes),(address,address,bytes32,bytes32))": - { notice: "Settles the bond escalation process of a given requestId." }, - "validateParameters(bytes)": { - notice: "Validates parameters prior to creating a request", - }, - }, - version: 1, - }, - }, - settings: { - remappings: [ - "@defi-wonderland/=node_modules/@defi-wonderland/", - "@openzeppelin/=node_modules/@openzeppelin/", - "ds-test/=node_modules/ds-test/src/", - "forge-std/=node_modules/forge-std/src/", - "solmate/=node_modules/solmate/src/", - ], - optimizer: { enabled: true, runs: 10000 }, - metadata: { bytecodeHash: "ipfs" }, - compilationTarget: { - "solidity/contracts/modules/dispute/BondEscalationModule.sol": - "BondEscalationModule", - }, - evmVersion: "paris", - libraries: {}, - }, - sources: { - "node_modules/@defi-wonderland/prophet-core/solidity/contracts/Module.sol": { - keccak256: "0xf1cc2b38026d6ceac64603b09c495703b28bff3bb16759538328771583c55b8f", - urls: [ - "bzz-raw://c494462ff30a687311169777253165ece60a7ab41a10befe5595c2d912610120", - "dweb:/ipfs/QmfWr8nPriXt6HrxbYx65xA2ACmJBXWBSUjCLrN783vErZ", - ], - license: "MIT", - }, - "node_modules/@defi-wonderland/prophet-core/solidity/contracts/Validator.sol": { - keccak256: "0x5a06b99d5dd53c00c76a8195a72c0afaa801e343eae449d00c502571967343aa", - urls: [ - "bzz-raw://f576bcad599cd37f6f34d9760a469dd4948872e38db74946947904d642a52b72", - "dweb:/ipfs/QmXAyxczdwmSFHoix1zQqdAtANf1uRfqTQZjBkDWfWmRE9", - ], - license: "MIT", - }, - "node_modules/@defi-wonderland/prophet-core/solidity/interfaces/IModule.sol": { - keccak256: "0x68ee41846e0dc31a48b9e4fa1056f914748cec29c64e79272d994fcdf74277c9", - urls: [ - "bzz-raw://3d22e0e329c145e6532f7a52baccb26ab3443d74a7d6573f6348fafb27ca91cd", - "dweb:/ipfs/QmQDx1aTsM7tCvvUAgPSmJp1xVYudvciNEvq6X1nLXwSnM", - ], - license: "MIT", - }, - "node_modules/@defi-wonderland/prophet-core/solidity/interfaces/IOracle.sol": { - keccak256: "0xe209995220c3a9f21b9dc3ca218551a203b7312585de580f5b35f8056c8a1e43", - urls: [ - "bzz-raw://f892e60fef98e11d7f52540e16b6cc1c0ff9329387ed69a3ac0240efce6c868f", - "dweb:/ipfs/QmNRXwSzcDCbq8WsjkTaoBFki8ZA1afqRGpsCqVswWmsvY", - ], - license: "MIT", - }, - "node_modules/@defi-wonderland/prophet-core/solidity/interfaces/IValidator.sol": { - keccak256: "0x19495833d4bfbe88d44b7576f2b02b5a0bb9ffc2d91a86961b4065df64d054b9", - urls: [ - "bzz-raw://ad23d158629b23dc31b9e2a4e75a4abf4b5cad40ee3e9f4f9efd9ae185ceec75", - "dweb:/ipfs/QmNWbbQaCS6dGcPiw49cJ7A7VaHUxNbEd5vvd4KcAgSxNX", - ], - license: "MIT", - }, - "node_modules/@defi-wonderland/prophet-core/solidity/interfaces/modules/dispute/IDisputeModule.sol": - { - keccak256: - "0x105959eaa1caf78b7dfcc5685cbbfb0f765ba4ec8eea12af180309dd2c1894c7", - urls: [ - "bzz-raw://e29ea2fe3abe20b25846828970a101ed3f2283f3b842e9dacf44e427f86d75dc", - "dweb:/ipfs/QmRYCzGN8qSW3RvqvANzFuX2SD1W9W69AcCAYnA1RQ4PU1", - ], - license: "MIT", - }, - "node_modules/@defi-wonderland/prophet-core/solidity/libraries/ValidatorLib.sol": { - keccak256: "0x9b4ac36694e207c3b53e0369c8b7340864f807d4e07fb8042ef6ea414fcb4ea0", - urls: [ - "bzz-raw://2e9c9845bcf35cfdf1a3450f46c59461cdc9aee95b98e1b34f11187b1b0ca3be", - "dweb:/ipfs/QmQJqsMzFN6FQeZvGj894mm7ckTqYkpvxpCHAKuY7PA5Dt", - ], - license: "MIT", - }, - "node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol": { - keccak256: "0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305", - urls: [ - "bzz-raw://bd39944e8fc06be6dbe2dd1d8449b5336e23c6a7ba3e8e9ae5ae0f37f35283f5", - "dweb:/ipfs/QmPV3FGYjVwvKSgAXKUN3r9T9GwniZz83CxBpM7vyj2G53", - ], - license: "MIT", - }, - "node_modules/solmate/src/utils/FixedPointMathLib.sol": { - keccak256: "0x1b62af9baf5b8e991ed7531bc87f45550ba9d61e8dbff5caf237ccaf3a3fd843", - urls: [ - "bzz-raw://b7b38b977c5305b18ceefbeed4c9ceaaaefa419b520de62de6604ea661f8c0a9", - "dweb:/ipfs/QmecMRzgfMyDVa2pvBqMMDLYBappaj7Aa3qcMoQYEQrhWi", - ], - license: "AGPL-3.0-only", - }, - "solidity/contracts/modules/dispute/BondEscalationModule.sol": { - keccak256: "0xca5bab50973326f18e773eabf1943a6ba87cb012eaccd8764cb2fe871500bff9", - urls: [ - "bzz-raw://50e1c4811d0e8e95e8955e772c6d081d9bc6447b8517ac946a26ae043077a765", - "dweb:/ipfs/QmaNYzCmhtkV9voi4G7dxnu7shfmk88iKtdwp8PVdEHZpQ", - ], - license: "MIT", - }, - "solidity/interfaces/extensions/IAccountingExtension.sol": { - keccak256: "0xf5a6798f05097db052b75e3863b744acffa3553f360a937769cf48085df03372", - urls: [ - "bzz-raw://941a90aa620ba7f0719adcf816cb3f1cf2614601165f83024f85320f51de0a64", - "dweb:/ipfs/QmZrHjveVuVBXz8GUBec3tDGNYRrF4YFyfcHCpQTfGVfF4", - ], - license: "MIT", - }, - "solidity/interfaces/extensions/IBondEscalationAccounting.sol": { - keccak256: "0xd015b2ae12f7bfaacfeb44a80a110f712e2695c8e4b55e44f198304a49cecc0d", - urls: [ - "bzz-raw://76bd7aba416cb7f6259565477c03f47b1cfd63ff873c9952ddddb10ddd1b1e0e", - "dweb:/ipfs/QmSwTmwTmgusGrXgcyg5t66y2FR2sqYQwKWcozBLSqmGTo", - ], - license: "MIT", - }, - "solidity/interfaces/modules/dispute/IBondEscalationModule.sol": { - keccak256: "0xbb9c791dd188b144632b6cfdc180dd42c4761d6ea2193ed93021a82abd055020", - urls: [ - "bzz-raw://b962d6df377cdb83187d35daf3c7faa8758ec13f6d53a01d8d6c874f9ccb870a", - "dweb:/ipfs/QmQoadeFhNndmE4JEzxpcr6YgHUKMPUoy1Go22hZWJk36A", - ], - license: "MIT", - }, - }, - version: 1, - }, id: 51, }, ] as const; diff --git a/packages/automated-dispute/src/exceptions/eboProcessor/index.ts b/packages/automated-dispute/src/exceptions/eboProcessor/index.ts index ee485fe..bd6ba41 100644 --- a/packages/automated-dispute/src/exceptions/eboProcessor/index.ts +++ b/packages/automated-dispute/src/exceptions/eboProcessor/index.ts @@ -1 +1,2 @@ +export * from "./pendingModulesApproval.exception.js"; export * from "./processorAlreadyStarted.exception.js"; diff --git a/packages/automated-dispute/src/exceptions/eboProcessor/pendingModulesApproval.exception.ts b/packages/automated-dispute/src/exceptions/eboProcessor/pendingModulesApproval.exception.ts new file mode 100644 index 0000000..79f70a0 --- /dev/null +++ b/packages/automated-dispute/src/exceptions/eboProcessor/pendingModulesApproval.exception.ts @@ -0,0 +1,21 @@ +import { AccountingModules } from "../../types/index.js"; + +export class PendingModulesApproval extends Error { + constructor( + public readonly approvedModules: Partial, + public readonly pendingModules: Partial, + ) { + const approvedModulesStr = Object.entries(approvedModules) + .map(([key, value]) => `(${key}: ${value})`) + .join(", "); + + const pendingModulesStr = Object.entries(pendingModules) + .map(([key, value]) => `(${key}: ${value})`) + .join(", "); + + super( + `Modules approved: ${approvedModulesStr}\n` + + `Modules pending approval: ${pendingModulesStr}`, + ); + } +} diff --git a/packages/automated-dispute/src/external.ts b/packages/automated-dispute/src/external.ts index 2f6b514..db6ab76 100644 --- a/packages/automated-dispute/src/external.ts +++ b/packages/automated-dispute/src/external.ts @@ -1 +1,3 @@ export { EboProcessor, EboActorsManager } from "./services/index.js"; +export { ProtocolProvider } from "./providers/index.js"; +export type { AccountingModules } from "./types/index.js"; diff --git a/packages/automated-dispute/src/interfaces/protocolProvider.ts b/packages/automated-dispute/src/interfaces/protocolProvider.ts index 436e57e..5508e18 100644 --- a/packages/automated-dispute/src/interfaces/protocolProvider.ts +++ b/packages/automated-dispute/src/interfaces/protocolProvider.ts @@ -39,6 +39,20 @@ export interface IReadProvider { * @returns A promise that resolves with an array of chain IDs. */ getAvailableChains(): Promise; + + /** + * Gets the address of the accounting module. + * + * @returns An address that points to the deployed accounting module. + */ + getAccountingModuleAddress(): Address; + + /** + * Gets the list of approved modules' addresses based on the wallet's account address. + * + * @returns A promise that resolves with an array of approved modules. + */ + getAccountingApprovedModules(): Promise; } /** @@ -140,6 +154,13 @@ export interface IWriteProvider { * @returns A promise that resolves when the request is finalized. */ finalize(request: Request["prophetData"], response: Response["prophetData"]): Promise; + + /** + * Approves modules needed by the accounting contract. + * + * @param modules an array of addresses for the modules to be approved + */ + approveAccountingModules(modules: Address[]): Promise; } /** diff --git a/packages/automated-dispute/src/providers/protocolProvider.ts b/packages/automated-dispute/src/providers/protocolProvider.ts index 7f91d7c..e68e1e8 100644 --- a/packages/automated-dispute/src/providers/protocolProvider.ts +++ b/packages/automated-dispute/src/providers/protocolProvider.ts @@ -143,6 +143,7 @@ export class ProtocolProvider implements IProtocolProvider { settleDispute: this.settleDispute.bind(this), escalateDispute: this.escalateDispute.bind(this), finalize: this.finalize.bind(this), + approveAccountingModules: this.approveAccountingModules.bind(this), }; public read: IReadProvider = { @@ -150,6 +151,8 @@ export class ProtocolProvider implements IProtocolProvider { getLastFinalizedBlock: this.getLastFinalizedBlock.bind(this), getEvents: this.getEvents.bind(this), getAvailableChains: this.getAvailableChains.bind(this), + getAccountingModuleAddress: this.getAccountingModuleAddress.bind(this), + getAccountingApprovedModules: this.getAccountingApprovedModules.bind(this), }; /** @@ -269,6 +272,20 @@ export class ProtocolProvider implements IProtocolProvider { return ["eip155:1", "eip155:42161"]; } + getAccountingModuleAddress(): Address { + // TODO: implement actual method + return "0x01"; + } + + async getAccountingApprovedModules(): Promise { + // TODO: implement actual method + return []; + } + + async approveAccountingModules(_modules: Address[]): Promise { + // TODO: implement actual method + } + /** * Creates a request on the EBO Request Creator contract by simulating the transaction * and then executing it if the simulation is successful. diff --git a/packages/automated-dispute/src/services/eboProcessor.ts b/packages/automated-dispute/src/services/eboProcessor.ts index 2a7b168..a7a856e 100644 --- a/packages/automated-dispute/src/services/eboProcessor.ts +++ b/packages/automated-dispute/src/services/eboProcessor.ts @@ -3,11 +3,22 @@ import { BlockNumberService } from "@ebo-agent/blocknumber"; import { Caip2ChainId } from "@ebo-agent/blocknumber/dist/types.js"; import { Address, EBO_SUPPORTED_CHAIN_IDS, ILogger } from "@ebo-agent/shared"; -import { ProcessorAlreadyStarted } from "../exceptions/index.js"; +import { PendingModulesApproval, ProcessorAlreadyStarted } from "../exceptions/index.js"; import { isRequestCreatedEvent } from "../guards.js"; import { ProtocolProvider } from "../providers/protocolProvider.js"; -import { alreadyDeletedActorWarning, droppingUnhandledEventsWarning } from "../templates/index.js"; -import { ActorRequest, EboEvent, EboEventName, Epoch, RequestId } from "../types/index.js"; +import { + alreadyDeletedActorWarning, + droppingUnhandledEventsWarning, + pendingApprovedModulesError, +} from "../templates/index.js"; +import { + AccountingModules, + ActorRequest, + EboEvent, + EboEventName, + Epoch, + RequestId, +} from "../types/index.js"; import { EboActorsManager } from "./eboActorsManager.js"; const DEFAULT_MS_BETWEEN_CHECKS = 10 * 60 * 1000; // 10 minutes @@ -19,6 +30,7 @@ export class EboProcessor { private lastCheckedBlock?: bigint; constructor( + private readonly accountingModules: AccountingModules, private readonly protocolProvider: ProtocolProvider, private readonly blockNumberService: BlockNumberService, private readonly actorsManager: EboActorsManager, @@ -33,6 +45,8 @@ export class EboProcessor { public async start(msBetweenChecks: number = DEFAULT_MS_BETWEEN_CHECKS) { if (this.eventsInterval) throw new ProcessorAlreadyStarted(); + await this.checkAllModulesApproved(); + await this.sync(); // Bootstrapping this.eventsInterval = setInterval(async () => { @@ -48,6 +62,42 @@ export class EboProcessor { }, msBetweenChecks); } + /** + * Check if all the modules have been granted approval within the accounting module. + * + * @throws {PendingModulesApproval} when there is at least one module pending approval + */ + private async checkAllModulesApproved() { + const approvedModules: Address[] = + await this.protocolProvider.getAccountingApprovedModules(); + + const summary: Record<"approved" | "notApproved", Partial> = { + approved: {}, + notApproved: {}, + }; + + for (const [moduleName, moduleAddress] of Object.entries(this.accountingModules)) { + const isApproved = approvedModules.includes(moduleAddress); + const key = isApproved ? "approved" : "notApproved"; + + summary[key][moduleName as keyof AccountingModules] = moduleAddress; + } + + if (Object.keys(summary.notApproved).length > 0) { + const accountingModuleAddress = this.protocolProvider.getAccountingModuleAddress(); + + this.logger.error( + pendingApprovedModulesError( + accountingModuleAddress, + summary["approved"], + summary["notApproved"], + ), + ); + + throw new PendingModulesApproval(summary["approved"], summary["notApproved"]); + } + } + /** Sync new blocks and their events with their corresponding actors. */ private async sync() { try { diff --git a/packages/automated-dispute/src/templates/index.ts b/packages/automated-dispute/src/templates/index.ts index b3e63b2..1a3bdd5 100644 --- a/packages/automated-dispute/src/templates/index.ts +++ b/packages/automated-dispute/src/templates/index.ts @@ -1,4 +1,6 @@ -import { RequestId } from "../types/prophet.js"; +import { Address } from "viem"; + +import { AccountingModules, RequestId } from "../types/prophet.js"; export const alreadyDeletedActorWarning = (requestId: RequestId) => ` Actor handling request ${requestId} was already deleted. @@ -11,3 +13,32 @@ Dropping events for request ${requestId} because no actor is handling it and the The request likely started before the current epoch's first block, which will not be handled by the agent. `; + +export const pendingApprovedModulesError = ( + horizonAddress: Address, + approvedModules: Partial, + notApprovedModules: Partial, +) => { + const approvedModulesList = Object.entries(approvedModules).map( + ([key, value]) => `* ${key} at ${value}\n`, + ); + const notApprovedModulesList = Object.entries(notApprovedModules).map( + ([key, value]) => `* ${key} at ${value}\n`, + ); + + return ` +The EBO agent cannot proceed until certain actions are resolved by the operator. + +The following modules already have approvals from HorizonAccountingExtension at ${horizonAddress}: +${approvedModulesList} + +The following modules need approval from HorizonAccountingExtension at ${horizonAddress}: +${notApprovedModulesList} + +To grant the necessary approvals, please run the script located at: + +apps/scripts/approveAccountingModules.ts + +Once approvals are completed, restart the EBO agent to continue. +`; +}; diff --git a/packages/automated-dispute/src/types/prophet.ts b/packages/automated-dispute/src/types/prophet.ts index 61da3da..4eca728 100644 --- a/packages/automated-dispute/src/types/prophet.ts +++ b/packages/automated-dispute/src/types/prophet.ts @@ -72,3 +72,9 @@ export interface Dispute { requestId: RequestId; }; } + +export type AccountingModules = { + requestModule: Address; + responseModule: Address; + escalationModule: Address; +}; diff --git a/packages/automated-dispute/tests/mocks/eboProcessor.mocks.ts b/packages/automated-dispute/tests/mocks/eboProcessor.mocks.ts index 1bca810..f678dc7 100644 --- a/packages/automated-dispute/tests/mocks/eboProcessor.mocks.ts +++ b/packages/automated-dispute/tests/mocks/eboProcessor.mocks.ts @@ -5,12 +5,20 @@ import { ILogger } from "@ebo-agent/shared"; import { ProtocolProvider } from "../../src/providers/index.js"; import { EboProcessor } from "../../src/services"; import { EboActorsManager } from "../../src/services/index.js"; +import { AccountingModules } from "../../src/types/prophet.js"; import { DEFAULT_MOCKED_PROTOCOL_CONTRACTS, mockedPrivateKey, } from "../services/eboActor/fixtures.js"; -export function buildEboProcessor(logger: ILogger) { +export function buildEboProcessor( + logger: ILogger, + accountingModules: AccountingModules = { + requestModule: "0x01", + responseModule: "0x02", + escalationModule: "0x03", + }, +) { const protocolProviderRpcUrls = ["http://localhost:8538"]; const protocolProvider = new ProtocolProvider( protocolProviderRpcUrls, @@ -24,7 +32,14 @@ export function buildEboProcessor(logger: ILogger) { const blockNumberService = new BlockNumberService(blockNumberRpcUrls, logger); const actorsManager = new EboActorsManager(); - const processor = new EboProcessor(protocolProvider, blockNumberService, actorsManager, logger); + + const processor = new EboProcessor( + accountingModules, + protocolProvider, + blockNumberService, + actorsManager, + logger, + ); return { processor, diff --git a/packages/automated-dispute/tests/services/eboProcessor.spec.ts b/packages/automated-dispute/tests/services/eboProcessor.spec.ts index 0fa62d3..cc352a5 100644 --- a/packages/automated-dispute/tests/services/eboProcessor.spec.ts +++ b/packages/automated-dispute/tests/services/eboProcessor.spec.ts @@ -2,14 +2,27 @@ import { BlockNumberService } from "@ebo-agent/blocknumber"; import { Caip2ChainId } from "@ebo-agent/blocknumber/dist/types.js"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { ProcessorAlreadyStarted } from "../../src/exceptions/index.js"; +import { PendingModulesApproval, ProcessorAlreadyStarted } from "../../src/exceptions/index.js"; import { ProtocolProvider } from "../../src/providers/index.js"; -import { EboEvent, EboEventName, Epoch, RequestId } from "../../src/types/index.js"; +import { + AccountingModules, + EboEvent, + EboEventName, + Epoch, + RequestId, +} from "../../src/types/index.js"; import mocks from "../mocks/index.js"; import { DEFAULT_MOCKED_REQUEST_CREATED_DATA } from "../services/eboActor/fixtures.js"; const logger = mocks.mockLogger(); const msBetweenChecks = 1; +const accountingModules: AccountingModules = { + requestModule: "0x01", + responseModule: "0x02", + escalationModule: "0x03", +}; + +const allModulesApproved = Object.values(accountingModules); describe("EboProcessor", () => { describe("start", () => { @@ -23,8 +36,24 @@ describe("EboProcessor", () => { vi.useRealTimers(); }); + it("throws if at least one module is pending approval", async () => { + const { processor, protocolProvider } = mocks.buildEboProcessor( + logger, + accountingModules, + ); + + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue([]); + + const result = processor.start(); + + expect(result).rejects.toThrow(PendingModulesApproval); + }); + it("bootstraps actors with onchain active requests when starting", async () => { - const { processor, actorsManager, protocolProvider } = mocks.buildEboProcessor(logger); + const { processor, actorsManager, protocolProvider } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const currentEpoch: Epoch = { number: 1n, @@ -45,6 +74,9 @@ describe("EboProcessor", () => { }, }; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue( currentEpoch.firstBlockNumber + 10n, @@ -97,6 +129,9 @@ describe("EboProcessor", () => { }, }; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue( currentEpoch.firstBlockNumber + 10n, @@ -119,6 +154,9 @@ describe("EboProcessor", () => { startTimestamp: BigInt(Date.UTC(2024, 1, 1, 0, 0, 0, 0)), }; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue( currentEpoch.firstBlockNumber + 10n, @@ -131,7 +169,10 @@ describe("EboProcessor", () => { }); it("fetches events since epoch start when starting", async () => { - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const { actor } = mocks.buildEboActor(request, logger); const currentEpoch = { @@ -155,6 +196,9 @@ describe("EboProcessor", () => { }, }; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock); vi.spyOn(actorsManager, "createActor").mockReturnValue(actor); @@ -173,7 +217,10 @@ describe("EboProcessor", () => { it("keeps the last block checked unaltered when something fails during sync", async () => { const initialCurrentBlock = 1n; - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const { actor } = mocks.buildEboActor(request, logger); const currentEpoch = { @@ -190,6 +237,10 @@ describe("EboProcessor", () => { }) .mockResolvedValueOnce([]); + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); + vi.spyOn(protocolProvider, "getLastFinalizedBlock") .mockResolvedValueOnce(initialCurrentBlock + 10n) .mockResolvedValueOnce(initialCurrentBlock + 20n); @@ -221,7 +272,10 @@ describe("EboProcessor", () => { }); it("fetches non-consumed events if event fetching fails", async () => { - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const { actor } = mocks.buildEboActor(request, logger); const mockLastCheckedBlock = 5n; @@ -248,6 +302,9 @@ describe("EboProcessor", () => { }, }; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock); vi.spyOn(actorsManager, "createActor").mockReturnValue(actor); @@ -266,7 +323,10 @@ describe("EboProcessor", () => { }); it("enqueues and process every new event into the actor", async () => { - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const currentEpoch = { number: 1n, @@ -276,6 +336,9 @@ describe("EboProcessor", () => { const currentBlock = currentEpoch.firstBlockNumber + 10n; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock); @@ -329,7 +392,10 @@ describe("EboProcessor", () => { }); it("enqueues events into corresponding actors", async () => { - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const currentEpoch = { number: 1n, @@ -339,6 +405,9 @@ describe("EboProcessor", () => { const currentBlock = currentEpoch.firstBlockNumber + 10n; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock); @@ -420,7 +489,10 @@ describe("EboProcessor", () => { it.skip("notifies if an actor throws while handling events"); it("creates a request when no actor is handling a chain's current epoch", async () => { - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const currentEpoch = { number: 1n, @@ -428,6 +500,9 @@ describe("EboProcessor", () => { startTimestamp: BigInt(Date.UTC(2024, 1, 1, 0, 0, 0, 0)), }; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(1n); vi.spyOn(protocolProvider, "getEvents").mockResolvedValue([]); @@ -452,7 +527,10 @@ describe("EboProcessor", () => { }); it("does not create a new request if a corresponding actor already exist", async () => { - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const currentEpoch = { number: 1n, @@ -460,6 +538,9 @@ describe("EboProcessor", () => { startTimestamp: BigInt(Date.UTC(2024, 1, 1, 0, 0, 0, 0)), }; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(1n); vi.spyOn(protocolProvider, "getEvents").mockResolvedValue([]); @@ -483,7 +564,10 @@ describe("EboProcessor", () => { }); it("handles errors during request creation", async () => { - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const currentEpoch = { epoch: 1n, @@ -491,6 +575,9 @@ describe("EboProcessor", () => { startTimestamp: BigInt(Date.UTC(2024, 1, 1, 0, 0, 0, 0)), }; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(1n); vi.spyOn(protocolProvider, "getEvents").mockResolvedValue([]); @@ -510,7 +597,10 @@ describe("EboProcessor", () => { it.skip("notifies if a request failed to be created"); it("removes the actor from registry when terminating", async () => { - const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor(logger); + const { processor, protocolProvider, actorsManager } = mocks.buildEboProcessor( + logger, + accountingModules, + ); const currentEpoch = { currentEpoch: 1n, @@ -520,6 +610,9 @@ describe("EboProcessor", () => { const currentBlock = currentEpoch.currentEpochBlockNumber + 10n; + vi.spyOn(protocolProvider, "getAccountingApprovedModules").mockResolvedValue( + allModulesApproved, + ); vi.spyOn(protocolProvider, "getCurrentEpoch").mockResolvedValue(currentEpoch); vi.spyOn(protocolProvider, "getLastFinalizedBlock").mockResolvedValue(currentBlock);