# non-custodial flash loans with transient storage
Powerful pattern enabled by transient storage.
The user calls `NonCustodialFlashLoans#startLoan`, and control is handed back to them using the `IStartCallback#start` callback.
The user can then borrow as much of any token they want, from any user that has sent approval, within this callback by calling `NonCustodialFlashLoans#borrow`.
The contract uses transient storage to track what has been borrowed and check the tokens are returned at the end. ***The SLOAD/SSTORE’s make this pattern gas-infeasible without transient storage.***
Credit: @sendmoodz for this idea
> Disclaimer: Unaudited code
```solidity
interface IStartCallback {
/// @notice Called on the `msg.sender` to hand over control to them.
/// Expectation is that msg.sender#start will borrow tokens using NonCustodialFlashLoans#borrow,
/// then return them to the original user before control is handed back to #start.
function start() external;
}
contract NonCustodialFlashLoans {
struct Borrow {
uint256 lenderStartingBalance;
address lender;
IERC20 token;
}
// The full list of borrows that have occured in the current transaction.
Borrow[] public transient borrows;
// The user borrowing. Borrower is able to call #borrow to release tokens.
address public transient borrower;
/// @notice Entry Point. Start borrowing from the users that have approved this contract.
function startLoan() external {
require(borrower == address(0)); // prevent reentrance
// TSTORE it!
borrower = msg.sender;
/// Hand control to the caller so they can start borrowing tokens
IStartCallback(msg.sender).start();
// At this point `msg.sender` should have returned any tokens that
// were borrowed to each lender. Check this and revert if not!
for (uint256 i = 0; i < borrows.length; i++) {
Borrow transient borrow = borrows[i]; // TLOAD!
require(
borrow.token.balanceOf(borrow.lender) >= borrow.lenderStartingBalance,
'You must pay back the person you borrowed from!'
);
}
borrows.length = 0; // this doesn't actually work in recent solidity versions for storage arrays, but we only need to set the length of the array, you can also use TSTORE directly
borrower = address(0); // clearing this allows it to be called again in the same transaction
}
// Only callable by `borrower`. Used to borrow tokens.
function borrow(
address from,
IERC20 token,
uint256 amount,
address to
) external {
require(msg.sender == borrower, 'Must be called from within the IStartCallback#start');
// TSTORE what has been borrowed
borrows.push(Borrow({lenderStartingBalance: token.balanceOf(from), lender: from, token: token}));
token.transferFrom(from, to, amount);
}
}
```