Initial commit: add .gitignore and README
This commit is contained in:
195
contracts/AtomicExecutor.sol
Normal file
195
contracts/AtomicExecutor.sol
Normal file
@@ -0,0 +1,195 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/security/Pausable.sol";
|
||||
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
||||
|
||||
interface IPool {
|
||||
function flashLoanSimple(
|
||||
address receiverAddress,
|
||||
address asset,
|
||||
uint256 amount,
|
||||
bytes calldata params,
|
||||
uint16 referralCode
|
||||
) external;
|
||||
}
|
||||
|
||||
interface IFlashLoanSimpleReceiver {
|
||||
function executeOperation(
|
||||
address asset,
|
||||
uint256 amount,
|
||||
uint256 premium,
|
||||
bytes calldata params
|
||||
) external returns (bool);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title AtomicExecutor
|
||||
* @notice Executes batches of calls atomically, with optional flash loan support
|
||||
*/
|
||||
contract AtomicExecutor is Ownable, Pausable, ReentrancyGuard {
|
||||
mapping(address => bool) public allowedTargets;
|
||||
mapping(address => bool) public allowedPools; // Aave pools that can call flash loan callback
|
||||
bool public allowListEnabled;
|
||||
|
||||
event TargetAllowed(address indexed target, bool allowed);
|
||||
event PoolAllowed(address indexed pool, bool allowed);
|
||||
event BatchExecuted(address indexed caller, uint256 callCount);
|
||||
event FlashLoanExecuted(address indexed asset, uint256 amount);
|
||||
|
||||
constructor(address _owner) Ownable(_owner) {
|
||||
allowListEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Enable/disable allow list
|
||||
*/
|
||||
function setAllowListEnabled(bool _enabled) external onlyOwner {
|
||||
allowListEnabled = _enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allow/deny a target address
|
||||
*/
|
||||
function setAllowedTarget(address _target, bool _allowed) external onlyOwner {
|
||||
allowedTargets[_target] = _allowed;
|
||||
emit TargetAllowed(_target, _allowed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Batch allow/deny multiple targets
|
||||
*/
|
||||
function setAllowedTargets(address[] calldata _targets, bool _allowed) external onlyOwner {
|
||||
for (uint256 i = 0; i < _targets.length; i++) {
|
||||
allowedTargets[_targets[i]] = _allowed;
|
||||
emit TargetAllowed(_targets[i], _allowed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Execute a batch of calls atomically
|
||||
* @param targets Array of target addresses
|
||||
* @param calldatas Array of calldata for each call
|
||||
*/
|
||||
function executeBatch(
|
||||
address[] calldata targets,
|
||||
bytes[] calldata calldatas
|
||||
) external whenNotPaused nonReentrant {
|
||||
require(targets.length == calldatas.length, "Length mismatch");
|
||||
require(targets.length > 0, "Empty batch");
|
||||
|
||||
for (uint256 i = 0; i < targets.length; i++) {
|
||||
if (allowListEnabled) {
|
||||
require(allowedTargets[targets[i]], "Target not allowed");
|
||||
}
|
||||
|
||||
(bool success, bytes memory returnData) = targets[i].call(calldatas[i]);
|
||||
require(success, string(returnData));
|
||||
}
|
||||
|
||||
emit BatchExecuted(msg.sender, targets.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Execute a flash loan and callback
|
||||
* @param pool Aave v3 Pool address
|
||||
* @param asset Asset to borrow
|
||||
* @param amount Amount to borrow
|
||||
* @param targets Array of target addresses for callback
|
||||
* @param calldatas Array of calldata for callback
|
||||
*/
|
||||
function executeFlashLoan(
|
||||
address pool,
|
||||
address asset,
|
||||
uint256 amount,
|
||||
address[] calldata targets,
|
||||
bytes[] calldata calldatas
|
||||
) external whenNotPaused nonReentrant {
|
||||
require(targets.length == calldatas.length, "Length mismatch");
|
||||
|
||||
bytes memory params = abi.encode(targets, calldatas, msg.sender);
|
||||
|
||||
IPool(pool).flashLoanSimple(
|
||||
address(this),
|
||||
asset,
|
||||
amount,
|
||||
params,
|
||||
0
|
||||
);
|
||||
|
||||
emit FlashLoanExecuted(asset, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allow/deny a pool address for flash loan callbacks
|
||||
*/
|
||||
function setAllowedPool(address _pool, bool _allowed) external onlyOwner {
|
||||
allowedPools[_pool] = _allowed;
|
||||
emit PoolAllowed(_pool, _allowed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Flash loan callback (called by Aave Pool)
|
||||
*/
|
||||
function executeOperation(
|
||||
address asset,
|
||||
uint256 amount,
|
||||
uint256 premium,
|
||||
bytes calldata params
|
||||
) external returns (bool) {
|
||||
// Verify caller is an allowed Aave Pool
|
||||
require(allowedPools[msg.sender], "Unauthorized pool");
|
||||
|
||||
// Decode params
|
||||
(address[] memory targets, bytes[] memory calldatas, address initiator) = abi.decode(
|
||||
params,
|
||||
(address[], bytes[], address)
|
||||
);
|
||||
|
||||
// Verify initiator is authorized (optional check)
|
||||
require(initiator == tx.origin || initiator == address(this), "Unauthorized initiator");
|
||||
|
||||
// Execute callback operations
|
||||
for (uint256 i = 0; i < targets.length; i++) {
|
||||
if (allowListEnabled) {
|
||||
require(allowedTargets[targets[i]], "Target not allowed");
|
||||
}
|
||||
|
||||
(bool success, bytes memory returnData) = targets[i].call(calldatas[i]);
|
||||
require(success, string(returnData));
|
||||
}
|
||||
|
||||
// Approve repayment
|
||||
IERC20(asset).approve(msg.sender, amount + premium);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Pause contract
|
||||
*/
|
||||
function pause() external onlyOwner {
|
||||
_pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Unpause contract
|
||||
*/
|
||||
function unpause() external onlyOwner {
|
||||
_unpause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Emergency withdraw (owner only)
|
||||
*/
|
||||
function emergencyWithdraw(address token, uint256 amount) external onlyOwner {
|
||||
IERC20(token).transfer(owner(), amount);
|
||||
}
|
||||
}
|
||||
|
||||
interface IERC20 {
|
||||
function transfer(address to, uint256 amount) external returns (bool);
|
||||
function approve(address spender, uint256 amount) external returns (bool);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user