From eab30d339aea11ee7bd6d39c524fccee6165b2f8 Mon Sep 17 00:00:00 2001 From: jj1980a Date: Thu, 19 Sep 2024 10:30:50 +0400 Subject: [PATCH 1/7] forge fmt --- lib/forge-std | 2 +- lib/openzeppelin-contracts | 2 +- lib/openzeppelin-contracts-upgradeable | 2 +- lib/redstone-oracles-monorepo | 2 +- lib/solady | 2 +- src/contracts/atlas/Factory.sol | 4 +--- src/contracts/atlas/Storage.sol | 4 +--- src/contracts/common/ExecutionEnvironment.sol | 8 ++------ src/contracts/dapp/DAppControl.sol | 8 ++------ src/contracts/examples/ex-post-mev-example/V2ExPost.sol | 4 +--- src/contracts/examples/gas-filler/Filler.sol | 4 +--- .../examples/intents-example/SwapIntentDAppControl.sol | 4 +--- src/contracts/examples/intents-example/V4SwapIntent.sol | 8 ++------ .../examples/oev-example/ChainlinkAtlasWrapper.sol | 4 +--- .../examples/oev-example/ChainlinkDAppControl.sol | 4 +--- .../examples/oev-example/ChainlinkDAppControlAlt.sol | 4 +--- .../examples/oev-example/IChainlinkAtlasWrapper.sol | 4 +--- .../examples/redstone-oev/RedstoneDAppControl.sol | 4 +--- src/contracts/examples/v2-example/V2DAppControl.sol | 4 +--- src/contracts/helpers/Simulator.sol | 4 +--- src/contracts/interfaces/IAtlas.sol | 4 +--- 21 files changed, 24 insertions(+), 62 deletions(-) diff --git a/lib/forge-std b/lib/forge-std index e4aef94c1..beb836e33 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit e4aef94c1768803a16fe19f7ce8b65defd027cfd +Subproject commit beb836e33f9a207f4927abb7cd09ad0afe4b3f9f diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index bd325d56b..0a25c1940 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit bd325d56b4c62c9c5c1aff048c37c6bb18ac0290 +Subproject commit 0a25c1940ca220686588c4af3ec526f725fe2582 diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable index 723f8cab0..c7c4a7bad 160000 --- a/lib/openzeppelin-contracts-upgradeable +++ b/lib/openzeppelin-contracts-upgradeable @@ -1 +1 @@ -Subproject commit 723f8cab09cdae1aca9ec9cc1cfa040c2d4b06c1 +Subproject commit c7c4a7bad2adbd23565c5aaef5a0041bde81b891 diff --git a/lib/redstone-oracles-monorepo b/lib/redstone-oracles-monorepo index 223d13e3e..c3c902af7 160000 --- a/lib/redstone-oracles-monorepo +++ b/lib/redstone-oracles-monorepo @@ -1 +1 @@ -Subproject commit 223d13e3ef3646e9ce4250d227992fed13a70a97 +Subproject commit c3c902af71097fc55626b4b1f5d4333c3be066d7 diff --git a/lib/solady b/lib/solady index bb4b43b44..b14edc51b 160000 --- a/lib/solady +++ b/lib/solady @@ -1 +1 @@ -Subproject commit bb4b43b44bec3c5d42604c08904bca0442e0bc78 +Subproject commit b14edc51bc720bacdce28bbd9e095d2662a6628f diff --git a/src/contracts/atlas/Factory.sol b/src/contracts/atlas/Factory.sol index 8766bd573..ba5c5fc5a 100644 --- a/src/contracts/atlas/Factory.sol +++ b/src/contracts/atlas/Factory.sol @@ -62,9 +62,7 @@ abstract contract Factory { /// @param userOp The user operation containing details about the user and the DAppControl contract. /// @return executionEnvironment The address of the execution environment that was found or created. /// @return dConfig The DAppConfig for the execution environment, specifying how operations should be handled. - function _getOrCreateExecutionEnvironment( - UserOperation calldata userOp - ) + function _getOrCreateExecutionEnvironment(UserOperation calldata userOp) internal returns (address executionEnvironment, DAppConfig memory dConfig) { diff --git a/src/contracts/atlas/Storage.sol b/src/contracts/atlas/Storage.sol index 416bb124d..4a20052b1 100644 --- a/src/contracts/atlas/Storage.sol +++ b/src/contracts/atlas/Storage.sol @@ -87,9 +87,7 @@ contract Storage is AtlasEvents, AtlasErrors, AtlasConstants { return S_bondedTotalSupply; } - function accessData( - address account - ) + function accessData(address account) external view returns ( diff --git a/src/contracts/common/ExecutionEnvironment.sol b/src/contracts/common/ExecutionEnvironment.sol index 48bebfadd..b818e2c22 100644 --- a/src/contracts/common/ExecutionEnvironment.sol +++ b/src/contracts/common/ExecutionEnvironment.sol @@ -40,9 +40,7 @@ contract ExecutionEnvironment is Base { /// corresponding `preOpsCall` function. /// @param userOp The UserOperation struct. /// @return preOpsData Data to be passed to the next call phase. - function preOpsWrapper( - UserOperation calldata userOp - ) + function preOpsWrapper(UserOperation calldata userOp) external validUser(userOp) onlyAtlasEnvironment @@ -64,9 +62,7 @@ contract ExecutionEnvironment is Base { /// with `userOp.data` as calldata, depending on the the needsDelegateUser flag. /// @param userOp The UserOperation struct. /// @return returnData Data to be passed to the next call phase. - function userWrapper( - UserOperation calldata userOp - ) + function userWrapper(UserOperation calldata userOp) external payable validUser(userOp) diff --git a/src/contracts/dapp/DAppControl.sol b/src/contracts/dapp/DAppControl.sol index 4095413d1..6cf5fa25d 100644 --- a/src/contracts/dapp/DAppControl.sol +++ b/src/contracts/dapp/DAppControl.sol @@ -63,9 +63,7 @@ abstract contract DAppControl is DAppControlTemplate, ExecutionBase { /// @notice The preOpsCall hook which may be called before the UserOperation is executed. /// @param userOp The UserOperation struct. /// @return data Data to be passed to the next call phase. - function preOpsCall( - UserOperation calldata userOp - ) + function preOpsCall(UserOperation calldata userOp) external payable validControl @@ -164,9 +162,7 @@ abstract contract DAppControl is DAppControlTemplate, ExecutionBase { /// @notice Returns the DAppConfig struct of this DAppControl contract. /// @param userOp The UserOperation struct. /// @return dConfig The DAppConfig struct of this DAppControl contract. - function getDAppConfig( - UserOperation calldata userOp - ) + function getDAppConfig(UserOperation calldata userOp) external view mustBeCalled diff --git a/src/contracts/examples/ex-post-mev-example/V2ExPost.sol b/src/contracts/examples/ex-post-mev-example/V2ExPost.sol index cd1f41c1a..6d7bb4948 100644 --- a/src/contracts/examples/ex-post-mev-example/V2ExPost.sol +++ b/src/contracts/examples/ex-post-mev-example/V2ExPost.sol @@ -37,9 +37,7 @@ contract V2ExPost is DAppControl { event GiftedGovernanceToken(address indexed user, address indexed token, uint256 amount); - constructor( - address _atlas - ) + constructor(address _atlas) DAppControl( _atlas, msg.sender, diff --git a/src/contracts/examples/gas-filler/Filler.sol b/src/contracts/examples/gas-filler/Filler.sol index 93deb83f7..a0e9ee643 100644 --- a/src/contracts/examples/gas-filler/Filler.sol +++ b/src/contracts/examples/gas-filler/Filler.sol @@ -269,9 +269,7 @@ contract Filler is DAppControl { delete prepaid; } - function _decodeRawData( - bytes calldata data - ) + function _decodeRawData(bytes calldata data) internal pure returns (uint256 gasNeeded, ApprovalTx memory approvalTx) diff --git a/src/contracts/examples/intents-example/SwapIntentDAppControl.sol b/src/contracts/examples/intents-example/SwapIntentDAppControl.sol index ca295009d..8aabc1b1c 100644 --- a/src/contracts/examples/intents-example/SwapIntentDAppControl.sol +++ b/src/contracts/examples/intents-example/SwapIntentDAppControl.sol @@ -40,9 +40,7 @@ contract SwapIntentDAppControl is DAppControl { uint256 public constant USER_CONDITION_GAS_LIMIT = 20_000; uint256 public constant MAX_USER_CONDITIONS = 5; - constructor( - address _atlas - ) + constructor(address _atlas) DAppControl( _atlas, msg.sender, diff --git a/src/contracts/examples/intents-example/V4SwapIntent.sol b/src/contracts/examples/intents-example/V4SwapIntent.sol index d9ef5a777..46c6f2775 100644 --- a/src/contracts/examples/intents-example/V4SwapIntent.sol +++ b/src/contracts/examples/intents-example/V4SwapIntent.sol @@ -103,9 +103,7 @@ contract V4SwapIntentControl is DAppControl { } // selector 0x04e45aaf - function exactInputSingle( - ExactInputSingleParams calldata params - ) + function exactInputSingle(ExactInputSingleParams calldata params) external payable verifyCall(params.tokenIn, params.tokenOut, params.amountIn) @@ -133,9 +131,7 @@ contract V4SwapIntentControl is DAppControl { } // selector 0x5023b4df - function exactOutputSingle( - ExactOutputSingleParams calldata params - ) + function exactOutputSingle(ExactOutputSingleParams calldata params) external payable verifyCall(params.tokenIn, params.tokenOut, params.amountInMaximum) diff --git a/src/contracts/examples/oev-example/ChainlinkAtlasWrapper.sol b/src/contracts/examples/oev-example/ChainlinkAtlasWrapper.sol index 807ecf8ed..50ab45579 100644 --- a/src/contracts/examples/oev-example/ChainlinkAtlasWrapper.sol +++ b/src/contracts/examples/oev-example/ChainlinkAtlasWrapper.sol @@ -172,9 +172,7 @@ contract ChainlinkAtlasWrapper is Ownable, IChainlinkAtlasWrapper { } // Pass-through call to base oracle's `getRoundData()` function - function getRoundData( - uint80 _roundId - ) + function getRoundData(uint80 _roundId) external view override diff --git a/src/contracts/examples/oev-example/ChainlinkDAppControl.sol b/src/contracts/examples/oev-example/ChainlinkDAppControl.sol index d7eb555e6..c13bcd6ea 100644 --- a/src/contracts/examples/oev-example/ChainlinkDAppControl.sol +++ b/src/contracts/examples/oev-example/ChainlinkDAppControl.sol @@ -53,9 +53,7 @@ contract ChainlinkDAppControl is DAppControl { event SignerRemovedForBaseFeed(address indexed baseFeed, address indexed signer); event ObservationsQuorumSet(uint256 oldQuorum, uint256 newQuorum); - constructor( - address _atlas - ) + constructor(address _atlas) DAppControl( _atlas, msg.sender, diff --git a/src/contracts/examples/oev-example/ChainlinkDAppControlAlt.sol b/src/contracts/examples/oev-example/ChainlinkDAppControlAlt.sol index 6b6599b9c..d518c4eb4 100644 --- a/src/contracts/examples/oev-example/ChainlinkDAppControlAlt.sol +++ b/src/contracts/examples/oev-example/ChainlinkDAppControlAlt.sol @@ -49,9 +49,7 @@ contract ChainlinkDAppControl is DAppControl { event SignerAddedForBaseFeed(address indexed baseFeed, address indexed signer); event SignerRemovedForBaseFeed(address indexed baseFeed, address indexed signer); - constructor( - address _atlas - ) + constructor(address _atlas) DAppControl( _atlas, msg.sender, diff --git a/src/contracts/examples/oev-example/IChainlinkAtlasWrapper.sol b/src/contracts/examples/oev-example/IChainlinkAtlasWrapper.sol index f46b40860..a45b6e7b8 100644 --- a/src/contracts/examples/oev-example/IChainlinkAtlasWrapper.sol +++ b/src/contracts/examples/oev-example/IChainlinkAtlasWrapper.sol @@ -22,9 +22,7 @@ interface AggregatorV3Interface { // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. - function getRoundData( - uint80 _roundId - ) + function getRoundData(uint80 _roundId) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); diff --git a/src/contracts/examples/redstone-oev/RedstoneDAppControl.sol b/src/contracts/examples/redstone-oev/RedstoneDAppControl.sol index 603e39382..e783af1eb 100644 --- a/src/contracts/examples/redstone-oev/RedstoneDAppControl.sol +++ b/src/contracts/examples/redstone-oev/RedstoneDAppControl.sol @@ -24,9 +24,7 @@ contract RedstoneDAppControl is DAppControl { mapping(address bundler => bool isWhitelisted) public bundlerWhitelist; uint32 public NUM_WHITELISTED_BUNDLERS = 0; - constructor( - address _atlas - ) + constructor(address _atlas) DAppControl( _atlas, msg.sender, diff --git a/src/contracts/examples/v2-example/V2DAppControl.sol b/src/contracts/examples/v2-example/V2DAppControl.sol index 95c897656..9eef3516a 100644 --- a/src/contracts/examples/v2-example/V2DAppControl.sol +++ b/src/contracts/examples/v2-example/V2DAppControl.sol @@ -51,9 +51,7 @@ contract V2DAppControl is DAppControl { event GiftedGovernanceToken(address indexed user, address indexed token, uint256 amount); - constructor( - address _atlas - ) + constructor(address _atlas) DAppControl( _atlas, msg.sender, diff --git a/src/contracts/helpers/Simulator.sol b/src/contracts/helpers/Simulator.sol index a9bbdd8d9..8d76bd618 100644 --- a/src/contracts/helpers/Simulator.sol +++ b/src/contracts/helpers/Simulator.sol @@ -37,9 +37,7 @@ contract Simulator is AtlasErrors { atlas = _atlas; } - function simUserOperation( - UserOperation calldata userOp - ) + function simUserOperation(UserOperation calldata userOp) external payable returns (bool success, Result simResult, uint256) diff --git a/src/contracts/interfaces/IAtlas.sol b/src/contracts/interfaces/IAtlas.sol index 762203e34..9bf1238b4 100644 --- a/src/contracts/interfaces/IAtlas.sol +++ b/src/contracts/interfaces/IAtlas.sol @@ -75,9 +75,7 @@ interface IAtlas { function solverLockData() external view returns (address currentSolver, bool calledBack, bool fulfilled); function totalSupply() external view returns (uint256); function bondedTotalSupply() external view returns (uint256); - function accessData( - address account - ) + function accessData(address account) external view returns ( From 4714d79dd0fa7b3e2395c8a225282ed7bde8cc15 Mon Sep 17 00:00:00 2001 From: jj1980a Date: Thu, 19 Sep 2024 15:53:32 +0400 Subject: [PATCH 2/7] add pre ops hook --- .../redstone-oev/RedstoneOevDappControl.sol | 100 +++++++++++++++--- 1 file changed, 86 insertions(+), 14 deletions(-) diff --git a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol index 623cc08f6..1b5dd7562 100644 --- a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol +++ b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol @@ -7,11 +7,16 @@ import "src/contracts/types/UserOperation.sol"; import "src/contracts/types/SolverOperation.sol"; import "./RedstoneAdapterAtlasWrapper.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; +import { IRedstoneAdapter } from + "lib/redstone-oracles-monorepo/packages/on-chain-relayer/contracts/core/IRedstoneAdapter.sol"; contract RedstoneOevDappControl is DAppControl { - error FailedToAllocateOEV(); error OnlyGovernance(); error OnlyWhitelistedBundlerAllowed(); + error OnlyWhitelistedOracleAllowed(); + error InvalidUserDestination(); + error InvalidUserEntryCall(); + error InvalidUserUpdateCall(); error OracleUpdateFailed(); uint256 public bundlerOEVPercent; @@ -22,6 +27,9 @@ contract RedstoneOevDappControl is DAppControl { mapping(address bundler => bool isWhitelisted) public bundlerWhitelist; uint32 public NUM_WHITELISTED_BUNDLERS = 0; + mapping(address oracle => bool isWhitelisted) public oracleWhitelist; + uint32 public NUM_WHITELISTED_ORACLES = 0; + constructor( address _atlas, address _atlasVault, @@ -34,14 +42,14 @@ contract RedstoneOevDappControl is DAppControl { CallConfig({ userNoncesSequential: false, dappNoncesSequential: false, - requirePreOps: false, + requirePreOps: true, trackPreOpsReturnData: false, trackUserReturnData: true, delegateUser: false, requirePreSolver: false, requirePostSolver: false, requirePostOps: false, - zeroSolvers: true, // oracle updates can be made without solvers and no OEV + zeroSolvers: true, // Oracle updates can be made without solvers and no OEV reuseUserOp: true, userAuctioneer: true, solverAuctioneer: false, @@ -52,7 +60,7 @@ contract RedstoneOevDappControl is DAppControl { trustedOpHash: false, invertBidValue: false, exPostBids: false, - allowAllocateValueFailure: true // oracle updates should go through even if OEV allocation fails + allowAllocateValueFailure: true // Oracle updates should go through even if OEV allocation fails }) ) { @@ -61,6 +69,15 @@ contract RedstoneOevDappControl is DAppControl { atlasVault = _atlasVault; } + // ---------------------------------------------------- // + // Custom Functions // + // ---------------------------------------------------- // + + modifier onlyGov() { + if (msg.sender != governance) revert OnlyGovernance(); + _; + } + function setBundlerOEVPercent(uint256 _bundlerOEVPercent) external onlyGov { require(_bundlerOEVPercent + atlasOEVPercent <= 100, "Invalid OEV percent"); bundlerOEVPercent = _bundlerOEVPercent; @@ -79,6 +96,15 @@ contract RedstoneOevDappControl is DAppControl { oracleVaults[oracle] = _oracleVault; } + // ---------------------------------------------------- // + // Bundler Related Functions // + // ---------------------------------------------------- // + + function verifyBundlerWhitelist() external view { + // Whitelisting is enforced only if the whitelist is not empty + if (NUM_WHITELISTED_BUNDLERS > 0 && !bundlerWhitelist[_bundler()]) revert OnlyWhitelistedBundlerAllowed(); + } + function addBundlerToWhitelist(address bundler) external onlyGov { if (!bundlerWhitelist[bundler]) { bundlerWhitelist[bundler] = true; @@ -93,23 +119,63 @@ contract RedstoneOevDappControl is DAppControl { } } - function _onlyGov() internal view { - if (msg.sender != governance) revert OnlyGovernance(); + // ---------------------------------------------------- // + // Oracle Related Functions // + // ---------------------------------------------------- // + + function verifyOracleWhitelist(address oracle) external view { + // Whitelisting is enforced only if the whitelist is not empty + if (NUM_WHITELISTED_ORACLES > 0 && !oracleWhitelist[oracle]) revert OnlyWhitelistedOracleAllowed(); } - modifier onlyGov() { - _onlyGov(); - _; + function addOracleToWhitelist(address oracle) external onlyGov { + if (!oracleWhitelist[oracle]) { + oracleWhitelist[oracle] = true; + NUM_WHITELISTED_ORACLES++; + } } - function verifyBundlerWhitelist() external view { - if (NUM_WHITELISTED_BUNDLERS > 0 && !bundlerWhitelist[_bundler()]) revert OnlyWhitelistedBundlerAllowed(); + function removeOracleFromWhitelist(address oracle) external onlyGov { + if (oracleWhitelist[oracle]) { + oracleWhitelist[oracle] = false; + NUM_WHITELISTED_ORACLES--; + } } // ---------------------------------------------------- // // Atlas Hook Overrides // // ---------------------------------------------------- // + /** + * @notice Checks if the bundler is whitelisted and if the user is calling the update function + * @param userOp The user operation to check + * @return An empty bytes array + */ + function _preOpsCall(UserOperation calldata userOp) internal view override returns (bytes memory) { + // The bundler must be whitelisted + RedstoneOevDappControl(_control()).verifyBundlerWhitelist(); + + // The user must be calling the present contract + if (userOp.dapp != _control()) revert InvalidUserDestination(); + + // The user must be calling the update function + if (bytes4(userOp.data) != bytes4(RedstoneOevDappControl.update.selector)) { + revert InvalidUserEntryCall(); + } + + (address oracle, bytes memory updateCallData) = abi.decode(userOp.data[4:], (address, bytes)); + + // The called oracle must be whitelisted + RedstoneOevDappControl(_control()).verifyOracleWhitelist(oracle); + + // The update call data must be a valid updateDataFeedsValues call + if (bytes4(updateCallData) != bytes4(IRedstoneAdapter.updateDataFeedsValues.selector)) { + revert InvalidUserUpdateCall(); + } + + return ""; + } + function _allocateValueCall(address, uint256 bidAmount, bytes calldata returnData) internal virtual override { if (bidAmount == 0) return; @@ -130,17 +196,23 @@ contract RedstoneOevDappControl is DAppControl { } // ---------------------------------------------------- // - // UserOp function // + // UserOp Function // // ---------------------------------------------------- // + /** + * @notice Updates the oracle with the new values + * @param oracle The oracle to update + * @param callData The call data to update the oracle with + * @return The encoded address of the updated oracle, that will be later on used in _allocateValueCall + */ function update(address oracle, bytes calldata callData) external returns (bytes memory) { - RedstoneOevDappControl(_control()).verifyBundlerWhitelist(); + // Parameters have already been validated in _preOpsCall (bool success,) = oracle.call(callData); if (!success) revert OracleUpdateFailed(); + return abi.encode(oracle); } - // NOTE: Functions below are not delegatecalled // ---------------------------------------------------- // // View Functions // // ---------------------------------------------------- // From c216e2ee7c53215fb2e25421d2b23147f6207e4e Mon Sep 17 00:00:00 2001 From: jj1980a Date: Mon, 23 Sep 2024 11:37:25 +0400 Subject: [PATCH 3/7] allocate value call function --- lib/openzeppelin-contracts | 2 +- lib/solady | 2 +- .../redstone-oev/RedstoneOevDappControl.sol | 63 +++++++++---------- 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 0a25c1940..dbb6104ce 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 0a25c1940ca220686588c4af3ec526f725fe2582 +Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 diff --git a/lib/solady b/lib/solady index b14edc51b..362b2efd2 160000 --- a/lib/solady +++ b/lib/solady @@ -1 +1 @@ -Subproject commit b14edc51bc720bacdce28bbd9e095d2662a6628f +Subproject commit 362b2efd20f38aea7252b391e5e016633ff79641 diff --git a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol index 1b5dd7562..889023b11 100644 --- a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol +++ b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol @@ -18,11 +18,12 @@ contract RedstoneOevDappControl is DAppControl { error InvalidUserEntryCall(); error InvalidUserUpdateCall(); error OracleUpdateFailed(); + error InvalidOevShare(); - uint256 public bundlerOEVPercent; - uint256 public atlasOEVPercent; - address public atlasVault; - mapping(address oracle => address oracleVault) public oracleVaults; + uint256 public constant OEV_SHARE_SCALE = 10_000; + + uint256 public oevShareBundler; // In hundredth of percent + address public oevAllocationDestination; mapping(address bundler => bool isWhitelisted) public bundlerWhitelist; uint32 public NUM_WHITELISTED_BUNDLERS = 0; @@ -32,9 +33,8 @@ contract RedstoneOevDappControl is DAppControl { constructor( address _atlas, - address _atlasVault, - uint256 _bundlerOEVPercent, - uint256 _atlasOEVPercent + uint256 _oevShareBundler, + address _oevAllocationDestination ) DAppControl( _atlas, @@ -64,9 +64,8 @@ contract RedstoneOevDappControl is DAppControl { }) ) { - bundlerOEVPercent = _bundlerOEVPercent; - atlasOEVPercent = _atlasOEVPercent; - atlasVault = _atlasVault; + oevShareBundler = _oevShareBundler; + oevAllocationDestination = _oevAllocationDestination; } // ---------------------------------------------------- // @@ -78,22 +77,13 @@ contract RedstoneOevDappControl is DAppControl { _; } - function setBundlerOEVPercent(uint256 _bundlerOEVPercent) external onlyGov { - require(_bundlerOEVPercent + atlasOEVPercent <= 100, "Invalid OEV percent"); - bundlerOEVPercent = _bundlerOEVPercent; - } - - function setAtlasOEVPercent(uint256 _atlasOEVPercent) external onlyGov { - require(_atlasOEVPercent + bundlerOEVPercent <= 100, "Invalid OEV percent"); - atlasOEVPercent = _atlasOEVPercent; - } - - function setAtlasVault(address _atlasVault) external onlyGov { - atlasVault = _atlasVault; + function setOevShareBundler(uint256 _oevShareBundler) external onlyGov { + if (_oevShareBundler > OEV_SHARE_SCALE) revert InvalidOevShare(); + oevShareBundler = _oevShareBundler; } - function setOracleVault(address oracle, address _oracleVault) external onlyGov { - oracleVaults[oracle] = _oracleVault; + function setOevAllocationDestination(address _oevAllocationDestination) external onlyGov { + oevAllocationDestination = _oevAllocationDestination; } // ---------------------------------------------------- // @@ -150,6 +140,7 @@ contract RedstoneOevDappControl is DAppControl { * @notice Checks if the bundler is whitelisted and if the user is calling the update function * @param userOp The user operation to check * @return An empty bytes array + * @dev This function is delegatcalled */ function _preOpsCall(UserOperation calldata userOp) internal view override returns (bytes memory) { // The bundler must be whitelisted @@ -176,23 +167,25 @@ contract RedstoneOevDappControl is DAppControl { return ""; } + /** + * @notice Allocates the bid amount to the relevant parties + * @param bidAmount The bid amount to be allocated + * @param returnData The return data from the user operation + */ function _allocateValueCall(address, uint256 bidAmount, bytes calldata returnData) internal virtual override { if (bidAmount == 0) return; + // Returned from the user operation address oracle = abi.decode(returnData, (address)); - uint256 oevPercentBundler = RedstoneOevDappControl(_control()).bundlerOEVPercent(); - uint256 oevPercentAtlas = RedstoneOevDappControl(_control()).atlasOEVPercent(); - address vaultAtlas = RedstoneOevDappControl(_control()).atlasVault(); - address vaultOracle = RedstoneOevDappControl(_control()).oracleVaults(oracle); - - uint256 bundlerOev = (bidAmount * oevPercentBundler) / 100; - uint256 atlasOev = (bidAmount * oevPercentAtlas) / 100; - uint256 oracleOev = bidAmount - bundlerOev - atlasOev; + // Get the OEV share for the bundler and transfer it + uint256 oevShareBundler = bidAmount * RedstoneOevDappControl(_control()).oevShareBundler() / OEV_SHARE_SCALE; + if (oevShareBundler > 0) SafeTransferLib.safeTransferETH(_bundler(), oevShareBundler); - if (oracleOev > 0) SafeTransferLib.safeTransferETH(vaultOracle, oracleOev); - if (atlasOev > 0) SafeTransferLib.safeTransferETH(vaultAtlas, atlasOev); - if (bundlerOev > 0) SafeTransferLib.safeTransferETH(_bundler(), bundlerOev); + // Transfer the rest + SafeTransferLib.safeTransferETH( + RedstoneOevDappControl(_control()).oevAllocationDestination(), bidAmount - oevShareBundler + ); } // ---------------------------------------------------- // From 2c5a4d56ad4fbcf2b5a5adbe5a1337a02b490823 Mon Sep 17 00:00:00 2001 From: jj1980a Date: Mon, 23 Sep 2024 12:10:53 +0400 Subject: [PATCH 4/7] variables naming --- .../redstone-oev/RedstoneOevDappControl.sol | 75 ++++++++++++------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol index 889023b11..d1ab229a6 100644 --- a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol +++ b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol @@ -3,13 +3,13 @@ pragma solidity 0.8.25; import { DAppControl } from "src/contracts/dapp/DAppControl.sol"; import { CallConfig } from "src/contracts/types/ConfigTypes.sol"; -import "src/contracts/types/UserOperation.sol"; -import "src/contracts/types/SolverOperation.sol"; -import "./RedstoneAdapterAtlasWrapper.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { IRedstoneAdapter } from "lib/redstone-oracles-monorepo/packages/on-chain-relayer/contracts/core/IRedstoneAdapter.sol"; +import "src/contracts/types/UserOperation.sol"; +import "src/contracts/types/SolverOperation.sol"; + contract RedstoneOevDappControl is DAppControl { error OnlyGovernance(); error OnlyWhitelistedBundlerAllowed(); @@ -19,10 +19,14 @@ contract RedstoneOevDappControl is DAppControl { error InvalidUserUpdateCall(); error OracleUpdateFailed(); error InvalidOevShare(); + error InvalidOevAllocationDestination(); uint256 public constant OEV_SHARE_SCALE = 10_000; - uint256 public oevShareBundler; // In hundredth of percent + // OEV shares are in hundredth of percent + uint256 public oevShareBundler; + uint256 public oevShareFastlane; + address public oevAllocationDestination; mapping(address bundler => bool isWhitelisted) public bundlerWhitelist; @@ -32,19 +36,20 @@ contract RedstoneOevDappControl is DAppControl { uint32 public NUM_WHITELISTED_ORACLES = 0; constructor( - address _atlas, - uint256 _oevShareBundler, - address _oevAllocationDestination + address atlas, + uint256 oevShareBundler_, + uint256 oevShareFastlane_, + address oevAllocationDestination_ ) DAppControl( - _atlas, + atlas, msg.sender, CallConfig({ userNoncesSequential: false, dappNoncesSequential: false, requirePreOps: true, trackPreOpsReturnData: false, - trackUserReturnData: true, + trackUserReturnData: false, delegateUser: false, requirePreSolver: false, requirePostSolver: false, @@ -64,8 +69,12 @@ contract RedstoneOevDappControl is DAppControl { }) ) { - oevShareBundler = _oevShareBundler; - oevAllocationDestination = _oevAllocationDestination; + if (oevShareBundler_ + oevShareFastlane_ > OEV_SHARE_SCALE) revert InvalidOevShare(); + if (oevAllocationDestination_ == address(0)) revert InvalidOevAllocationDestination(); + + oevShareBundler = oevShareBundler_; + oevShareFastlane = oevShareFastlane_; + oevAllocationDestination = oevAllocationDestination_; } // ---------------------------------------------------- // @@ -77,13 +86,19 @@ contract RedstoneOevDappControl is DAppControl { _; } - function setOevShareBundler(uint256 _oevShareBundler) external onlyGov { - if (_oevShareBundler > OEV_SHARE_SCALE) revert InvalidOevShare(); - oevShareBundler = _oevShareBundler; + function setOevShareBundler(uint256 oevShareBundler_) external onlyGov { + if (oevShareBundler_ + oevShareFastlane > OEV_SHARE_SCALE) revert InvalidOevShare(); + oevShareBundler = oevShareBundler_; } - function setOevAllocationDestination(address _oevAllocationDestination) external onlyGov { - oevAllocationDestination = _oevAllocationDestination; + function setOevShareFastlane(uint256 oevShareFastlane_) external onlyGov { + if (oevShareFastlane_ + oevShareBundler > OEV_SHARE_SCALE) revert InvalidOevShare(); + oevShareFastlane = oevShareFastlane_; + } + + function setOevAllocationDestination(address oevAllocationDestination_) external onlyGov { + if (oevAllocationDestination_ == address(0)) revert InvalidOevAllocationDestination(); + oevAllocationDestination = oevAllocationDestination_; } // ---------------------------------------------------- // @@ -154,13 +169,13 @@ contract RedstoneOevDappControl is DAppControl { revert InvalidUserEntryCall(); } - (address oracle, bytes memory updateCallData) = abi.decode(userOp.data[4:], (address, bytes)); + (address _oracle, bytes memory _updateCallData) = abi.decode(userOp.data[4:], (address, bytes)); // The called oracle must be whitelisted - RedstoneOevDappControl(_control()).verifyOracleWhitelist(oracle); + RedstoneOevDappControl(_control()).verifyOracleWhitelist(_oracle); // The update call data must be a valid updateDataFeedsValues call - if (bytes4(updateCallData) != bytes4(IRedstoneAdapter.updateDataFeedsValues.selector)) { + if (bytes4(_updateCallData) != bytes4(IRedstoneAdapter.updateDataFeedsValues.selector)) { revert InvalidUserUpdateCall(); } @@ -170,21 +185,23 @@ contract RedstoneOevDappControl is DAppControl { /** * @notice Allocates the bid amount to the relevant parties * @param bidAmount The bid amount to be allocated - * @param returnData The return data from the user operation + * @dev This function is delegatcalled */ - function _allocateValueCall(address, uint256 bidAmount, bytes calldata returnData) internal virtual override { + function _allocateValueCall(address, uint256 bidAmount, bytes calldata) internal virtual override { if (bidAmount == 0) return; - // Returned from the user operation - address oracle = abi.decode(returnData, (address)); - // Get the OEV share for the bundler and transfer it - uint256 oevShareBundler = bidAmount * RedstoneOevDappControl(_control()).oevShareBundler() / OEV_SHARE_SCALE; - if (oevShareBundler > 0) SafeTransferLib.safeTransferETH(_bundler(), oevShareBundler); + uint256 _oevShareBundler = bidAmount * RedstoneOevDappControl(_control()).oevShareBundler() / OEV_SHARE_SCALE; + if (_oevShareBundler > 0) SafeTransferLib.safeTransferETH(_bundler(), _oevShareBundler); + + // Get the OEV share for Fastlane and transfer it + uint256 _oevShareFastlane = bidAmount * RedstoneOevDappControl(_control()).oevShareFastlane() / OEV_SHARE_SCALE; + if (_oevShareFastlane > 0) SafeTransferLib.safeTransferETH(oevAllocationDestination, _oevShareFastlane); // Transfer the rest SafeTransferLib.safeTransferETH( - RedstoneOevDappControl(_control()).oevAllocationDestination(), bidAmount - oevShareBundler + RedstoneOevDappControl(_control()).oevAllocationDestination(), + bidAmount - _oevShareBundler - _oevShareFastlane ); } @@ -196,14 +213,14 @@ contract RedstoneOevDappControl is DAppControl { * @notice Updates the oracle with the new values * @param oracle The oracle to update * @param callData The call data to update the oracle with - * @return The encoded address of the updated oracle, that will be later on used in _allocateValueCall + * @return An empty bytes array */ function update(address oracle, bytes calldata callData) external returns (bytes memory) { // Parameters have already been validated in _preOpsCall (bool success,) = oracle.call(callData); if (!success) revert OracleUpdateFailed(); - return abi.encode(oracle); + return ""; } // ---------------------------------------------------- // From 0eb4b4315013c2083e3b93c53bd0ffc8f5b1cb60 Mon Sep 17 00:00:00 2001 From: jj1980a Date: Mon, 23 Sep 2024 12:16:25 +0400 Subject: [PATCH 5/7] forge update --- lib/forge-std | 2 +- lib/openzeppelin-contracts | 2 +- lib/openzeppelin-contracts-upgradeable | 2 +- lib/redstone-oracles-monorepo | 2 +- lib/solady | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/forge-std b/lib/forge-std index beb836e33..5a802d7c1 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit beb836e33f9a207f4927abb7cd09ad0afe4b3f9f +Subproject commit 5a802d7c10abb4bbfb3e7214c75052ef9e6a06f8 diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index dbb6104ce..0a25c1940 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit dbb6104ce834628e473d2173bbc9d47f81a9eec3 +Subproject commit 0a25c1940ca220686588c4af3ec526f725fe2582 diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable index c7c4a7bad..f231c5cb8 160000 --- a/lib/openzeppelin-contracts-upgradeable +++ b/lib/openzeppelin-contracts-upgradeable @@ -1 +1 @@ -Subproject commit c7c4a7bad2adbd23565c5aaef5a0041bde81b891 +Subproject commit f231c5cb86c0c045dc0b23d8f3beeaf0d68dccc7 diff --git a/lib/redstone-oracles-monorepo b/lib/redstone-oracles-monorepo index c3c902af7..97e00b4e9 160000 --- a/lib/redstone-oracles-monorepo +++ b/lib/redstone-oracles-monorepo @@ -1 +1 @@ -Subproject commit c3c902af71097fc55626b4b1f5d4333c3be066d7 +Subproject commit 97e00b4e9928061543be0fbe03bac4415430eb0f diff --git a/lib/solady b/lib/solady index 362b2efd2..42af395e6 160000 --- a/lib/solady +++ b/lib/solady @@ -1 +1 @@ -Subproject commit 362b2efd20f38aea7252b391e5e016633ff79641 +Subproject commit 42af395e631fcc9d640eddf11c57c6f1ca3f9103 From c47999f6eade718b777933ed354e26004a1773ad Mon Sep 17 00:00:00 2001 From: jj1980a Date: Mon, 23 Sep 2024 19:13:25 +0400 Subject: [PATCH 6/7] send oev share to the protocol only if positive --- .../examples/redstone-oev/RedstoneOevDappControl.sol | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol index d1ab229a6..5afd36506 100644 --- a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol +++ b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol @@ -199,10 +199,12 @@ contract RedstoneOevDappControl is DAppControl { if (_oevShareFastlane > 0) SafeTransferLib.safeTransferETH(oevAllocationDestination, _oevShareFastlane); // Transfer the rest - SafeTransferLib.safeTransferETH( - RedstoneOevDappControl(_control()).oevAllocationDestination(), - bidAmount - _oevShareBundler - _oevShareFastlane - ); + uint256 _oevShareDestination = bidAmount - _oevShareBundler - _oevShareFastlane; + if (_oevShareDestination > 0) { + SafeTransferLib.safeTransferETH( + RedstoneOevDappControl(_control()).oevAllocationDestination(), _oevShareDestination + ); + } } // ---------------------------------------------------- // From c8f98c91886c52895b433498fab7ebfce5e31319 Mon Sep 17 00:00:00 2001 From: jj1980a Date: Mon, 23 Sep 2024 19:15:39 +0400 Subject: [PATCH 7/7] rename variables --- .../redstone-oev/RedstoneOevDappControl.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol index 5afd36506..da2f73cf3 100644 --- a/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol +++ b/src/contracts/examples/redstone-oev/RedstoneOevDappControl.sol @@ -30,10 +30,10 @@ contract RedstoneOevDappControl is DAppControl { address public oevAllocationDestination; mapping(address bundler => bool isWhitelisted) public bundlerWhitelist; - uint32 public NUM_WHITELISTED_BUNDLERS = 0; + uint32 public whitelistedBundlersCount = 0; mapping(address oracle => bool isWhitelisted) public oracleWhitelist; - uint32 public NUM_WHITELISTED_ORACLES = 0; + uint32 public whitelistedOraclesCount = 0; constructor( address atlas, @@ -107,20 +107,20 @@ contract RedstoneOevDappControl is DAppControl { function verifyBundlerWhitelist() external view { // Whitelisting is enforced only if the whitelist is not empty - if (NUM_WHITELISTED_BUNDLERS > 0 && !bundlerWhitelist[_bundler()]) revert OnlyWhitelistedBundlerAllowed(); + if (whitelistedBundlersCount > 0 && !bundlerWhitelist[_bundler()]) revert OnlyWhitelistedBundlerAllowed(); } function addBundlerToWhitelist(address bundler) external onlyGov { if (!bundlerWhitelist[bundler]) { bundlerWhitelist[bundler] = true; - NUM_WHITELISTED_BUNDLERS++; + whitelistedBundlersCount++; } } function removeBundlerFromWhitelist(address bundler) external onlyGov { if (bundlerWhitelist[bundler]) { bundlerWhitelist[bundler] = false; - NUM_WHITELISTED_BUNDLERS--; + whitelistedBundlersCount--; } } @@ -130,20 +130,20 @@ contract RedstoneOevDappControl is DAppControl { function verifyOracleWhitelist(address oracle) external view { // Whitelisting is enforced only if the whitelist is not empty - if (NUM_WHITELISTED_ORACLES > 0 && !oracleWhitelist[oracle]) revert OnlyWhitelistedOracleAllowed(); + if (whitelistedOraclesCount > 0 && !oracleWhitelist[oracle]) revert OnlyWhitelistedOracleAllowed(); } function addOracleToWhitelist(address oracle) external onlyGov { if (!oracleWhitelist[oracle]) { oracleWhitelist[oracle] = true; - NUM_WHITELISTED_ORACLES++; + whitelistedOraclesCount++; } } function removeOracleFromWhitelist(address oracle) external onlyGov { if (oracleWhitelist[oracle]) { oracleWhitelist[oracle] = false; - NUM_WHITELISTED_ORACLES--; + whitelistedOraclesCount--; } }