Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 143910220 | 68 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
HookExecutor
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import {IHookExecutor, Hook} from "../interfaces/IHookExecutor.sol";
import {CallWithExactGas} from "../libraries/CallWithExactGas.sol";
/// @dev A contract for executing user-specified hooks. It ensures that
/// user-specified calls are not executed from a privileged context, and that
/// reverts do not prevent Router and borrower matching from executing.
contract HookExecutor is IHookExecutor {
using CallWithExactGas for bytes;
/// @dev The address of the Router contract.
address public immutable router;
/// @notice Gas amount reserved for the exact EXTCODESIZE call and additional overhead
/// required by the `CallWithExactGas` library to safely execute calls.
/// @dev This value should be carefully calibrated based on EVM gas costs to
/// prevent unexpected failures when making external calls with precise gas.
/// It can be updated by the Router contract if needed.
uint32 public gasForCallExactCheck = 5_000;
/// @dev Emitted after each hook is executed.
event HookExecuted(address indexed target, bool success);
/// @dev Emitted when execution of a hook fails and failure is not allowed.
event HookExecutionFailed(address indexed target, bool success);
/// @dev Emitted when the gasForCallExactCheck is set / updated.
event GasForCallExactCheckSet(uint32 gasForCallExactCheck);
/// @dev Error indicating that the contract was not called from the Router contract.
error NotRouter();
error HookExecutionFailedError(address target);
error ZeroGasForCallExactCheck();
/// @param router_ The address of the Router contract.
constructor(address router_) {
router = router_;
}
/// @dev Modifier that ensures that the `msg.sender` is the Router contract.
modifier onlyRouter() {
_onlyRouter();
_;
}
/// @dev Executes the user specified hooks. Called only by the Router contract.
/// Each hook is executed with the specified gas limit, and failure does not revert the entire transaction.
/// Each hook is only executed before the specified expiry timestamp.
/// @param hooks The hooks to execute.
function execute(Hook[] calldata hooks) external onlyRouter {
unchecked {
for (uint256 i = 0; i < hooks.length; ++i) {
Hook calldata hook = hooks[i];
(bool success,) = hook.callData
._callWithExactGasEvenIfTargetIsNoContract(hook.target, hook.gasLimit, gasForCallExactCheck);
if (!success) {
// Revert if the call fails
revert HookExecutionFailedError(hook.target);
} else {
emit HookExecuted(hook.target, success);
}
}
}
}
/// @notice Updates the gas reserved for the exact EXTCODESIZE call and related checks
/// used internally when executing hooks.
/// @dev Only callable by the Router contract.
/// @param gasForCallExactCheck_ The new gas amount to reserve for the exact call check.
/// Should be calibrated according to current gas costs of the EXTCODESIZE opcode
/// and overhead from the CallWithExactGas library.
function setGasForCallExactCheck(uint32 gasForCallExactCheck_) external onlyRouter {
require(gasForCallExactCheck_ > 0, ZeroGasForCallExactCheck());
gasForCallExactCheck = gasForCallExactCheck_;
emit GasForCallExactCheckSet(gasForCallExactCheck);
}
function _onlyRouter() internal view {
require(msg.sender == router, NotRouter());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/// @dev A user-specified hook to be executed before or after an intent.
/// @param target The address of the contract to call for the hook.
/// @param callData The calldata to be sent to the target contract for the hook execution.
/// @param gasLimit The maximum gas allowed for the hook execution.
struct Hook {
address target;
bytes callData;
uint256 gasLimit;
}
/// @notice Interface for executing an array of hooks.
interface IHookExecutor {
/// @notice Executes the provided hooks.
/// @param hooks The array of Hook structs to execute.
function execute(Hook[] calldata hooks) external;
/// @notice Sets the gas limit for exact call checks.
/// @param gasForCallExactCheck_ The new gas limit value.
function setGasForCallExactCheck(uint32 gasForCallExactCheck_) external;
/// @notice Returns the current gas limit for exact call checks.
/// @return The gas limit value.
function gasForCallExactCheck() external view returns (uint32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
/// @title CallWithExactGas Library
/// @notice This library provides multiple `callWithExactGas` functions that are resistant to gas bomb attacks.
/// @dev Assembly code is duplicated intentionally to ensure safety and maintain the structure within inline assembly blocks.
/// @notice Adapted from Chainlink: https://github.com/smartcontractkit/chainlink/blob/develop/contracts/src/v0.8/shared/call/CallWithExactGas.sol
library CallWithExactGas {
bytes4 internal constant NO_CONTRACT_SIG = 0x0c3b563c;
bytes4 internal constant NO_GAS_FOR_CALL_EXACT_CHECK_SIG = 0xafa32a2c;
bytes4 internal constant NOT_ENOUGH_GAS_FOR_CALL_SIG = 0x37c3be29;
/// @notice calls target address with exactly gasAmount gas and payload as calldata.
/// Accounts for gasForCallExactCheck gas that will be used by this function. Will revert
/// if the target is not a contact. Will revert when there is not enough gas to call the
/// target with gasAmount gas.
/// @dev Ignores the return data, which makes it immune to gas bomb attacks.
/// @return success whether the call succeeded
function _callWithExactGas(bytes memory payload, address target, uint256 gasLimit, uint32 gasForCallExactCheck)
internal
returns (bool success)
{
assembly {
// solidity calls check that a contract actually exists at the destination, so we do the same
// Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion")
// doesn't need to account for it.
if iszero(extcodesize(target)) {
mstore(0x0, NO_CONTRACT_SIG)
revert(0x0, 0x4)
}
let g := gas()
// Compute g -= gasForCallExactCheck and check for underflow
// The gas actually passed to the callee is _min(gasAmount, 63//64*gas available).
// We want to ensure that we revert if gasAmount > 63//64*gas available
// as we do not want to provide them with less, however that check itself costs
// gas. gasForCallExactCheck ensures we have at least enough gas to be able
// to revert if gasAmount > 63//64*gas available.
if lt(g, gasForCallExactCheck) {
mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG)
revert(0x0, 0x4)
}
g := sub(g, gasForCallExactCheck)
// if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150
if iszero(gt(sub(g, div(g, 64)), gasLimit)) {
mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG)
revert(0x0, 0x4)
}
// call and return whether we succeeded. ignore return data
// call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
}
return success;
}
/// @notice calls target address with exactly gasAmount gas and payload as calldata.
/// Account for gasForCallExactCheck gas that will be used by this function. Will revert
/// if the target is not a contact. Will revert when there is not enough gas to call the
/// target with gasAmount gas.
/// @dev Caps the return data length, which makes it immune to gas bomb attacks.
/// @dev Return data cap logic borrowed from
/// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol.
/// @return success whether the call succeeded
/// @return retData the return data from the call, capped at maxReturnBytes bytes
/// @return gasUsed the gas used by the external call. Does not include the overhead of this function.
function _callWithExactGasSafeReturnData(
bytes memory payload,
address target,
uint256 gasLimit,
uint32 gasForCallExactCheck,
uint16 maxReturnBytes
) internal returns (bool success, bytes memory retData, uint256 gasUsed) {
// allocate retData memory ahead of time
retData = new bytes(maxReturnBytes);
assembly {
// solidity calls check that a contract actually exists at the destination, so we do the same
// Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion")
// doesn't need to account for it.
if iszero(extcodesize(target)) {
mstore(0x0, NO_CONTRACT_SIG)
revert(0x0, 0x4)
}
let g := gas()
// Compute g -= gasForCallExactCheck and check for underflow
// The gas actually passed to the callee is _min(gasAmount, 63//64*gas available).
// We want to ensure that we revert if gasAmount > 63//64*gas available
// as we do not want to provide them with less, however that check itself costs
// gas. gasForCallExactCheck ensures we have at least enough gas to be able
// to revert if gasAmount > 63//64*gas available.
if lt(g, gasForCallExactCheck) {
mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG)
revert(0x0, 0x4)
}
g := sub(g, gasForCallExactCheck)
// if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150
if iszero(gt(sub(g, div(g, 64)), gasLimit)) {
mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG)
revert(0x0, 0x4)
}
// We save the gas before the call so we can calculate how much gas the call used
let gasBeforeCall := gas()
// call and return whether we succeeded. ignore return data
// call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
gasUsed := sub(gasBeforeCall, gas())
// limit our copy to maxReturnBytes bytes
let toCopy := returndatasize()
if gt(toCopy, maxReturnBytes) { toCopy := maxReturnBytes }
// Store the length of the copied bytes
mstore(retData, toCopy)
// copy the bytes from retData[0:_toCopy]
returndatacopy(add(retData, 0x20), 0x0, toCopy)
}
return (success, retData, gasUsed);
}
/// @notice Calls target address with exactly gasAmount gas and payload as calldata
/// or reverts if at least gasLimit gas is not available.
/// @dev Does not check if target is a contract. If it is not a contract, the low-level
/// call will still be made and it will succeed.
/// @dev Ignores the return data, which makes it immune to gas bomb attacks.
/// @return success whether the call succeeded
/// @return sufficientGas Whether there was enough gas to make the call
function _callWithExactGasEvenIfTargetIsNoContract(
bytes memory payload,
address target,
uint256 gasLimit,
uint32 gasForCallExactCheck
) internal returns (bool success, bool sufficientGas) {
assembly {
let g := gas()
// Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We
// need the cushion since the logic following the above call to gas also
// costs gas which we cannot account for exactly. So cushion is a
// conservative upper bound for the cost of this logic.
if iszero(lt(g, gasForCallExactCheck)) {
g := sub(g, gasForCallExactCheck)
// If g - g//64 <= gasAmount, we don't have enough gas. We subtract g//64 because of EIP-150.
if gt(sub(g, div(g, 64)), gasLimit) {
// Call and ignore success/return data. Note that we did not check
// whether a contract actually exists at the target address.
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
sufficientGas := true
}
}
}
return (success, sufficientGas);
}
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=dependencies/@openzeppelin-contracts-upgradeable-5.4.0/",
"@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.4.0/",
"blocklock-solidity/=dependencies/blocklock-solidity-0.2.0/src/",
"bls-solidity-0.3.0/=dependencies/bls-solidity-0.3.0/",
"bls-solidity/=dependencies/bls-solidity-0.3.0/src/",
"forge-std/=dependencies/forge-std-1.10.0/src/",
"onlyswaps-solidity/=dependencies/onlyswaps-solidity-0.7.0/src/",
"randomness-solidity/=dependencies/randomness-solidity-0.4.0/src/",
"solmate/=dependencies/solmate-89365b880c4f3c786bdd453d4b8e8fe410344a69/",
"uniswap-permit2-unlocked/=dependencies/uniswap-permit2-unlocked-1.0.0/src/",
"uniswap-permit2/=dependencies/uniswap-permit2-0x000000000022D473030F116dDEE9F6B43aC78BA3/src/",
"@ds-test/=dependencies/blocklock-solidity-0.2.0/lib/forge-std/lib/ds-test/src/",
"@openzeppelin-contracts-5.4.0/=dependencies/@openzeppelin-contracts-5.4.0/",
"@openzeppelin-contracts-upgradeable-5.4.0/=dependencies/@openzeppelin-contracts-upgradeable-5.4.0/",
"blocklock-solidity-0.2.0/=dependencies/blocklock-solidity-0.2.0/src/",
"chainlink-2.24.0/=dependencies/randomness-solidity-0.2.0/dependencies/chainlink-2.24.0/",
"ds-test/=dependencies/uniswap-permit2-unlocked-1.0.0/lib/solmate/lib/ds-test/src/",
"forge-gas-snapshot/=dependencies/uniswap-permit2-unlocked-1.0.0/lib/forge-gas-snapshot/src/",
"forge-std-1.10.0/=dependencies/forge-std-1.10.0/src/",
"onlyswaps-solidity-0.1.0/=dependencies/onlyswaps-solidity-0.1.0/src/",
"onlyswaps-solidity-0.2.0/=dependencies/onlyswaps-solidity-0.2.0/src/",
"onlyswaps-solidity-0.3.0/=dependencies/onlyswaps-solidity-0.3.0/src/",
"onlyswaps-solidity-0.4.0/=dependencies/onlyswaps-solidity-0.4.0/src/",
"onlyswaps-solidity-0.5.0/=dependencies/onlyswaps-solidity-0.5.0/src/",
"onlyswaps-solidity-0.7.0/=dependencies/onlyswaps-solidity-0.7.0/src/",
"openzeppelin-contracts/=dependencies/uniswap-permit2-unlocked-1.0.0/lib/openzeppelin-contracts/",
"randomness-solidity-0.1.0/=dependencies/randomness-solidity-0.1.0/src/",
"randomness-solidity-0.2.0/=dependencies/randomness-solidity-0.2.0/src/",
"randomness-solidity-0.3.0/=dependencies/randomness-solidity-0.3.0/src/",
"randomness-solidity-0.4.0/=dependencies/randomness-solidity-0.4.0/src/",
"solmate-89365b880c4f3c786bdd453d4b8e8fe410344a69/=dependencies/solmate-89365b880c4f3c786bdd453d4b8e8fe410344a69/src/",
"uniswap-permit2-0x000000000022D473030F116dDEE9F6B43aC78BA3/=dependencies/uniswap-permit2-0x000000000022D473030F116dDEE9F6B43aC78BA3/src/",
"uniswap-permit2-unlocked-1.0.0/=dependencies/uniswap-permit2-unlocked-1.0.0/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"router_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"HookExecutionFailedError","type":"error"},{"inputs":[],"name":"NotRouter","type":"error"},{"inputs":[],"name":"ZeroGasForCallExactCheck","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"gasForCallExactCheck","type":"uint32"}],"name":"GasForCallExactCheckSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"HookExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"HookExecutionFailed","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"internalType":"struct Hook[]","name":"hooks","type":"tuple[]"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gasForCallExactCheck","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"gasForCallExactCheck_","type":"uint32"}],"name":"setGasForCallExactCheck","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a034607c57601f6104cb38819003918201601f19168301916001600160401b03831184841017608057808492602094604052833981010312607c57516001600160a01b0381168103607c5761138863ffffffff195f5416175f556080526040516104369081610095823960805181818161016701526103720152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c8063760f2a0b14610054578063a8afbddd1461004f578063b066aafc1461004a5763f887ea4014610045575f80fd5b610152565b610130565b6100b7565b346100b35760203660031901126100b35760043567ffffffffffffffff81116100b357366023820112156100b357806004013567ffffffffffffffff81116100b3573660248260051b840101116100b35760246100b19201610196565b005b5f80fd5b346100b35760203660031901126100b35760043563ffffffff81168091036100b3576100e1610370565b8015610121576020817f75de08d29c16281a600d57180e47c4ad749f743264f4bf5670477b14871361989263ffffffff195f5416175f55604051908152a1005b6305691de360e41b5f5260045ffd5b346100b3575f3660031901126100b357602063ffffffff5f5416604051908152f35b346100b3575f3660031901126100b3576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b61019e610370565b5f915b8083106101ad57505050565b6101bb838284959694610282565b936101f96101d66101cf60208801886102b8565b36916102ff565b6101df8761035c565b6040880135906101f35f5463ffffffff1690565b926103b1565b50806102295761022661020b8761035c565b630b8b4c9960e11b5f526001600160a01b0316600452602490565b5ffd5b7fa5ce1292f71836359bea068ac79cd2424ca8f795c7421606753cb7bcbee5f3db610276600194959697610262868060a01b039161035c565b604051941515855216929081906020820190565b0390a2019192906101a1565b91908110156102a45760051b81013590605e19813603018212156100b3570190565b634e487b7160e01b5f52603260045260245ffd5b903590601e19813603018212156100b3570180359067ffffffffffffffff82116100b3576020019181360383136100b357565b634e487b7160e01b5f52604160045260245ffd5b92919267ffffffffffffffff82116103575760405191601f8101601f19908116603f0116830167ffffffffffffffff811184821017610357576040528294818452818301116100b3578281602093845f960137010152565b6102eb565b356001600160a01b03811681036100b35790565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036103a257565b639165520160e01b5f5260045ffd5b5f949385939192905a90808210156103cd575b50505050509190565b8391038060061c9003116103e3575b80806103c4565b5f949550849350839060208451940192f1906001915f80806103dc56fea26469706673582212204d12376dceb1947c84ce8f839c52cf765b533839d2b6a0764451befbc5f8686764736f6c634300081e003300000000000000000000000016323707e61d20a39aae5ab64808e480b91658ab
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c8063760f2a0b14610054578063a8afbddd1461004f578063b066aafc1461004a5763f887ea4014610045575f80fd5b610152565b610130565b6100b7565b346100b35760203660031901126100b35760043567ffffffffffffffff81116100b357366023820112156100b357806004013567ffffffffffffffff81116100b3573660248260051b840101116100b35760246100b19201610196565b005b5f80fd5b346100b35760203660031901126100b35760043563ffffffff81168091036100b3576100e1610370565b8015610121576020817f75de08d29c16281a600d57180e47c4ad749f743264f4bf5670477b14871361989263ffffffff195f5416175f55604051908152a1005b6305691de360e41b5f5260045ffd5b346100b3575f3660031901126100b357602063ffffffff5f5416604051908152f35b346100b3575f3660031901126100b3576040517f00000000000000000000000016323707e61d20a39aae5ab64808e480b91658ab6001600160a01b03168152602090f35b61019e610370565b5f915b8083106101ad57505050565b6101bb838284959694610282565b936101f96101d66101cf60208801886102b8565b36916102ff565b6101df8761035c565b6040880135906101f35f5463ffffffff1690565b926103b1565b50806102295761022661020b8761035c565b630b8b4c9960e11b5f526001600160a01b0316600452602490565b5ffd5b7fa5ce1292f71836359bea068ac79cd2424ca8f795c7421606753cb7bcbee5f3db610276600194959697610262868060a01b039161035c565b604051941515855216929081906020820190565b0390a2019192906101a1565b91908110156102a45760051b81013590605e19813603018212156100b3570190565b634e487b7160e01b5f52603260045260245ffd5b903590601e19813603018212156100b3570180359067ffffffffffffffff82116100b3576020019181360383136100b357565b634e487b7160e01b5f52604160045260245ffd5b92919267ffffffffffffffff82116103575760405191601f8101601f19908116603f0116830167ffffffffffffffff811184821017610357576040528294818452818301116100b3578281602093845f960137010152565b6102eb565b356001600160a01b03811681036100b35790565b7f00000000000000000000000016323707e61d20a39aae5ab64808e480b91658ab6001600160a01b031633036103a257565b639165520160e01b5f5260045ffd5b5f949385939192905a90808210156103cd575b50505050509190565b8391038060061c9003116103e3575b80806103c4565b5f949550849350839060208451940192f1906001915f80806103dc56fea26469706673582212204d12376dceb1947c84ce8f839c52cf765b533839d2b6a0764451befbc5f8686764736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000016323707e61d20a39aae5ab64808e480b91658ab
-----Decoded View---------------
Arg [0] : router_ (address): 0x16323707e61d20A39AaE5ab64808e480B91658aB
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000016323707e61d20a39aae5ab64808e480b91658ab
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.