编译器
0.8.15+commit.e14f2714
文件 1 的 24:ActionAddress.sol
pragma solidity ^0.8.15;
import "./Address.sol";
import "../actions/common/Executable.sol";
library ActionAddress {
using Address for address;
function execute(address action, bytes memory callData) internal {
require(isCallingAnExecutable(callData), "OpExecutor: illegal call");
action.functionDelegateCall(callData, "OpExecutor: low-level delegatecall failed");
}
function isCallingAnExecutable(bytes memory callData) private pure returns (bool) {
bytes4 executeSelector = convertBytesToBytes4(
abi.encodeWithSelector(Executable.execute.selector)
);
bytes4 selector = convertBytesToBytes4(callData);
return selector == executeSelector;
}
function convertBytesToBytes4(bytes memory inBytes) private pure returns (bytes4 outBytes4) {
if (inBytes.length == 0) {
return 0x0;
}
assembly {
outBytes4 := mload(add(inBytes, 32))
}
}
}
文件 2 的 24:Address.sol
pragma solidity >=0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(
address target,
bytes memory data,
uint256 weiValue,
string memory errorMessage
) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
if (success) {
return returndata;
}
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
}
revert(errorMessage);
}
}
文件 3 的 24:Balancer.sol
pragma solidity ^0.8.15;
string constant BALANCER_VAULT = "BalancerVault";
文件 4 的 24:ChainLogView.sol
pragma solidity ^0.8.15;
import { IChainLog } from "../../interfaces/maker/IChainLog.sol";
contract ChainLogView {
address public immutable chainlogAddress;
constructor(address _chainlogAddress) {
chainlogAddress = _chainlogAddress;
}
function bytes32ToString(bytes32 _bytes32) public pure returns (string memory) {
uint8 i = 0;
while (i < 32 && _bytes32[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
if (_bytes32[i] == bytes1("-")) {
bytesArray[i] = bytes1("_");
} else {
bytesArray[i] = _bytes32[i];
}
}
return string(bytesArray);
}
function getServiceAddress(string calldata serviceName) public view returns (address) {
bytes32 serviceHash = bytes32(abi.encodePacked(serviceName));
return IChainLog(chainlogAddress).getAddress(serviceHash);
}
function getIlkJoinAddressByName(string calldata ilkName) public view returns (address) {
bytes32 ilkHash = bytes32(abi.encodePacked("MCD_JOIN_", ilkName));
return IChainLog(chainlogAddress).getAddress(ilkHash);
}
function getIlkJoinAddressByHash(bytes32 ilkHash) public view returns (address) {
bytes32 newIlkHash = bytes32(abi.encodePacked("MCD_JOIN_", bytes32ToString(ilkHash)));
return IChainLog(chainlogAddress).getAddress(newIlkHash);
}
}
文件 5 的 24:Common.sol
pragma solidity ^0.8.15;
string constant OPERATION_STORAGE = "OperationStorage_2";
string constant OPERATION_EXECUTOR = "OperationExecutor_2";
string constant OPERATIONS_REGISTRY = "OperationsRegistry_2";
string constant CHAINLOG_VIEWER = "ChainLogView";
string constant ONE_INCH_AGGREGATOR = "OneInchAggregator";
string constant DS_GUARD_FACTORY = "DSGuardFactory";
string constant WETH = "WETH";
string constant DAI = "DAI";
uint256 constant RAY = 10 ** 27;
bytes32 constant NULL = "";
string constant POSITION_CREATED_ACTION = "PositionCreated";
string constant UNISWAP_ROUTER = "UniswapRouter";
string constant SWAP = "Swap";
address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
文件 6 的 24:Executable.sol
pragma solidity ^0.8.15;
interface Executable {
function execute(bytes calldata data, uint8[] memory paramsMap) external payable;
}
文件 7 的 24:IAccountGuard.sol
pragma solidity >=0.8.15;
interface IAccountGuard {
function owners(address) external view returns (address);
function owner() external view returns (address);
function setWhitelist(address target, bool status) external;
function canCall(address proxy, address operator) external view returns (bool);
function permit(address caller, address target, bool allowance) external;
function isWhitelisted(address target) external view returns (bool);
function isWhitelistedSend(address target) external view returns (bool);
}
文件 8 的 24:IAccountImplementation.sol
pragma solidity >=0.8.15;
interface IAccountImplementation {
function execute(address _target, bytes memory _data) external payable returns (bytes32 response);
function send(address _target, bytes memory _data) external payable;
function owner() external view returns (address owner);
function guard() external returns (address);
}
文件 9 的 24:IChainLog.sol
pragma solidity ^0.8.15;
abstract contract IChainLog {
function getAddress(bytes32 _key) public view virtual returns (address addr);
}
文件 10 的 24:IDSProxy.sol
pragma solidity ^0.8.15;
interface IDSProxy {
function owner() external returns (address);
function execute(bytes memory, bytes memory) external payable returns (address, bytes memory);
function execute(address, bytes memory) external payable returns (bytes memory);
function setCache(address _cacheAddr) external returns (bool);
}
interface IDSAuthority {
function canCall(address, address, bytes4) external view returns (bool);
}
interface IDSAuth {
function authority() external returns (IDSAuthority);
function setAuthority(IDSAuthority) external;
}
interface IDSGuard {
function canCall(address, address, bytes4) external view returns (bool);
function permit(address, address, bytes32) external;
function forbid(address, address, bytes32) external;
}
interface IDSGuardFactory {
function newGuard() external returns (IDSGuard);
}
文件 11 的 24:IERC20.sol
pragma solidity ^0.8.15;
interface IERC20 {
function totalSupply() external view returns (uint256 supply);
function balanceOf(address _owner) external view returns (uint256 balance);
function transfer(address _to, uint256 _value) external returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
function approve(address _spender, uint256 _value) external returns (bool success);
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
function decimals() external view returns (uint256 digits);
}
文件 12 的 24:IERC3156FlashBorrower.sol
pragma solidity ^0.8.15;
interface IERC3156FlashBorrower {
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}
文件 13 的 24:IERC3156FlashLender.sol
pragma solidity ^0.8.15;
import "./IERC3156FlashBorrower.sol";
interface IERC3156FlashLender {
function maxFlashLoan(address token) external view returns (uint256);
function flashFee(address token, uint256 amount) external view returns (uint256);
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}
文件 14 的 24:IFlashLoanRecipient.sol
pragma solidity ^0.8.15;
import { IERC20 } from "../../../libs/SafeERC20.sol";
interface IFlashLoanRecipient {
function receiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external;
}
文件 15 的 24:IVault.sol
pragma solidity ^0.8.15;
import { IFlashLoanRecipient } from "../flashloan/balancer/IFlashLoanRecipient.sol";
import { IERC20 } from "../../libs/SafeERC20.sol";
interface IVault {
function flashLoan(
IFlashLoanRecipient recipient,
IERC20[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external;
}
文件 16 的 24:Maker.sol
pragma solidity ^0.8.15;
string constant FLASH_MINT_MODULE = "McdFlashMintModule";
string constant MCD_MANAGER = "McdManager";
string constant MCD_JUG = "McdJug";
string constant MCD_JOIN_DAI = "McdJoinDai";
string constant MCD_FLASH = "MCD_FLASH";
文件 17 的 24:OperationExecutor.sol
pragma solidity ^0.8.15;
import { ServiceRegistry } from "./ServiceRegistry.sol";
import { OperationStorage } from "./OperationStorage.sol";
import { OperationsRegistry } from "./OperationsRegistry.sol";
import { ActionAddress } from "../libs/ActionAddress.sol";
import { TakeFlashloan } from "../actions/common/TakeFlashloan.sol";
import { Executable } from "../actions/common/Executable.sol";
import { IERC3156FlashBorrower } from "../interfaces/flashloan/IERC3156FlashBorrower.sol";
import { IERC3156FlashLender } from "../interfaces/flashloan/IERC3156FlashLender.sol";
import { IFlashLoanRecipient } from "../interfaces/flashloan/balancer/IFlashLoanRecipient.sol";
import { IDSProxy } from "../interfaces/ds/IDSProxy.sol";
import { SafeERC20, IERC20 } from "../libs/SafeERC20.sol";
import { SafeMath } from "../libs/SafeMath.sol";
import { FlashloanData, Call } from "./types/Common.sol";
import { OPERATION_STORAGE, OPERATIONS_REGISTRY, OPERATION_EXECUTOR } from "./constants/Common.sol";
import { FLASH_MINT_MODULE } from "./constants/Maker.sol";
import { BALANCER_VAULT } from "./constants/Balancer.sol";
error UntrustedLender(address lender);
error InconsistentAsset(address flashloaned, address required);
error InconsistentAmount(uint256 flashloaned, uint256 required);
contract OperationExecutor is IERC3156FlashBorrower, IFlashLoanRecipient {
using ActionAddress for address;
using SafeERC20 for IERC20;
using SafeMath for uint256;
ServiceRegistry public immutable registry;
event Operation(bytes32 indexed name, Call[] calls);
constructor(ServiceRegistry _registry) {
registry = _registry;
}
function executeOp(Call[] memory calls, string calldata operationName) public payable {
OperationStorage opStorage = OperationStorage(registry.getRegisteredService(OPERATION_STORAGE));
opStorage.lock();
OperationsRegistry opRegistry = OperationsRegistry(
registry.getRegisteredService(OPERATIONS_REGISTRY)
);
opStorage.clearStorage();
(bytes32[] memory actions, bool[] memory optional) = opRegistry.getOperation(operationName);
opStorage.setOperationActions(actions, optional);
aggregate(calls);
opStorage.clearStorage();
opStorage.unlock();
emit Operation(bytes32(abi.encodePacked(operationName)), calls);
}
function aggregate(Call[] memory calls) internal {
OperationStorage opStorage = OperationStorage(registry.getRegisteredService(OPERATION_STORAGE));
bool hasActionsToVerify = opStorage.hasActionsToVerify();
for (uint256 current = 0; current < calls.length; current++) {
if (hasActionsToVerify) {
opStorage.verifyAction(calls[current].targetHash, calls[current].skipped);
}
if (!calls[current].skipped) {
address target = registry.getServiceAddress(calls[current].targetHash);
target.execute(calls[current].callData);
}
}
}
function callbackAggregate(Call[] memory calls) external {
require(
msg.sender == registry.getRegisteredService(OPERATION_EXECUTOR),
"OpExecutor: Caller forbidden"
);
aggregate(calls);
}
function onFlashLoan(
address initiator,
address asset,
uint256 amount,
uint256 fee,
bytes calldata data
) external override returns (bytes32) {
FlashloanData memory flData = abi.decode(data, (FlashloanData));
address lender = registry.getRegisteredService(FLASH_MINT_MODULE);
checkIfLenderIsTrusted(lender);
checkIfFlashloanedAssetIsTheRequiredOne(asset, flData.asset);
checkIfFlashloanedAmountIsTheRequiredOne(asset, flData.amount);
processFlashloan(flData, initiator);
uint256 paybackAmount = amount.add(fee);
require(
IERC20(asset).balanceOf(address(this)) >= paybackAmount,
"Insufficient funds for payback"
);
IERC20(asset).safeApprove(lender, paybackAmount);
return keccak256("ERC3156FlashBorrower.onFlashLoan");
}
function receiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory data
) external override {
address asset = address(tokens[0]);
address lender = registry.getRegisteredService(BALANCER_VAULT);
(FlashloanData memory flData, address initiator) = abi.decode(data, (FlashloanData, address));
checkIfLenderIsTrusted(lender);
checkIfFlashloanedAssetIsTheRequiredOne(asset, flData.asset);
checkIfFlashloanedAmountIsTheRequiredOne(asset, flData.amount);
processFlashloan(flData, initiator);
uint256 paybackAmount = amounts[0].add(feeAmounts[0]);
require(
IERC20(asset).balanceOf(address(this)) >= paybackAmount,
"Insufficient funds for payback"
);
IERC20(asset).safeTransfer(lender, paybackAmount);
}
function checkIfLenderIsTrusted(address lender) public view {
if (msg.sender != lender) revert UntrustedLender(msg.sender);
}
function checkIfFlashloanedAssetIsTheRequiredOne(
address flashloaned,
address required
) public pure {
if (flashloaned != required) revert InconsistentAsset(flashloaned, required);
}
function checkIfFlashloanedAmountIsTheRequiredOne(
address asset,
uint256 requiredAmount
) public view {
uint256 assetBalance = IERC20(asset).balanceOf(address(this));
if (assetBalance < requiredAmount) revert InconsistentAmount(assetBalance, requiredAmount);
}
function processFlashloan(FlashloanData memory flData, address initiator) private {
if (flData.isProxyFlashloan) {
IERC20(flData.asset).safeTransfer(initiator, flData.amount);
IDSProxy(payable(initiator)).execute(
address(this),
abi.encodeWithSelector(this.callbackAggregate.selector, flData.calls)
);
} else {
OperationStorage opStorage = OperationStorage(
registry.getRegisteredService(OPERATION_STORAGE)
);
opStorage.setInitiator(initiator);
aggregate(flData.calls);
}
}
}
文件 18 的 24:OperationStorage.sol
pragma solidity ^0.8.15;
import { ServiceRegistry } from "./ServiceRegistry.sol";
contract OperationStorage {
uint8 internal action = 0;
bytes32[] public actions;
bool[] public optionals;
mapping(address => bytes32[]) public returnValues;
address[] public valuesHolders;
bool private locked;
address private whoLocked;
address public initiator;
address immutable operationExecutorAddress;
ServiceRegistry internal immutable registry;
constructor(ServiceRegistry _registry, address _operationExecutorAddress) {
registry = _registry;
operationExecutorAddress = _operationExecutorAddress;
}
function lock() external {
locked = true;
whoLocked = msg.sender;
}
function unlock() external {
require(whoLocked == msg.sender, "Only the locker can unlock");
require(locked, "Not locked");
locked = false;
whoLocked = address(0);
}
function setInitiator(address _initiator) external {
require(msg.sender == operationExecutorAddress);
initiator = _initiator;
}
function setOperationActions(bytes32[] memory _actions, bool[] memory _optionals) external {
actions = _actions;
optionals = _optionals;
}
function verifyAction(bytes32 actionHash, bool skipped) external {
if (skipped) {
require(optionals[action], "Action cannot be skipped");
}
require(actions[action] == actionHash, "incorrect-action");
registry.getServiceAddress(actionHash);
action++;
}
function hasActionsToVerify() external view returns (bool) {
return actions.length > 0;
}
function push(bytes32 value) external {
address who = msg.sender;
if (who == operationExecutorAddress) {
who = initiator;
}
if (returnValues[who].length == 0) {
valuesHolders.push(who);
}
returnValues[who].push(value);
}
function at(uint256 index, address who) external view returns (bytes32) {
if (who == operationExecutorAddress) {
who = initiator;
}
return returnValues[who][index];
}
function len(address who) external view returns (uint256) {
if (who == operationExecutorAddress) {
who = initiator;
}
return returnValues[who].length;
}
function clearStorage() external {
delete action;
delete actions;
for (uint256 i = 0; i < valuesHolders.length; i++) {
delete returnValues[valuesHolders[i]];
}
delete valuesHolders;
}
}
文件 19 的 24:OperationsRegistry.sol
pragma solidity ^0.8.15;
import { Operation } from "./types/Common.sol";
import { OPERATIONS_REGISTRY } from "./constants/Common.sol";
struct StoredOperation {
bytes32[] actions;
bool[] optional;
string name;
}
contract OperationsRegistry {
mapping(string => StoredOperation) private operations;
address public owner;
modifier onlyOwner() {
require(msg.sender == owner, "only-owner");
_;
}
constructor() {
owner = msg.sender;
}
function transferOwnership(address newOwner) public onlyOwner {
owner = newOwner;
}
event OperationAdded(bytes32 indexed name);
function addOperation(StoredOperation calldata operation) external onlyOwner {
operations[operation.name] = operation;
emit OperationAdded(bytes32(abi.encodePacked(operation.name)));
}
function getOperation(
string memory name
) external view returns (bytes32[] memory actions, bool[] memory optional) {
if (keccak256(bytes(operations[name].name)) == keccak256(bytes(""))) {
revert("Operation doesn't exist");
}
actions = operations[name].actions;
optional = operations[name].optional;
}
}
文件 20 的 24:ProxyPermission.sol
pragma solidity ^0.8.15;
import { FlashloanData } from "../../core/types/Common.sol";
import { IAccountImplementation } from "../../interfaces/dpm/IAccountImplementation.sol";
import { IAccountGuard } from "../../interfaces/dpm/IAccountGuard.sol";
import { ServiceRegistry } from "../../core/ServiceRegistry.sol";
import { DS_GUARD_FACTORY } from "../../core/constants/Common.sol";
import { IDSGuardFactory, IDSGuard, IDSAuth, IDSAuthority } from "../../interfaces/ds/IDSProxy.sol";
contract ProxyPermission {
IDSGuardFactory internal immutable dsGuardFactory;
bytes4 public constant ALLOWED_METHOD_HASH = bytes4(keccak256("execute(address,bytes)"));
constructor(address _dsGuardFactory) {
dsGuardFactory = IDSGuardFactory(_dsGuardFactory);
}
function givePermission(bool isDPMProxy, address _contractAddr) public {
if (isDPMProxy) {
IAccountGuard(IAccountImplementation(address(this)).guard()).permit(
_contractAddr,
address(this),
true
);
} else {
address currAuthority = address(IDSAuth(address(this)).authority());
IDSGuard guard = IDSGuard(currAuthority);
if (currAuthority == address(0)) {
guard = dsGuardFactory.newGuard();
IDSAuth(address(this)).setAuthority(IDSAuthority(address(guard)));
}
if (!guard.canCall(_contractAddr, address(this), ALLOWED_METHOD_HASH)) {
guard.permit(_contractAddr, address(this), ALLOWED_METHOD_HASH);
}
}
}
function removePermission(bool isDPMProxy, address _contractAddr) public {
if (isDPMProxy) {
IAccountGuard(IAccountImplementation(address(this)).guard()).permit(
_contractAddr,
address(this),
false
);
} else {
address currAuthority = address(IDSAuth(address(this)).authority());
if (currAuthority == address(0)) {
return;
}
IDSGuard guard = IDSGuard(currAuthority);
guard.forbid(_contractAddr, address(this), ALLOWED_METHOD_HASH);
}
}
}
文件 21 的 24:SafeERC20.sol
pragma solidity >=0.8.1;
import { IERC20 } from "../interfaces/tokens/IERC20.sol";
import { Address } from "./Address.sol";
import { SafeMath } from "./SafeMath.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
);
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(
value,
"SafeERC20: decreased allowance below zero"
);
_callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
);
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 22 的 24:SafeMath.sol
pragma solidity ^0.8.15;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 23 的 24:ServiceRegistry.sol
pragma solidity ^0.8.0;
contract ServiceRegistry {
uint256 public constant MAX_DELAY = 30 days;
mapping(bytes32 => uint256) public lastExecuted;
mapping(bytes32 => address) private namedService;
mapping(bytes32 => bool) private invalidHashes;
address public owner;
uint256 public requiredDelay;
modifier validateInput(uint256 len) {
require(msg.data.length == len, "registry/illegal-padding");
_;
}
modifier delayedExecution() {
bytes32 operationHash = keccak256(msg.data);
uint256 reqDelay = requiredDelay;
if (lastExecuted[operationHash] == 0 && reqDelay > 0) {
lastExecuted[operationHash] = block.timestamp;
emit ChangeScheduled(operationHash, block.timestamp + reqDelay, msg.data);
} else {
require(block.timestamp - reqDelay > lastExecuted[operationHash], "registry/delay-too-small");
emit ChangeApplied(operationHash, block.timestamp, msg.data);
_;
lastExecuted[operationHash] = 0;
}
}
modifier onlyOwner() {
require(msg.sender == owner, "registry/only-owner");
_;
}
constructor(uint256 initialDelay) {
require(initialDelay <= MAX_DELAY, "registry/invalid-delay");
requiredDelay = initialDelay;
owner = msg.sender;
}
function transferOwnership(
address newOwner
) external onlyOwner validateInput(36) delayedExecution {
owner = newOwner;
}
function changeRequiredDelay(
uint256 newDelay
) external onlyOwner validateInput(36) delayedExecution {
require(newDelay <= MAX_DELAY, "registry/invalid-delay");
requiredDelay = newDelay;
}
function getServiceNameHash(string memory name) external pure returns (bytes32) {
return keccak256(abi.encodePacked(name));
}
function addNamedService(
bytes32 serviceNameHash,
address serviceAddress
) external onlyOwner validateInput(68) delayedExecution {
require(invalidHashes[serviceNameHash] == false, "registry/service-name-used-before");
require(namedService[serviceNameHash] == address(0), "registry/service-override");
namedService[serviceNameHash] = serviceAddress;
emit NamedServiceAdded(serviceNameHash, serviceAddress);
}
function removeNamedService(bytes32 serviceNameHash) external onlyOwner validateInput(36) {
require(namedService[serviceNameHash] != address(0), "registry/service-does-not-exist");
namedService[serviceNameHash] = address(0);
invalidHashes[serviceNameHash] = true;
emit NamedServiceRemoved(serviceNameHash);
}
function getRegisteredService(string memory serviceName) external view returns (address) {
return namedService[keccak256(abi.encodePacked(serviceName))];
}
function getServiceAddress(bytes32 serviceNameHash) external view returns (address) {
return namedService[serviceNameHash];
}
function clearScheduledExecution(
bytes32 scheduledExecution
) external onlyOwner validateInput(36) {
require(lastExecuted[scheduledExecution] > 0, "registry/execution-not-scheduled");
lastExecuted[scheduledExecution] = 0;
emit ChangeCancelled(scheduledExecution);
}
event ChangeScheduled(bytes32 dataHash, uint256 scheduledFor, bytes data);
event ChangeApplied(bytes32 dataHash, uint256 appliedAt, bytes data);
event ChangeCancelled(bytes32 dataHash);
event NamedServiceRemoved(bytes32 nameHash);
event NamedServiceAdded(bytes32 nameHash, address service);
}
文件 24 的 24:TakeFlashloan.sol
pragma solidity ^0.8.15;
import { Executable } from "../common/Executable.sol";
import { ServiceRegistry } from "../../core/ServiceRegistry.sol";
import { IVault } from "../../interfaces/balancer/IVault.sol";
import { IERC3156FlashBorrower } from "../../interfaces/flashloan/IERC3156FlashBorrower.sol";
import { IERC3156FlashLender } from "../../interfaces/flashloan/IERC3156FlashLender.sol";
import { IFlashLoanRecipient } from "../../interfaces/flashloan/balancer/IFlashLoanRecipient.sol";
import { FlashloanData, FlashloanProvider } from "../../core/types/Common.sol";
import { OPERATION_EXECUTOR, DAI, CHAINLOG_VIEWER } from "../../core/constants/Common.sol";
import { MCD_FLASH } from "../../core/constants/Maker.sol";
import { BALANCER_VAULT } from "../../core/constants/Balancer.sol";
import { ChainLogView } from "../../core/views/ChainLogView.sol";
import { ProxyPermission } from "../../libs/DS/ProxyPermission.sol";
import { IERC20 } from "../../libs/SafeERC20.sol";
contract TakeFlashloan is Executable, ProxyPermission {
address internal immutable dai;
ServiceRegistry private immutable registry;
constructor(
ServiceRegistry _registry,
address _dai,
address _dsGuardFactory
) ProxyPermission(_dsGuardFactory) {
registry = _registry;
dai = _dai;
}
function execute(bytes calldata data, uint8[] memory) external payable override {
FlashloanData memory flData = parseInputs(data);
address operationExecutorAddress = registry.getRegisteredService(OPERATION_EXECUTOR);
if (flData.isProxyFlashloan) {
givePermission(flData.isDPMProxy, operationExecutorAddress);
}
if (flData.provider == FlashloanProvider.DssFlash) {
ChainLogView chainlogView = ChainLogView(registry.getRegisteredService(CHAINLOG_VIEWER));
IERC3156FlashLender(chainlogView.getServiceAddress(MCD_FLASH)).flashLoan(
IERC3156FlashBorrower(operationExecutorAddress),
dai,
flData.amount,
abi.encode(flData, address(this))
);
}
if (flData.provider == FlashloanProvider.Balancer) {
IERC20[] memory tokens = new IERC20[](1);
uint256[] memory amounts = new uint256[](1);
tokens[0] = IERC20(flData.asset);
amounts[0] = flData.amount;
IVault(registry.getRegisteredService(BALANCER_VAULT)).flashLoan(
IFlashLoanRecipient(operationExecutorAddress),
tokens,
amounts,
abi.encode(flData, address(this))
);
}
if (flData.isProxyFlashloan) {
removePermission(flData.isDPMProxy, operationExecutorAddress);
}
}
function parseInputs(bytes memory _callData) public pure returns (FlashloanData memory params) {
return abi.decode(_callData, (FlashloanData));
}
}
{
"compilationTarget": {
"contracts/core/OperationExecutor.sol": "OperationExecutor"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract ServiceRegistry","name":"_registry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"flashloaned","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InconsistentAmount","type":"error"},{"inputs":[{"internalType":"address","name":"flashloaned","type":"address"},{"internalType":"address","name":"required","type":"address"}],"name":"InconsistentAsset","type":"error"},{"inputs":[{"internalType":"address","name":"lender","type":"address"}],"name":"UntrustedLender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"name","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"targetHash","type":"bytes32"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bool","name":"skipped","type":"bool"}],"indexed":false,"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"name":"Operation","type":"event"},{"inputs":[{"components":[{"internalType":"bytes32","name":"targetHash","type":"bytes32"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bool","name":"skipped","type":"bool"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"name":"callbackAggregate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"requiredAmount","type":"uint256"}],"name":"checkIfFlashloanedAmountIsTheRequiredOne","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"flashloaned","type":"address"},{"internalType":"address","name":"required","type":"address"}],"name":"checkIfFlashloanedAssetIsTheRequiredOne","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"lender","type":"address"}],"name":"checkIfLenderIsTrusted","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"targetHash","type":"bytes32"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bool","name":"skipped","type":"bool"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"},{"internalType":"string","name":"operationName","type":"string"}],"name":"executeOp","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onFlashLoan","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"feeAmounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"receiveFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract ServiceRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"}]