forked from t4sk/hello-foundry
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
276 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.17; | ||
|
||
import "./interfaces/IERC721.sol"; | ||
|
||
contract ERC721 is IERC721 { | ||
event Transfer(address indexed from, address indexed to, uint256 indexed id); | ||
event Approval(address indexed owner, address indexed spender, uint256 indexed id); | ||
event ApprovalForAll(address indexed owner, address indexed operator, bool approved); | ||
|
||
// Mapping from token ID to owner address | ||
mapping(uint256 => address) internal _ownerOf; | ||
|
||
// Mapping owner address to token count | ||
mapping(address => uint256) internal _balanceOf; | ||
|
||
// Mapping from token ID to approved address | ||
mapping(uint256 => address) internal _approvals; | ||
|
||
// Mapping from owner to operator approvals | ||
mapping(address => mapping(address => bool)) public isApprovedForAll; | ||
|
||
function supportsInterface(bytes4 interfaceId) external pure returns (bool) { | ||
return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC165).interfaceId; | ||
} | ||
|
||
function ownerOf(uint256 id) external view returns (address owner) { | ||
owner = _ownerOf[id]; | ||
require(owner != address(0), "token doesn't exist"); | ||
} | ||
|
||
function balanceOf(address owner) external view returns (uint256) { | ||
require(owner != address(0), "owner = zero address"); | ||
return _balanceOf[owner]; | ||
} | ||
|
||
function setApprovalForAll(address operator, bool approved) external { | ||
isApprovedForAll[msg.sender][operator] = approved; | ||
emit ApprovalForAll(msg.sender, operator, approved); | ||
} | ||
|
||
function approve(address spender, uint256 id) external { | ||
address owner = _ownerOf[id]; | ||
require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "not authorized"); | ||
|
||
_approvals[id] = spender; | ||
|
||
emit Approval(owner, spender, id); | ||
} | ||
|
||
function getApproved(uint256 id) external view returns (address) { | ||
require(_ownerOf[id] != address(0), "token doesn't exist"); | ||
return _approvals[id]; | ||
} | ||
|
||
function _isApprovedOrOwner(address owner, address spender, uint256 id) internal view returns (bool) { | ||
return (spender == owner || isApprovedForAll[owner][spender] || spender == _approvals[id]); | ||
} | ||
|
||
function transferFrom(address from, address to, uint256 id) public { | ||
require(from == _ownerOf[id], "from != owner"); | ||
require(to != address(0), "transfer to zero address"); | ||
|
||
require(_isApprovedOrOwner(from, msg.sender, id), "not authorized"); | ||
|
||
_balanceOf[from]--; | ||
_balanceOf[to]++; | ||
_ownerOf[id] = to; | ||
|
||
delete _approvals[id]; | ||
|
||
emit Transfer(from, to, id); | ||
} | ||
|
||
function safeTransferFrom(address from, address to, uint256 id) external { | ||
transferFrom(from, to, id); | ||
|
||
require( | ||
to.code.length == 0 | ||
|| IERC721Receiver(to).onERC721Received(msg.sender, from, id, "") | ||
== IERC721Receiver.onERC721Received.selector, | ||
"unsafe recipient" | ||
); | ||
} | ||
|
||
function safeTransferFrom(address from, address to, uint256 id, bytes calldata data) external { | ||
transferFrom(from, to, id); | ||
|
||
require( | ||
to.code.length == 0 | ||
|| IERC721Receiver(to).onERC721Received(msg.sender, from, id, data) | ||
== IERC721Receiver.onERC721Received.selector, | ||
"unsafe recipient" | ||
); | ||
} | ||
|
||
function _mint(address to, uint256 id) internal { | ||
require(to != address(0), "mint to zero address"); | ||
require(_ownerOf[id] == address(0), "already minted"); | ||
|
||
_balanceOf[to]++; | ||
_ownerOf[id] = to; | ||
|
||
emit Transfer(address(0), to, id); | ||
} | ||
|
||
function _burn(uint256 id) internal { | ||
address owner = _ownerOf[id]; | ||
require(owner != address(0), "not minted"); | ||
|
||
_balanceOf[owner] -= 1; | ||
|
||
delete _ownerOf[id]; | ||
delete _approvals[id]; | ||
|
||
emit Transfer(owner, address(0), id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.18; | ||
|
||
import "../interfaces/IERC20.sol"; | ||
import "../interfaces/IERC721.sol"; | ||
import "../ERC20.sol"; | ||
import "../ERC721.sol"; | ||
import "../Token.sol"; | ||
|
||
// Bond is bought at a discount | ||
// Discount determines fixed interest | ||
|
||
contract CollateralToken is Token("collateral", "col", 18) {} | ||
|
||
contract Coin is Token("coin", "coin", 6) {} | ||
|
||
contract Auth { | ||
mapping(address => bool) public authorized; | ||
|
||
modifier onlyAuthorized() { | ||
require(authorized[msg.sender], "not authorized"); | ||
_; | ||
} | ||
|
||
function _setAuthorized(address account, bool auth) internal { | ||
authorized[account] = auth; | ||
} | ||
|
||
function setAuthorized(address account, bool auth) external onlyAuthorized { | ||
_setAuthorized(account, auth); | ||
} | ||
} | ||
|
||
// NFT | ||
interface IFixedYieldBond is IERC721 { | ||
function mint(address account, uint256 fyAmount) external returns (uint256); | ||
} | ||
|
||
struct ZeroCouponBond { | ||
address issuer; | ||
uint256 debt; | ||
uint256 maturity; | ||
} | ||
|
||
contract FixedYieldBond is IFixedYieldBond, ERC721, Auth { | ||
constructor() { | ||
_setAuthorized(msg.sender, true); | ||
} | ||
|
||
function mint(address account, uint256 fyAmount) external onlyAuthorized returns (uint256) { | ||
// TODO: maturity | ||
// TODO: id | ||
uint256 id = 123; | ||
_mint(account, id); | ||
return id; | ||
} | ||
|
||
function burn() external {} | ||
} | ||
|
||
contract ZeroCouponBondMarket { | ||
IERC20 public immutable coin; | ||
IFixedYieldBond public immutable fyBond; | ||
|
||
constructor(IERC20 _coin, IFixedYieldBond _fyBond) { | ||
coin = _coin; | ||
fyBond = _fyBond; | ||
} | ||
|
||
function sell(uint256 _nftId) external { | ||
fyBond.transferFrom(msg.sender, address(this), _nftId); | ||
} | ||
|
||
// TODO: cancel | ||
|
||
// TODO: Auction or AMM | ||
function buy(uint256 _nftId) external { | ||
uint256 price = 0; | ||
address nftOwner; | ||
uint256 fyAmount; | ||
coin.transferFrom(msg.sender, nftOwner, fyAmount); | ||
// TODO: can be resold? | ||
fyBond.transferFrom(address(this), msg.sender, _nftId); | ||
} | ||
} | ||
|
||
contract CollateralLock { | ||
IERC20 public immutable collateral; | ||
IERC20 public immutable coin; | ||
IFixedYieldBond public immutable fyBond; | ||
|
||
mapping(address => uint256) public collateralBalances; | ||
|
||
constructor(IERC20 _collateral, IERC20 _coin, IFixedYieldBond _fyBond) { | ||
collateral = _collateral; | ||
coin = _coin; | ||
fyBond = _fyBond; | ||
} | ||
|
||
function lock(uint256 colAmount) external { | ||
collateral.transferFrom(msg.sender, address(this), colAmount); | ||
collateralBalances[msg.sender] += colAmount; | ||
} | ||
|
||
function borrow(uint256 fyAmount) external returns (uint256) { | ||
uint256 nftId = fyBond.mint(msg.sender, fyAmount); | ||
return nftId; | ||
} | ||
|
||
function repay(uint256 fyAmount) external { | ||
// TODO: fees after expiry | ||
coin.transferFrom(msg.sender, address(this), fyAmount); | ||
// TODO: calculate how much collateral to release | ||
uint256 colAmount; | ||
collateral.transfer(msg.sender, colAmount); | ||
} | ||
|
||
function withdraw() external {} | ||
|
||
// TODO: liquidation AMM or auction | ||
function liquidate() external {} | ||
} | ||
|
||
contract PriceOracle {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.17; | ||
|
||
interface IERC165 { | ||
function supportsInterface(bytes4 interfaceID) external view returns (bool); | ||
} | ||
|
||
interface IERC721 is IERC165 { | ||
function balanceOf(address owner) external view returns (uint256 balance); | ||
|
||
function ownerOf(uint256 tokenId) external view returns (address owner); | ||
|
||
function safeTransferFrom(address from, address to, uint256 tokenId) external; | ||
|
||
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; | ||
|
||
function transferFrom(address from, address to, uint256 tokenId) external; | ||
|
||
function approve(address to, uint256 tokenId) external; | ||
|
||
function getApproved(uint256 tokenId) external view returns (address operator); | ||
|
||
function setApprovalForAll(address operator, bool _approved) external; | ||
|
||
function isApprovedForAll(address owner, address operator) external view returns (bool); | ||
} | ||
|
||
interface IERC721Receiver { | ||
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) | ||
external | ||
returns (bytes4); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters