Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions contracts/actions/OperationData.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.7.6;
pragma abicoder v2;

struct Operation {
string name;
bytes[][] callData;
bytes32[] actionIds;
}
58 changes: 41 additions & 17 deletions contracts/actions/OperationRunner.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,51 @@ import "../interfaces/mcd/IManager.sol";
import "./ActionBase.sol";
import "hardhat/console.sol";
import "../ServiceRegistry.sol";

struct Operation {
string name;
bytes[][] callData;
bytes32[] actionIds;
address serviceRegistryAddr;
}
import "./OperationData.sol";

contract OperationRunner {
address public constant serviceRegistryAddr = 0x2B0d36FACD61B71CC05ab8F3D2355ec3631C0dd5;

function executeOperation(Operation memory operation) public payable {
_executeActions(operation);
}

function _executeActionsAfterFlashLoan(Operation memory operation, bytes32 _flashloanAmount)
public
payable
{
bytes32[] memory returnValues = new bytes32[](operation.actionIds.length);
returnValues[0] = _flashloanAmount;

for (uint256 i = 2; i < operation.actionIds.length; ++i) {
console.log("RUN THIRD OPERATION");
returnValues[i] = _executeAction(operation, i, returnValues);
}
}

function _executeActions(Operation memory operation) internal {
// address firstActionAddr = ServiceRegistry(operation.serviceRegistryAddr)
// .getServiceAddress(operation.actionIds[0]);
address firstActionAddr = ServiceRegistry(serviceRegistryAddr).getServiceAddress(
operation.actionIds[1]
);

bytes32[] memory returnValues = new bytes32[](operation.actionIds.length);

// if (isFlashLoanAction(firstActionAddr)) {
// executeFlashloan(operation, firstActionAddr, returnValues);
// } else {
for (uint256 i = 0; i < operation.actionIds.length; ++i) {
returnValues[i] = _executeAction(operation, i, returnValues);
// _executeAction(operation, i);
if (isFlashLoanAction(firstActionAddr)) {
returnValues[0] = _executeAction(operation, 0, returnValues);
returnValues[1] = _executeFlashLoan(operation, firstActionAddr, returnValues);
} else {
for (uint256 i = 0; i < operation.actionIds.length; ++i) {
returnValues[i] = _executeAction(operation, i, returnValues);
}
}
// }
}

function _executeAction(
Operation memory operation,
uint256 _index,
bytes32[] memory returnValues
) internal returns (bytes32 response) {
address actionAddress = ServiceRegistry(operation.serviceRegistryAddr).getServiceAddress(
address actionAddress = ServiceRegistry(serviceRegistryAddr).getServiceAddress(
operation.actionIds[_index]
);

Expand All @@ -52,6 +62,20 @@ contract OperationRunner {
return "";
}

function _executeFlashLoan(
Operation memory operation,
address _flashloanActionAddr,
bytes32[] memory _returnValues
) internal returns (bytes32) {
bytes memory operationFL = abi.encode(operation);
operation.callData[1][operation.callData[1].length - 1] = operationFL;

_flashloanActionAddr.delegatecall(
abi.encodeWithSignature("executeAction(bytes[])", operation.callData[1])
);
return bytes32(0);
}

function isFlashLoanAction(address actionAddr) internal pure returns (bool) {
return ActionBase(actionAddr).actionType() == uint8(ActionBase.ActionType.FLASHLOAN);
}
Expand Down
42 changes: 15 additions & 27 deletions contracts/actions/deposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,31 @@ import "./ActionBase.sol";
import "hardhat/console.sol";

contract Deposit is ActionBase {
function executeAction(bytes[] memory _callData)
public
payable
override
returns (
// ) public payable virtual override returns (bytes32) {
bytes32
)
{
(address joinAddr, address mcdManager) = parseInputs(_callData);
// address joinAddr = 0x2F0b23f53734252Bda2277357e97e1517d6B042A;
// address mcdManager = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;

// // joinAddr = _parseParamAddr(joinAddr, _paramMapping[0], _subData, _returnValues);

console.log("address this", address(this));

uint256 newVaultId = _mcdOpen(joinAddr, mcdManager);

return bytes32(newVaultId);
function executeAction(bytes[] memory _callData) public payable override returns (bytes32) {
console.log("TODO EXECUTE DEPOSIT");
}

function actionType() public pure override returns (uint8) {
return uint8(ActionType.DEFAULT);
}

function _mcdOpen(address _joinAddr, address _mcdManager) internal returns (uint256 vaultId) {
bytes32 ilk = IJoin(_joinAddr).ilk();
vaultId = IManager(_mcdManager).open(ilk, address(this));
}
function _deposit() internal returns (uint256 vaultId) {}

function parseInputs(bytes[] memory _callData)
internal
pure
returns (address joinAddr, address mcdManager)
returns (
uint256 vaultId,
uint256 amount,
address joinAddr,
address from,
address mcdManager
)
{
joinAddr = abi.decode(_callData[0], (address));
mcdManager = abi.decode(_callData[1], (address));
vaultId = abi.decode(_callData[0], (uint256));
amount = abi.decode(_callData[1], (uint256));
joinAddr = abi.decode(_callData[2], (address));
from = abi.decode(_callData[3], (address));
mcdManager = abi.decode(_callData[4], (address));
}
}
84 changes: 71 additions & 13 deletions contracts/actions/flashloan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,83 @@
pragma solidity >=0.7.6;
pragma abicoder v2;

import "../interfaces/mcd/IJoin.sol";
import "../interfaces/mcd/IManager.sol";
import "./ActionBase.sol";
import { IERC20 } from "../interfaces/IERC20.sol";
import "../flash-mint/interface/IERC3156FlashBorrower.sol";
import "../flash-mint/interface/IERC3156FlashLender.sol";
import "../ServiceRegistry.sol";
import "./OperationData.sol";
import "./OperationRunner.sol";

import "hardhat/console.sol";

contract Flashloan is ActionBase {
contract FlashLoan is ActionBase, IERC3156FlashBorrower {
address public constant serviceRegistryAddr = 0x2B0d36FACD61B71CC05ab8F3D2355ec3631C0dd5;
bytes32 constant FLASH_LOAN = keccak256("FLASH_LOAN");
bytes32 constant FLASH_LOAN_LENDER = keccak256("FLASH_LOAN_LENDER");
bytes32 constant OPERATION_RUNNER = keccak256("OPERATION_RUNNER");

address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;

function actionType() public pure override returns (uint8) {
return uint8(ActionType.FLASHLOAN);
}

function executeAction(bytes[] memory _callData)
public
payable
override
returns (
// ) public payable virtual override returns (bytes32) {
bytes32
)
{
return "";
// beforeFlashloan
function executeAction(bytes[] memory _callData) public payable override returns (bytes32) {
bytes memory operation = _callData[1];
_beforeFlashLoan(1000000, operation);
_afterFlashLoan();
return bytes32(0);
}

function _beforeFlashLoan(uint256 amount, bytes memory operation) internal {
address flashLoanLender = ServiceRegistry(serviceRegistryAddr).getServiceAddress(
FLASH_LOAN_LENDER
);
address flashLoanAction = ServiceRegistry(serviceRegistryAddr).getServiceAddress(FLASH_LOAN);

IERC3156FlashLender(flashLoanLender).flashLoan(
IERC3156FlashBorrower(flashLoanAction),
DAI,
amount,
operation
);
}

function duringFlashLoan(
Operation memory operation,
uint256 _amount,
uint256 _fee
) public payable {
uint256 balance = IERC20(DAI).balanceOf(address(this));

uint256 paybackAmount = _amount + _fee; // todo: safe math
address operationRunnerAddr = ServiceRegistry(serviceRegistryAddr).getServiceAddress(
OPERATION_RUNNER
);

OperationRunner(operationRunnerAddr)._executeActionsAfterFlashLoan(
operation,
bytes32(paybackAmount)
);
}

function _afterFlashLoan() internal {
//Todo: revoke cdpAllow
}

function onFlashLoan(
address _initiator,
address _token,
uint256 _amount,
uint256 _fee,
bytes calldata params
) external override returns (bytes32) {
Operation memory operation = abi.decode(params, (Operation));

duringFlashLoan(operation, _amount, _fee);

return keccak256("ERC3156FlashBorrower.onFlashLoan");
}
}
10 changes: 3 additions & 7 deletions contracts/actions/openVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ import "hardhat/console.sol";

contract OpenVault is ActionBase {
function executeAction(bytes[] memory _callData) public payable override returns (bytes32) {
// (address joinAddr, address mcdManager) = parseInputs(_callData);
(address joinAddr, address mcdManager) = parseInputs(_callData);

address joinAddr = 0x2F0b23f53734252Bda2277357e97e1517d6B042A;
address mcdManager = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;

uint256 newVaultId = _mcdOpen(joinAddr, mcdManager);
uint256 newVaultId = _openVault(joinAddr, mcdManager);

return bytes32(newVaultId);
}
Expand All @@ -23,14 +20,13 @@ contract OpenVault is ActionBase {
return uint8(ActionType.DEFAULT);
}

function _mcdOpen(address _joinAddr, address _mcdManager) internal returns (uint256 vaultId) {
function _openVault(address _joinAddr, address _mcdManager) internal returns (uint256 vaultId) {
bytes32 ilk = IJoin(_joinAddr).ilk();
vaultId = IManager(_mcdManager).open(ilk, address(this));
}

function parseInputs(bytes[] memory _callData)
internal
pure
returns (address joinAddr, address mcdManager)
{
joinAddr = abi.decode(_callData[0], (address));
Expand Down
57 changes: 46 additions & 11 deletions test/actions-poc-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import { balanceOf } from './utils'

import ERC20ABI from '../abi/IERC20.json'
import CDPManagerABI from '../abi/external/dss-cdp-manager.json'
import { getVaultInfo } from './common/utils/mcd.utils'
import { expectToBe, expectToBeEqual } from './common/utils/test.utils'
import { one } from './common/cosntants'
Expand Down Expand Up @@ -68,7 +69,6 @@ describe('Multiply Proxy Action with Mocked Exchange', async () => {

system = await deploySystem(provider, signer, true)


// exchangeDataMock = {
// to: system.exchangeInstance.address,
// data: 0,
Expand All @@ -95,22 +95,50 @@ describe('Multiply Proxy Action with Mocked Exchange', async () => {
})

it(`should open vault with required collateralisation ratio`, async () => {
const callData1 = ethers.utils.defaultAbiCoder.encode(["address"], [MAINNET_ADDRESSES.MCD_JOIN_ETH_A])
const callData2 = ethers.utils.defaultAbiCoder.encode(["address"], [MAINNET_ADDRESSES.CDP_MANAGER])
const openVaultCalldata = system.actionOpenVault.interface.encodeFunctionData("executeAction", [[callData1, callData2]]);
const mcdJoinEth = ethers.utils.defaultAbiCoder.encode(["address"], [MAINNET_ADDRESSES.MCD_JOIN_ETH_A])
const cdpManager = ethers.utils.defaultAbiCoder.encode(["address"], [MAINNET_ADDRESSES.CDP_MANAGER])

const operationRunnerHashName = await system.serviceRegistry.getServiceNameHash('OPERATION_RUNNER');
const openVaultHashName = await system.serviceRegistry.getServiceNameHash('OPEN_VAULT');
const flashLoanHashName = await system.serviceRegistry.getServiceNameHash('FLASH_LOAN');
const depositHashName = await system.serviceRegistry.getServiceNameHash('DEPOSIT');
const flashLoanLenderHashName = await system.serviceRegistry.getServiceNameHash('FLASH_LOAN_LENDER');

const FMM = "0x1EB4CF3A948E7D72A198fe073cCb8C7a948cD853"; // Maker Flash Mint Module

await system.serviceRegistry.addNamedService(
operationRunnerHashName,
system.operationRunner.address,
)
await system.serviceRegistry.addNamedService(
openVaultHashName,
system.actionOpenVault.address,
)

await system.serviceRegistry.addNamedService(
flashLoanHashName,
system.actionFlashLoan.address,
)
await system.serviceRegistry.addNamedService(
depositHashName,
system.actionDeposit.address,
)
await system.serviceRegistry.addNamedService(
flashLoanLenderHashName,
FMM,
)

const dsproxy_calldata = system.operationRunner.interface.encodeFunctionData("executeOperation",
[{
name: 'openVaultOperation',
callData: [[openVaultCalldata],[openVaultCalldata]],
actionIds: [openVaultHashName, openVaultHashName],
serviceRegistryAddr: system.serviceRegistry.address,
name: 'openDepositDrawDebtOperation',
callData: [
[mcdJoinEth, cdpManager],
[1000000,0],
[0, 10000, mcdJoinEth, system.userProxyAddress, cdpManager ]
],
actionIds: [
openVaultHashName,
flashLoanHashName,
depositHashName],
}]
)

Expand All @@ -120,10 +148,17 @@ describe('Multiply Proxy Action with Mocked Exchange', async () => {
gasLimit: 8500000,
gasPrice: 1000000000,
})

const lastCDP = await getLastCDP(provider, signer, system.userProxyAddress)

console.log('LAST CDP', lastCDP );

const cdpManagerContract = new ethers.Contract(MAINNET_ADDRESSES.CDP_MANAGER, CDPManagerABI, provider).connect(
signer,
)

const vaultOwner = await cdpManagerContract.owns(lastCDP.id);

expectToBeEqual(vaultOwner, system.userProxyAddress)

})
})
})
Loading