Skip to content

Instantly share code, notes, and snippets.

@wilsoncusack
Created November 16, 2021 20:00
Show Gist options
  • Save wilsoncusack/9b196bbe6f1311ce6914efcba5df1984 to your computer and use it in GitHub Desktop.
Save wilsoncusack/9b196bbe6f1311ce6914efcba5df1984 to your computer and use it in GitHub Desktop.
NFT-Loan Lending Vault Sketch
pragma solidity 0.8.6;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../interfaces/INFTLoanFacilitator.sol";
struct LendValues {
uint256 loanAmount;
uint256 perSecondInterestRate;
uint256 durationSeconds;
}
interface ILendValuesSource {
function lendValues(uint256 tokenId, address erc721ContractAddress, address loanAssetAddress)
external returns(LendValues memory);
}
contract LendVault is ERC20 {
using SafeERC20 for IERC20;
IERC20 public immutable loanAsset;
INFTLoanFacilitator public immutable facilitator;
ILendValuesSource public lendValuesSource;
constructor(IERC20 _loanAsset, INFTLoanFacilitator _facilitator, ILendValuesSource _lendValuesSource) ERC20("Lend Vault 1", "LV1") {
loanAsset = _loanAsset;
facilitator = _facilitator;
lendValuesSource = _lendValuesSource;
}
function lend(uint256 loanId) external {
(,,,,,,
uint256 collateralTokenId,
address collateralContractAddress,
address loanAssetContractAddress) = facilitator.loanInfo(loanId);
require(loanAssetContractAddress == address(loanAsset), 'wrong loan asset');
// call to a contract which determines what values to use for lend.
// Multiple vaults could share a lendValuesSource contract, which is maybe thought to be good at evaluating asset worth.
// We could even make `lendValues` a payable method so people could pay for valuations
// In some cases a LendValuesSource contract could have its LendValues updated by a DAO.
// A DAO could also update LendVault as to which LendValuesSource to use.
LendValues memory lendValues = lendValuesSource.lendValues(collateralTokenId, collateralContractAddress, loanAssetContractAddress);
facilitator.underwriteLoan(loanId, lendValues.perSecondInterestRate, lendValues.loanAmount, lendValues.durationSeconds, address(this));
}
function seizeCollateral(uint256 loanId) external {
facilitator.seizeCollateral(loanId, address(this));
}
function auction(uint256 tokenId, address tokenContract) external {
// sell a seized asset
// use Zora auction house
}
// close to https://github.com/pooltogether/pods-v3-contracts/blob/master/contracts/Pod.sol#L215
function deposit(address to, uint256 amount) external returns (uint256){
require(amount > 0, "invalid-amount");
uint256 shares = _calculateAllocation(amount);
_mint(to, shares);
loanAsset.safeTransferFrom(
msg.sender,
address(this),
amount
);
// Return Shares Minted
return shares;
}
function withdraw(address to, uint256 shares) external {
uint256 amount = _calculateUnderlyingTokens(shares);
_burn(msg.sender, shares);
loanAsset.safeTransfer(msg.sender, amount);
}
// from https://github.com/pooltogether/pods-v3-contracts/blob/master/contracts/Pod.sol#L485
function _calculateAllocation(uint256 amount) internal returns (uint256) {
uint256 allocation = 0;
uint256 _totalSupply = totalSupply();
// Calculate Allocation
if (_totalSupply == 0) {
allocation = amount;
} else {
allocation = (amount * _totalSupply) / balance();
}
// Return Allocation Amount
return allocation;
}
// close to https://github.com/pooltogether/pods-v3-contracts/blob/master/contracts/Pod.sol#L591
function _calculateUnderlyingTokens(uint256 shares)
internal
view
returns (uint256)
{
return (balance() * shares) / totalSupply();
}
function balance() public view returns (uint256) {
loanAsset.balanceOf(address(this));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment