Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

alternative implementation to use FL #109

Draft
wants to merge 8 commits into
base: develop
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion contracts/flash-mint/interface/IERC3156FlashBorrower.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.6.12;
pragma solidity ^0.8.1;

interface IERC3156FlashBorrower {
/**
Expand Down
2 changes: 1 addition & 1 deletion contracts/flash-mint/interface/IERC3156FlashLender.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.6.12;
pragma solidity ^0.8.1;

import "./IERC3156FlashBorrower.sol";

Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/exchange/IExchange.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.7.0;
pragma solidity ^0.8.1;

abstract contract IExchange {
function swapDaiForToken(
Expand Down
18 changes: 18 additions & 0 deletions contracts/multiply/CdpData.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.1;

struct CdpData {
address gemJoin;
address payable fundsReceiver;
uint256 cdpId;
bytes32 ilk;
uint256 requiredDebt;
uint256 borrowCollateral;
uint256 withdrawCollateral;
uint256 withdrawDai;
uint256 depositDai;
uint256 depositCollateral;
bool skipFL;
string methodName;
Comment on lines +5 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we sticking with this struct? it has an abundance of unnecessary fields. could we maybe break it out into CloseCDPData, OpenCDPData etc

}
50 changes: 18 additions & 32 deletions contracts/multiply/MultiplyProxyActions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,14 @@ import "../interfaces/mcd/IJug.sol";
import "../interfaces/mcd/IDaiJoin.sol";
import "../interfaces/exchange/IExchange.sol";
import "./ExchangeData.sol";
import "./CdpData.sol";

import "../flash-mint/interface/IERC3156FlashBorrower.sol";
import "../flash-mint/interface/IERC3156FlashLender.sol";

pragma solidity ^0.8.1;
pragma abicoder v2;

struct CdpData {
address gemJoin;
address payable fundsReceiver;
uint256 cdpId;
bytes32 ilk;
uint256 requiredDebt;
uint256 borrowCollateral;
uint256 withdrawCollateral;
uint256 withdrawDai;
uint256 depositDai;
uint256 depositCollateral;
bool skipFL;
string methodName;
}

struct AddressRegistry {
address jug;
address manager;
Expand Down Expand Up @@ -415,23 +401,6 @@ contract MultiplyProxyActions is IERC3156FlashBorrower {
return ink;
}

function _getWipeDart(
address vat,
uint256 dai,
address urn,
bytes32 ilk
) internal view returns (int256 dart) {
// Gets actual rate from the vat
(, uint256 rate, , , ) = IVat(vat).ilks(ilk);
// Gets actual art value of the urn
(, uint256 art) = IVat(vat).urns(ilk, urn);

// Uses the whole dai balance in the vat to reduce the debt
dart = toInt256(dai / rate);
// Checks the calculated dart is not higher than urn.art (total debt), otherwise uses its value
dart = uint256(dart) <= art ? -dart : -toInt256(art);
}

function _getWipeAllWad(
address vat,
address usr,
Expand All @@ -452,6 +421,23 @@ contract MultiplyProxyActions is IERC3156FlashBorrower {
wad = wad.mul(RAY) < rad ? wad + 1 : wad;
}

function _getWipeDart(
address vat,
uint256 dai,
address urn,
bytes32 ilk
) internal view returns (int256 dart) {
// Gets actual rate from the vat
(, uint256 rate, , , ) = IVat(vat).ilks(ilk);
// Gets actual art value of the urn
(, uint256 art) = IVat(vat).urns(ilk, urn);

// Uses the whole dai balance in the vat to reduce the debt
dart = toInt256(dai / rate);
// Checks the calculated dart is not higher than urn.art (total debt), otherwise uses its value
dart = uint256(dart) <= art ? -dart : -toInt256(art);
}

function wipeAndFreeGem(
address manager,
address gemJoin,
Expand Down
103 changes: 103 additions & 0 deletions contracts/multiply_alternative/ActionsRunner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
pragma solidity ^0.8.1;
import "./interfaces/ExternalInterfaces.sol";
import "./../flash-mint/interface/IERC3156FlashBorrower.sol";
import "./../flash-mint/interface/IERC3156FlashLender.sol";

struct FlashLoanData {
address lendedTokenAddress;
uint256 lendedTokenAmount;
}

struct FlashLoanExecutionData {
address caller;
address token;
uint256 amount;
uint256 fee;
}

abstract contract BaseAction {
function main(bytes calldata data, FlashLoanExecutionData memory executionData) external virtual;

function beforeFlashLoan(bytes calldata data) external virtual returns (bytes memory);

function afterFlashLoan(bytes calldata data) external virtual;

function isFlashLoanRequired() external virtual returns (bool);
}

contract FlashLoanProvider is IERC3156FlashBorrower {
address public immutable lender;
address public immutable self;

constructor(address _lender) {
lender = _lender;
self = address(this);
}

function onFlashLoan(
address caller,
address token,
uint256 amount,
uint256 fee,
bytes calldata params
) public override returns (bytes32) {
(address action, bytes memory mainData) = abi.decode(params, (address, bytes));
BaseAction(action).main(mainData, FlashLoanExecutionData(caller, token, amount, fee)); //here we do not mind change context since we changed it anyway
}

function execute(address action, bytes memory actionsData) public {
(FlashLoanData memory flashLoanData, bytes memory mainData) = abi.decode(
actionsData,
(FlashLoanData, bytes)
);

bytes memory beforeCallData = abi.encodeWithSignature("beforeFlashLoan(bytes)", mainData);
(bool status, bytes memory step2Data) = address(action).delegatecall(beforeCallData);
require(status, "action/beforeFlashLoan-failed");

IERC3156FlashLender(lender).flashLoan(
IERC3156FlashBorrower(self),
flashLoanData.lendedTokenAddress,
flashLoanData.lendedTokenAmount,
abi.encode(action, step2Data)
);

bytes memory afterCallData = abi.encodeWithSignature("afterFlashLoan(bytes)", mainData);
(status, ) = address(action).delegatecall(afterCallData);
require(status, "action/afterFlashLoan-failed");
}
}

contract Runner {
ServiceRegistryLike public immutable registry;
FlashLoanProvider public immutable flashLoanProvider;

constructor(address _reg, address _flProvider) {
registry = ServiceRegistryLike(_reg);
flashLoanProvider = FlashLoanProvider(_flProvider);
}

/*
actionName - key for stored in serviceRegistry address of action implementation, for example MCLOSE_TO_DAI, GCLOSE_TO_DAI
actionData - abi.encode(flashLoanData, mainData)
where flashLoanData are information for flash loan about asset and amount to borrow
where mainData is action-specific bytes used in beforeFlashLoan, main, afterFlashLoan that then Adtion internally decodes to whatever it uses
*/
function executeAction(string calldata actionName, bytes calldata actionData) external {
BaseAction action = BaseAction(registry.getRegisteredService(actionName));

bool useFlashLoan = action.isFlashLoanRequired();
if (useFlashLoan) {
bytes memory flashLoanCallData = abi.encodeWithSignature(
"execute(address,bytes)",
abi.encode(address(action), actionData)
);
(bool status, ) = address(flashLoanProvider).delegatecall(flashLoanCallData);
require(status, "runner/flashloan-failed");
} else {
bytes memory actionDelegateData = abi.encodeWithSignature("main(bytes)", actionData);
(bool status, ) = address(action).delegatecall(actionDelegateData);
require(status, "runner/action-failed");
}
}
}
66 changes: 66 additions & 0 deletions contracts/multiply_alternative/MakerCalculations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
pragma solidity ^0.8.1;
import "./../utils/SafeMath.sol";
import "./../interfaces/IERC20.sol";
import "./../interfaces/mcd/IVat.sol";
import "./../interfaces/mcd/IManager.sol";
import "./../interfaces/mcd/IJoin.sol";

//TODO: This should be library "using MakerMath for uint256"
//TODO: Get rid of SafeMath since new compiler do safeMath out of the box
contract MakerMath {
using SafeMath for uint256;

function convertTo18(address gemJoin, uint256 amt) internal view returns (uint256 wad) {
// For those collaterals that have less than 18 decimals precision we need to do the conversion before passing to frob function
// Adapters will automatically handle the difference of precision
wad = amt.mul(10**(18 - IJoin(gemJoin).dec()));
}

function toInt256(uint256 x) internal pure returns (int256 y) {
y = int256(x);
require(y >= 0, "int256-overflow");
}
}

//TODO:This eventually should be library not inheritance, it can be used as "using MakerTools for IVat"
contract MakerCalculations is MakerMath {
uint256 constant RAY = 10**27;
using SafeMath for uint256;

function _getWipeDart(
address vat,
uint256 dai,
address urn,
bytes32 ilk
) internal view returns (int256 dart) {
// Gets actual rate from the vat
(, uint256 rate, , , ) = IVat(vat).ilks(ilk);
// Gets actual art value of the urn
(, uint256 art) = IVat(vat).urns(ilk, urn);

// Uses the whole dai balance in the vat to reduce the debt
dart = toInt256(dai / rate);
// Checks the calculated dart is not higher than urn.art (total debt), otherwise uses its value
dart = uint256(dart) <= art ? -dart : -toInt256(art);
}

function _getWipeAllWad(
address vat,
address usr,
address urn,
bytes32 ilk
) internal view returns (uint256 wad) {
// Gets actual rate from the vat
(, uint256 rate, , , ) = IVat(vat).ilks(ilk);
// Gets actual art value of the urn
(, uint256 art) = IVat(vat).urns(ilk, urn);
// Gets actual dai amount in the urn
uint256 dai = IVat(vat).dai(usr);

uint256 rad = art.mul(rate).sub(dai);
wad = rad / RAY;

// If the rad precision has some dust, it will need to request for 1 extra wad wei
wad = wad.mul(RAY) < rad ? wad + 1 : wad;
}
}
44 changes: 44 additions & 0 deletions contracts/multiply_alternative/MakerTools.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
pragma solidity ^0.8.1;
import "./MakerCalculations.sol";
import "./interfaces/ExternalInterfaces.sol";
import "./../utils/SafeMath.sol";
import "./../interfaces/IERC20.sol";
import "./../interfaces/mcd/IVat.sol";
import "./../interfaces/mcd/IManager.sol";
import "./../interfaces/mcd/IDaiJoin.sol";
import "./../interfaces/mcd/IJoin.sol";
import "./../../contracts/interfaces/exchange/IExchange.sol";

//TODO:This eventually should be library not inheritance
contract MakerTools is MakerCalculations {
address public immutable daijoin;
IERC20 public immutable DAI;
using SafeMath for uint256;

constructor(address _daiJoin, address _dai) {
daijoin = _daiJoin;
DAI = IERC20(_dai);
}

function wipeAndFreeGem(
address manager,
address gemJoin,
uint256 cdp,
uint256 borrowedDai,
uint256 collateralDraw
) internal {
address vat = IManager(manager).vat();
address urn = IManager(manager).urns(cdp);
bytes32 ilk = IManager(manager).ilks(cdp);

IERC20(DAI).approve(daijoin, borrowedDai);
IDaiJoin(daijoin).join(urn, borrowedDai);

uint256 wadC = convertTo18(gemJoin, collateralDraw);

IManager(manager).frob(cdp, -toInt256(wadC), _getWipeDart(vat, IVat(vat).dai(urn), urn, ilk));

IManager(manager).flux(cdp, address(this), wadC);
IJoin(gemJoin).exit(address(this), collateralDraw);
}
}
Loading