Skip to content

Instantly share code, notes, and snippets.

@brianmcmichael
Created June 17, 2021 21:50
Show Gist options
  • Save brianmcmichael/29577eb641a697eb8b5ccc963e3e73f3 to your computer and use it in GitHub Desktop.
Save brianmcmichael/29577eb641a697eb8b5ccc963e3e73f3 to your computer and use it in GitHub Desktop.
pragma solidity ^0.6.12;
interface VatAbstract {
function wards(address) external view returns (uint256);
function rely(address) external;
function deny(address) external;
function can(address, address) external view returns (uint256);
function hope(address) external;
function nope(address) external;
function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256);
function urns(bytes32, address) external view returns (uint256, uint256);
function gem(bytes32, address) external view returns (uint256);
function dai(address) external view returns (uint256);
function sin(address) external view returns (uint256);
function debt() external view returns (uint256);
function vice() external view returns (uint256);
function Line() external view returns (uint256);
function live() external view returns (uint256);
function init(bytes32) external;
function file(bytes32, uint256) external;
function file(bytes32, bytes32, uint256) external;
function cage() external;
function slip(bytes32, address, int256) external;
function flux(bytes32, address, address, uint256) external;
function move(address, address, uint256) external;
function frob(bytes32, address, address, address, int256, int256) external;
function fork(bytes32, address, address, int256, int256) external;
function grab(bytes32, address, address, address, int256, int256) external;
function heal(uint256) external;
function suck(address, address, uint256) external;
function fold(bytes32, address, int256) external;
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address) external view returns (uint256);
function allowance(address, address) external view returns (uint256);
function approve(address, uint256) external returns (bool);
function transfer(address, uint256) external returns (bool);
function transferFrom(address, address, uint256) external returns (bool);
}
interface IERC3156FlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}
interface IERC3156FlashLender {
/**
* @dev The amount of currency available to be lent.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(
address token
) external view returns (uint256);
/**
* @dev The fee to be charged for a given loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(
address token,
uint256 amount
) external view returns (uint256);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}
interface IVatDaiFlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param amount The amount of tokens lent. [rad]
* @param fee The additional amount of tokens to repay. [rad]
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "IVatDaiFlashLoanReceiver.onVatDaiFlashLoan"
*/
function onVatDaiFlashLoan(
address initiator,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}
interface IVatDaiFlashLender {
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param amount The amount of tokens lent. [rad]
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function vatDaiFlashLoan(
IVatDaiFlashBorrower receiver,
uint256 amount,
bytes calldata data
) external returns (bool);
}
contract FlashBorrower is IVatDaiFlashBorrower { // 0x68C7b18c987e7Fea919e02894614fD4FA0d58B96
enum Action {NORMAL, OTHER}
VatAbstract vat;
IVatDaiFlashLender lender;
constructor (
VatAbstract vat_, // 0xbA987bDB501d131f766fEe8180Da5d81b34b69d9
IVatDaiFlashLender lender_ // 0x5aA1323f61D679E52a90120DFDA2ed1A76E4475A
) public {
vat = vat_;
lender = lender_;
}
/// @dev Vat Dai Flash loan callback
function onVatDaiFlashLoan(
address initiator,
uint256 amount,
uint256 fee,
bytes calldata data
) external override returns (bytes32) {
require(
msg.sender == address(lender),
"FlashBorrower: Untrusted lender"
);
require(
initiator == address(this),
"FlashBorrower: Untrusted loan initiator"
);
(Action action) = abi.decode(data, (Action));
if (action == Action.NORMAL) {
require(vat.dai(address(this)) >= amount);
// that's it, repay on 176
} else if (action == Action.OTHER) {
// do another
}
// Repay the loan amount + fee
// Be sure not to overpay as there are no safety guards for this
vat.move(address(this), address(lender), amount + fee);
return keccak256("VatDaiFlashBorrower.onVatDaiFlashLoan");
}
/// @dev Initiate a flash loan
function vatDaiFlashBorrow(
uint256 amount
) public {
bytes memory data = abi.encode(Action.NORMAL);
lender.vatDaiFlashLoan(this, amount, data);
}
}
/**
contract FlashBorrower is IERC3156FlashBorrower {
enum Action {NORMAL, OTHER}
IERC3156FlashLender lender;
constructor (
IERC3156FlashLender lender_ // 0x5aA1323f61D679E52a90120DFDA2ed1A76E4475A
) public {
lender = lender_;
}
/// @dev ERC-3156 Flash loan callback
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external override returns (bytes32) {
require(
msg.sender == address(lender),
"FlashBorrower: Untrusted lender"
);
require(
initiator == address(this),
"FlashBorrower: Untrusted loan initiator"
);
(Action action) = abi.decode(data, (Action));
if (action == Action.NORMAL) {
require(IERC20(token).balanceOf(address(this)) >= amount);
// make a profitable trade here
IERC20(token).transfer(initiator, amount + fee);
} else if (action == Action.OTHER) {
// do another
}
return keccak256("ERC3156FlashBorrower.onFlashLoan");
}
/// @dev Initiate a flash loan
function flashBorrow(
address token, // Dai 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa
uint256 amount // wad
) public {
bytes memory data = abi.encode(Action.NORMAL);
uint256 _allowance = IERC20(token).allowance(address(this), address(lender));
uint256 _fee = lender.flashFee(token, amount);
uint256 _repayment = amount + _fee;
IERC20(token).approve(address(lender), _allowance + _repayment);
lender.flashLoan(this, token, amount, data);
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment