Skip to content
New issue

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

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

Already on GitHub? # to your account

Notional fCash as collateral #378

Merged
merged 27 commits into from
Feb 25, 2022
Merged
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
8 changes: 5 additions & 3 deletions contracts/Join.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract Join is IJoin, IERC3156FlashLender, AccessControl() {
event FlashFeeFactorSet(uint256 indexed fee);

bytes32 constant internal FLASH_LOAN_RETURN = keccak256("ERC3156FlashBorrower.onFlashLoan");
uint256 constant FLASH_LOANS_DISABLED = type(uint256).max;
uint256 constant public FLASH_LOANS_DISABLED = type(uint256).max;

address public immutable override asset;
uint256 public storedBalance;
Expand Down Expand Up @@ -56,8 +56,10 @@ contract Join is IJoin, IERC3156FlashLender, AccessControl() {
IERC20 token = IERC20(asset);
uint256 _storedBalance = storedBalance;
uint256 available = token.balanceOf(address(this)) - _storedBalance; // Fine to panic if this underflows
storedBalance = _storedBalance + amount;
unchecked { if (available < amount) token.safeTransferFrom(user, address(this), amount - available); }
unchecked {
storedBalance = _storedBalance + amount; // Unlikely that a uint128 added to the stored balance will make it overflow
if (available < amount) token.safeTransferFrom(user, address(this), amount - available);
}
return amount;
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/Ladle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ contract Ladle is LadleStorage, AccessControl() {
}

/// @dev The WETH9 contract will send ether to BorrowProxy on `weth.withdraw` using this function.
receive() external payable {
receive() external payable {
require (msg.sender == address(weth), "Only receive from WETH");
}

Expand Down
1 change: 1 addition & 0 deletions contracts/other/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This directory contains custom implementations to integrate with other platforms
253 changes: 253 additions & 0 deletions contracts/other/notional/ERC1155.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Minimalist and gas efficient standard ERC1155 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155 {
/*///////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/

event TransferSingle(
address indexed operator,
address indexed from,
address indexed to,
uint256 id,
uint256 amount
);

event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] amounts
);

event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

event URI(string value, uint256 indexed id);

/*///////////////////////////////////////////////////////////////
ERC1155 STORAGE
//////////////////////////////////////////////////////////////*/

mapping(address => mapping(uint256 => uint256)) public balanceOf;

mapping(address => mapping(address => bool)) public isApprovedForAll;

/*///////////////////////////////////////////////////////////////
METADATA LOGIC
//////////////////////////////////////////////////////////////*/

function uri(uint256 id) public view virtual returns (string memory);

/*///////////////////////////////////////////////////////////////
ERC1155 LOGIC
//////////////////////////////////////////////////////////////*/

function setApprovalForAll(address operator, bool approved) public virtual {
isApprovedForAll[msg.sender][operator] = approved;

emit ApprovalForAll(msg.sender, operator, approved);
}

function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual {
require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");

balanceOf[from][id] -= amount;
balanceOf[to][id] += amount;

emit TransferSingle(msg.sender, from, to, id, amount);

require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==
ERC1155TokenReceiver.onERC1155Received.selector,
"UNSAFE_RECIPIENT"
);
}

function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual {
uint256 idsLength = ids.length; // Saves MLOADs.

require(idsLength == amounts.length, "LENGTH_MISMATCH");

require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");

for (uint256 i = 0; i < idsLength; ) {
uint256 id = ids[i];
uint256 amount = amounts[i];

balanceOf[from][id] -= amount;
balanceOf[to][id] += amount;

// An array can't have a total length
// larger than the max uint256 value.
unchecked {
i++;
}
}

emit TransferBatch(msg.sender, from, to, ids, amounts);

require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
ERC1155TokenReceiver.onERC1155BatchReceived.selector,
"UNSAFE_RECIPIENT"
);
}

function balanceOfBatch(address[] memory owners, uint256[] memory ids)
public
view
virtual
returns (uint256[] memory balances)
{
uint256 ownersLength = owners.length; // Saves MLOADs.

require(ownersLength == ids.length, "LENGTH_MISMATCH");

balances = new uint256[](owners.length);

// Unchecked because the only math done is incrementing
// the array index counter which cannot possibly overflow.
unchecked {
for (uint256 i = 0; i < ownersLength; i++) {
balances[i] = balanceOf[owners[i]][ids[i]];
}
}
}

/*///////////////////////////////////////////////////////////////
ERC165 LOGIC
//////////////////////////////////////////////////////////////*/

function supportsInterface(bytes4 interfaceId) public pure virtual returns (bool) {
return
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
}

/*///////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/

function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal {
balanceOf[to][id] += amount;

emit TransferSingle(msg.sender, address(0), to, id, amount);

require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
ERC1155TokenReceiver.onERC1155Received.selector,
"UNSAFE_RECIPIENT"
);
}

function _batchMint(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal {
uint256 idsLength = ids.length; // Saves MLOADs.

require(idsLength == amounts.length, "LENGTH_MISMATCH");

for (uint256 i = 0; i < idsLength; ) {
balanceOf[to][ids[i]] += amounts[i];

// An array can't have a total length
// larger than the max uint256 value.
unchecked {
i++;
}
}

emit TransferBatch(msg.sender, address(0), to, ids, amounts);

require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
ERC1155TokenReceiver.onERC1155BatchReceived.selector,
"UNSAFE_RECIPIENT"
);
}

function _batchBurn(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal {
uint256 idsLength = ids.length; // Saves MLOADs.

require(idsLength == amounts.length, "LENGTH_MISMATCH");

for (uint256 i = 0; i < idsLength; ) {
balanceOf[from][ids[i]] -= amounts[i];

// An array can't have a total length
// larger than the max uint256 value.
unchecked {
i++;
}
}

emit TransferBatch(msg.sender, from, address(0), ids, amounts);
}

function _burn(
address from,
uint256 id,
uint256 amount
) internal {
balanceOf[from][id] -= amount;

emit TransferSingle(msg.sender, from, address(0), id, amount);
}
}

/// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
interface ERC1155TokenReceiver {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 amount,
bytes calldata data
) external returns (bytes4);

function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external returns (bytes4);
}
20 changes: 20 additions & 0 deletions contracts/other/notional/ERC1155Mock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import "./ERC1155.sol"; // TODO: Move to yield-utils-v2


contract ERC1155Mock is ERC1155 {

function uri(uint256) public view virtual override returns (string memory) {
return "";
}

function mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) external {
_mint(to, id, amount, data);
}
}
Loading