forked from OpenZeppelin/damn-vulnerable-defi
/
Exchange.sol
71 lines (54 loc) · 2.05 KB
/
Exchange.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./TrustfulOracle.sol";
import "../DamnValuableNFT.sol";
/**
* @title Exchange
* @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz)
*/
contract Exchange is ReentrancyGuard {
using Address for address payable;
DamnValuableNFT public immutable token;
TrustfulOracle public immutable oracle;
error InvalidPayment();
error SellerNotOwner(uint256 id);
error TransferNotApproved();
error NotEnoughFunds();
event TokenBought(address indexed buyer, uint256 tokenId, uint256 price);
event TokenSold(address indexed seller, uint256 tokenId, uint256 price);
constructor(address _oracle) payable {
token = new DamnValuableNFT();
token.renounceOwnership();
oracle = TrustfulOracle(_oracle);
}
function buyOne() external payable nonReentrant returns (uint256 id) {
if (msg.value == 0)
revert InvalidPayment();
// Price should be in [wei / NFT]
uint256 price = oracle.getMedianPrice(token.symbol());
if (msg.value < price)
revert InvalidPayment();
id = token.safeMint(msg.sender);
unchecked {
payable(msg.sender).sendValue(msg.value - price);
}
emit TokenBought(msg.sender, id, price);
}
function sellOne(uint256 id) external nonReentrant {
if (msg.sender != token.ownerOf(id))
revert SellerNotOwner(id);
if (token.getApproved(id) != address(this))
revert TransferNotApproved();
// Price should be in [wei / NFT]
uint256 price = oracle.getMedianPrice(token.symbol());
if (address(this).balance < price)
revert NotEnoughFunds();
token.transferFrom(msg.sender, address(this), id);
token.burn(id);
payable(msg.sender).sendValue(price);
emit TokenSold(msg.sender, id, price);
}
receive() external payable {}
}