Description:
Smart contract deployed on Ethereum with Factory features.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/OPFaultGameFinder.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
// https://github.com/ethereum-optimism/optimism/issues/11269
// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol
interface IOptimismPortal {
function disputeGameFactory() external view returns (IDisputeGameFactory);
function respectedGameType() external view returns (uint256);
function disputeGameBlacklist(
IDisputeGame game
) external view returns (bool);
function disputeGameFinalityDelaySeconds() external view returns (uint256);
function respectedGameTypeUpdatedAt() external view returns (uint64);
}
// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGameFactory.sol
interface IDisputeGameFactory {
function gameCount() external view returns (uint256);
function gameAtIndex(
uint256 index
)
external
view
returns (uint256 gameType, uint256 created, IDisputeGame gameProxy);
}
// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGame.sol
interface IDisputeGame {
function status() external view returns (uint256);
function l2BlockNumber() external view returns (uint256);
function rootClaim() external view returns (bytes32);
function resolvedAt() external view returns (uint64);
}
struct FinalizationParams {
uint256 finalityDelay;
uint64 gameTypeUpdatedAt;
}
// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/lib/Types.sol#L7
uint256 constant CHALLENGER_WINS = 1;
uint256 constant DEFENDER_WINS = 2;
// https://github.com/ethereum-optimism/optimism/blob/42acc178b262b4cdcc75f9b3f4f63941c65bcb8a/packages/contracts-bedrock/interfaces/dispute/IFaultDisputeGame.sol
interface IFaultDisputeGame {
function l2BlockNumberChallenged() external view returns (bool);
}
// https://github.com/ethereum-optimism/optimism/blob/42acc178b262b4cdcc75f9b3f4f63941c65bcb8a/packages/contracts-bedrock/src/dispute/lib/Types.sol
uint32 constant GAME_TYPE_CANNON = 0;
uint32 constant GAME_TYPE_PERMISSIONED_CANNON = 1;
error GameNotFound();
contract OPFaultGameFinder {
function findGameIndex(
IOptimismPortal portal,
uint256 minAgeSec,
uint256[] memory allowedGameTypes,
uint256 gameCount
) external view virtual returns (uint256) {
FinalizationParams memory finalizationParams = FinalizationParams({
finalityDelay: portal.disputeGameFinalityDelaySeconds(),
gameTypeUpdatedAt: portal.respectedGameTypeUpdatedAt()
});
IDisputeGameFactory factory = portal.disputeGameFactory();
if (gameCount == 0) gameCount = factory.gameCount();
while (gameCount > 0) {
(
uint256 gameType,
uint256 created,
IDisputeGame gameProxy
) = factory.gameAtIndex(--gameCount);
if (
_isGameUsable(
portal,
gameProxy,
gameType,
created,
allowedGameTypes,
minAgeSec,
finalizationParams
)
) {
return gameCount;
}
}
revert GameNotFound();
}
function gameAtIndex(
IOptimismPortal portal,
uint256 minAgeSec,
uint256[] memory allowedGameTypes,
uint256 gameIndex
)
external
view
returns (
uint256 gameType,
uint256 created,
IDisputeGame gameProxy,
uint256 l2BlockNumber,
bytes32 rootClaim
)
{
FinalizationParams memory finalizationParams = FinalizationParams({
finalityDelay: portal.disputeGameFinalityDelaySeconds(),
gameTypeUpdatedAt: portal.respectedGameTypeUpdatedAt()
});
IDisputeGameFactory factory = portal.disputeGameFactory();
(gameType, created, gameProxy) = factory.gameAtIndex(gameIndex);
if (
_isGameUsable(
portal,
gameProxy,
gameType,
created,
allowedGameTypes,
minAgeSec,
finalizationParams
)
) {
l2BlockNumber = gameProxy.l2BlockNumber();
rootClaim = gameProxy.rootClaim();
}
}
function _isGameUsable(
IOptimismPortal portal,
IDisputeGame gameProxy,
uint256 gameType,
uint256 created,
uint256[] memory allowedGameTypes,
uint256 minAgeSec,
FinalizationParams memory finalizationParams
) internal view returns (bool) {
if (!_isAllowedGameType(gameType, allowedGameTypes)) return false;
// https://specs.optimism.io/fault-proof/stage-one/bridge-integration.html#blacklisting-disputegames
if (portal.disputeGameBlacklist(gameProxy)) return false;
if (minAgeSec > 0) {
if (created > block.timestamp - minAgeSec) return false;
if (
gameType == GAME_TYPE_CANNON ||
gameType == GAME_TYPE_PERMISSIONED_CANNON
) {
if (
IFaultDisputeGame(address(gameProxy))
.l2BlockNumberChallenged()
) return gameProxy.status() == DEFENDER_WINS;
return true;
}
// Testing for an unchallenged game falls back to finalized mode if unknown game type
}
if (
created > finalizationParams.gameTypeUpdatedAt &&
gameProxy.status() == DEFENDER_WINS
) {
return ((block.timestamp - gameProxy.resolvedAt()) >
finalizationParams.finalityDelay);
}
return false;
}
function _isAllowedGameType(uint256 gameType, uint256[] memory allowedGameTypes) pure internal returns (bool) {
for (uint i = 0; i < allowedGameTypes.length; i++) {
if (allowedGameTypes[i] == gameType) return true;
}
return false;
}
}
"
}
},
"settings": {
"remappings": [
"@unruggable/=lib/unruggable-gateways/",
"@eth-optimism/=lib/unruggable-gateways/lib/optimism/packages/",
"@openzeppelin/contracts/=lib/unruggable-gateways/lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/unruggable-gateways/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/unruggable-gateways/lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/unruggable-gateways/lib/forge-std/src/",
"openzeppelin-contracts/=lib/unruggable-gateways/lib/openzeppelin-contracts/",
"optimism/=lib/unruggable-gateways/lib/optimism/packages/contracts-bedrock/src/",
"unruggable-gateways/=lib/unruggable-gateways/contracts/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}
}}
Submitted on: 2025-09-29 14:10:29
Comments
Log in to comment.
No comments yet.