Damn Vulnerable DeFi 是一个 Defi 智能合约攻击挑战系列。内容包括了闪电贷攻击、借贷池、链上预言机等。在开始之前你需要具备 Solidity 以及 JavaScipt 相关的技能。针对每一题你需要做的就是保证该题的单元测试能够通过。
题目链接:https://www.damnvulnerabledefi.xyz/challenges/10.html
题目描述:
现有已经发布的 Damn Valuable NFT 交易市场,初始 mint 了 6 个 NFT,并且可以在交易市场上出售,售价为 15ETH。
有个买家告诉了你一个秘密:市场是脆弱的,所有的代币都可以被拿走。然而,他并不知道怎么做。为此愿意提供 45 ETH 的奖励给取出 NFT 并发送给他的人。
你想在这个买家那里建立一些名声,所以你已经同意了这个计划。
遗憾的是你只有 0.5 ETH。要是有一个地方你可以免费获得 ETH 就好了,暂时性的也可以。
FreeRiderBuyer.sol
买家合约
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
contract FreeRiderBuyer is ReentrancyGuard, IERC721Receiver {
using Address for address payable;
address private immutable partner;
IERC721 private immutable nft;
uint256 private constant JOB_PAYOUT = 45 ether;
uint256 private received;
// 部署时向该合约转入了 45eth
constructor(address _partner, address _nft) payable {
require(msg.value == JOB_PAYOUT);
partner = _partner;
nft = IERC721(_nft);
IERC721(_nft).setApprovalForAll(msg.sender, true);
}
// 接收到NFT时触发的函数
function onERC721Received(
address,
address,
uint256 _tokenId,
bytes memory
)
external
override
nonReentrant
returns (bytes4)
{
require(msg.sender == address(nft));
require(tx.origin == partner); // 确保交易的发起人是partner
require(_tokenId >= 0 && _tokenId <= 5);
require(nft.ownerOf(_tokenId) == address(this)); // 确保已持有
received++;
// 接收到6个NFT后将45eth转给partner
if(received == 6) {
payable(partner).sendValue(JOB_PAYOUT);
}
return IERC721Receiver.onERC721Received.selector;
}
}
由于该合约继承自 IERC721Receiver
,且 NFT
合约继承自 ERC721
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
contract DamnValuableNFT is ERC721, ERC721Burnable, AccessControl {}