Skip to content
Open
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
21 changes: 14 additions & 7 deletions 38_NFTSwap/NFTSwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,24 @@ contract NFTSwap is IERC721Receiver {
IERC721 _nft = IERC721(_nftAddr);
require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT在合约中

// 将order信息缓存到内存变量,遵循 Checks-Effects-Interactions 模式
address owner = _order.owner;
uint256 price = _order.price;

// 先删除order,防止重入攻击
delete nftList[_nftAddr][_tokenId];

// 将NFT转给买家
_nft.safeTransferFrom(address(this), msg.sender, _tokenId);
// 将ETH转给卖家
payable(_order.owner).transfer(_order.price);
payable(owner).transfer(price);
// 多余ETH给买家退款
if (msg.value > _order.price) {
payable(msg.sender).transfer(msg.value - _order.price);
if (msg.value > price) {
payable(msg.sender).transfer(msg.value - price);
}

// 释放Purchase事件
emit Purchase(msg.sender, _nftAddr, _tokenId, _order.price);

delete nftList[_nftAddr][_tokenId]; // 删除order
emit Purchase(msg.sender, _nftAddr, _tokenId, price);
}

// 撤单: 卖家取消挂单
Expand All @@ -88,9 +93,11 @@ contract NFTSwap is IERC721Receiver {
IERC721 _nft = IERC721(_nftAddr);
require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT在合约中

// 先删除order,遵循 Checks-Effects-Interactions 模式
delete nftList[_nftAddr][_tokenId];

// 将NFT转给卖家
_nft.safeTransferFrom(address(this), msg.sender, _tokenId);
delete nftList[_nftAddr][_tokenId]; // 删除order

// 释放Revoke事件
emit Revoke(msg.sender, _nftAddr, _tokenId);
Expand Down
23 changes: 15 additions & 8 deletions Languages/en/38_NFTSwap_en/NFTSwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,23 @@ contract NFTSwap is IERC721Receiver {
IERC721 _nft = IERC721(_nftAddr);
require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT is in the contract

// Cache order info in memory, following Checks-Effects-Interactions pattern
address owner = _order.owner;
uint256 price = _order.price;

// Delete order first to prevent reentrancy
delete nftList[_nftAddr][_tokenId];

// Transfer NFT to buyer
_nft.safeTransferFrom(address(this), msg.sender, _tokenId);
// Transfer ETH to the seller, and refund the excess ETH to the buyer
payable(_order.owner).transfer(_order.price);
if (msg.value > _order.price) {
payable(msg.sender).transfer(msg.value - _order.price);
payable(owner).transfer(price);
if (msg.value > price) {
payable(msg.sender).transfer(msg.value - price);
}

// Release the Purchase event
emit Purchase(msg.sender, _nftAddr, _tokenId, _order.price);

delete nftList[_nftAddr][_tokenId]; // delete order
// Release the Purchase event
emit Purchase(msg.sender, _nftAddr, _tokenId, price);
}

// Cancellation: The seller cancels the pending order
Expand All @@ -87,9 +92,11 @@ contract NFTSwap is IERC721Receiver {
IERC721 _nft = IERC721(_nftAddr);
require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT is in the contract

// Delete order first, following Checks-Effects-Interactions pattern
delete nftList[_nftAddr][_tokenId];

// Transfer NFT to seller
_nft.safeTransferFrom(address(this), msg.sender, _tokenId);
delete nftList[_nftAddr][_tokenId]; // delete order

// Release the Revoke event
emit Revoke(msg.sender, _nftAddr, _tokenId);
Expand Down
2 changes: 1 addition & 1 deletion out/32_Faucet/IERC20.sol/IERC20.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/33_Airdrop/IERC20.sol/IERC20.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/51_ERC4626/ERC20.sol/ERC20.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/ABIEncode.sol/ABIEncode.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/AaveV3Flashloan.sol/AaveV3Flashloan.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/AaveV3Flashloan.sol/IFlashLoanSimpleReceiver.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"abi":[{"type":"function","name":"executeOperation","inputs":[{"name":"asset","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"premium","type":"uint256","internalType":"uint256"},{"name":"initiator","type":"address","internalType":"address"},{"name":"params","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"executeOperation(address,uint256,uint256,address,bytes)":"1b11d0ff"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.34+commit.80d5c536\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"}],\"name\":\"executeOperation\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"executeOperation(address,uint256,uint256,address,bytes)\":{\"details\":\"\\u786e\\u4fdd\\u5408\\u7ea6\\u80fd\\u591f\\u5f52\\u8fd8\\u503a\\u52a1 + \\u989d\\u5916\\u8d39\\u7528\\uff0c\\u4f8b\\u5982\\uff0c\\u5177\\u6709 \\u8db3\\u591f\\u7684\\u8d44\\u91d1\\u6765\\u507f\\u8fd8\\uff0c\\u5e76\\u5df2\\u6279\\u51c6 Pool \\u63d0\\u53d6\\u603b\\u91d1\\u989d\",\"params\":{\"amount\":\"\\u95ea\\u7535\\u501f\\u6b3e\\u8d44\\u4ea7\\u7684\\u6570\\u91cf\",\"asset\":\"\\u95ea\\u7535\\u501f\\u6b3e\\u8d44\\u4ea7\\u7684\\u5730\\u5740\",\"initiator\":\"\\u53d1\\u8d77\\u95ea\\u7535\\u8d37\\u6b3e\\u7684\\u5730\\u5740\",\"params\":\"\\u521d\\u59cb\\u5316\\u95ea\\u7535\\u8d37\\u6b3e\\u65f6\\u4f20\\u9012\\u7684\\u5b57\\u8282\\u7f16\\u7801\\u53c2\\u6570\",\"premium\":\"\\u95ea\\u7535\\u501f\\u6b3e\\u8d44\\u4ea7\\u7684\\u8d39\\u7528\"},\"returns\":{\"_0\":\"\\u5982\\u679c\\u64cd\\u4f5c\\u7684\\u6267\\u884c\\u6210\\u529f\\u5219\\u8fd4\\u56de True\\uff0c\\u5426\\u5219\\u8fd4\\u56de False\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"executeOperation(address,uint256,uint256,address,bytes)\":{\"notice\":\"\\u5728\\u63a5\\u6536\\u95ea\\u7535\\u501f\\u6b3e\\u8d44\\u4ea7\\u540e\\u6267\\u884c\\u64cd\\u4f5c\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/57_Flashloan/src/AaveV3Flashloan.sol\":\"IFlashLoanSimpleReceiver\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/\"]},\"sources\":{\"src/57_Flashloan/src/AaveV3Flashloan.sol\":{\"keccak256\":\"0x61090dad9f54bff20ae111b2ae1b0128edba77be6084f0c9c5e3b81e7793704a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26b84c57d72b499b698629e1522b3bff5c17ae3c5a5ad66a3fdc25cc3722e1f6\",\"dweb:/ipfs/QmYhfjmUbsDtPEcoLCeJjrfE1juxhzxQ3TmseRDSV7y9rP\"]},\"src/57_Flashloan/src/Lib.sol\":{\"keccak256\":\"0x9e0c02dca8bfcc0e98333a287ee8547fbef18c11e9f842794bb9f5d93d9619dc\",\"urls\":[\"bzz-raw://ffa2bcdd6f7cb221a4161c7e638c32f6ac7277050840174ffec5fa31d3b7c9be\",\"dweb:/ipfs/QmU1JPevALbdoq8sj4hMEReqCzCJ7VGLbDcDM9CPcmoXwc\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.34+commit.80d5c536"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"executeOperation(address,uint256,uint256,address,bytes)":{"details":"确保合约能够归还债务 + 额外费用,例如,具有 足够的资金来偿还,并已批准 Pool 提取总金额","params":{"amount":"闪电借款资产的数量","asset":"闪电借款资产的地址","initiator":"发起闪电贷款的地址","params":"初始化闪电贷款时传递的字节编码参数","premium":"闪电借款资产的费用"},"returns":{"_0":"如果操作的执行成功则返回 True,否则返回 False"}}},"version":1},"userdoc":{"kind":"user","methods":{"executeOperation(address,uint256,uint256,address,bytes)":{"notice":"在接收闪电借款资产后执行操作"}},"version":1}},"settings":{"remappings":["@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/"],"optimizer":{"enabled":false,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/57_Flashloan/src/AaveV3Flashloan.sol":"IFlashLoanSimpleReceiver"},"evmVersion":"prague","libraries":{}},"sources":{"src/57_Flashloan/src/AaveV3Flashloan.sol":{"keccak256":"0x61090dad9f54bff20ae111b2ae1b0128edba77be6084f0c9c5e3b81e7793704a","urls":["bzz-raw://26b84c57d72b499b698629e1522b3bff5c17ae3c5a5ad66a3fdc25cc3722e1f6","dweb:/ipfs/QmYhfjmUbsDtPEcoLCeJjrfE1juxhzxQ3TmseRDSV7y9rP"],"license":"MIT"},"src/57_Flashloan/src/Lib.sol":{"keccak256":"0x9e0c02dca8bfcc0e98333a287ee8547fbef18c11e9f842794bb9f5d93d9619dc","urls":["bzz-raw://ffa2bcdd6f7cb221a4161c7e638c32f6ac7277050840174ffec5fa31d3b7c9be","dweb:/ipfs/QmU1JPevALbdoq8sj4hMEReqCzCJ7VGLbDcDM9CPcmoXwc"],"license":null}},"version":1},"id":120}
{"abi":[{"type":"function","name":"executeOperation","inputs":[{"name":"asset","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"premium","type":"uint256","internalType":"uint256"},{"name":"initiator","type":"address","internalType":"address"},{"name":"params","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"executeOperation(address,uint256,uint256,address,bytes)":"1b11d0ff"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.34+commit.80d5c536\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"premium\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"initiator\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"}],\"name\":\"executeOperation\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"executeOperation(address,uint256,uint256,address,bytes)\":{\"details\":\"\\u786e\\u4fdd\\u5408\\u7ea6\\u80fd\\u591f\\u5f52\\u8fd8\\u503a\\u52a1 + \\u989d\\u5916\\u8d39\\u7528\\uff0c\\u4f8b\\u5982\\uff0c\\u5177\\u6709 \\u8db3\\u591f\\u7684\\u8d44\\u91d1\\u6765\\u507f\\u8fd8\\uff0c\\u5e76\\u5df2\\u6279\\u51c6 Pool \\u63d0\\u53d6\\u603b\\u91d1\\u989d\",\"params\":{\"amount\":\"\\u95ea\\u7535\\u501f\\u6b3e\\u8d44\\u4ea7\\u7684\\u6570\\u91cf\",\"asset\":\"\\u95ea\\u7535\\u501f\\u6b3e\\u8d44\\u4ea7\\u7684\\u5730\\u5740\",\"initiator\":\"\\u53d1\\u8d77\\u95ea\\u7535\\u8d37\\u6b3e\\u7684\\u5730\\u5740\",\"params\":\"\\u521d\\u59cb\\u5316\\u95ea\\u7535\\u8d37\\u6b3e\\u65f6\\u4f20\\u9012\\u7684\\u5b57\\u8282\\u7f16\\u7801\\u53c2\\u6570\",\"premium\":\"\\u95ea\\u7535\\u501f\\u6b3e\\u8d44\\u4ea7\\u7684\\u8d39\\u7528\"},\"returns\":{\"_0\":\"\\u5982\\u679c\\u64cd\\u4f5c\\u7684\\u6267\\u884c\\u6210\\u529f\\u5219\\u8fd4\\u56de True\\uff0c\\u5426\\u5219\\u8fd4\\u56de False\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"executeOperation(address,uint256,uint256,address,bytes)\":{\"notice\":\"\\u5728\\u63a5\\u6536\\u95ea\\u7535\\u501f\\u6b3e\\u8d44\\u4ea7\\u540e\\u6267\\u884c\\u64cd\\u4f5c\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/57_Flashloan/src/AaveV3Flashloan.sol\":\"IFlashLoanSimpleReceiver\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/\"]},\"sources\":{\"src/57_Flashloan/src/AaveV3Flashloan.sol\":{\"keccak256\":\"0x61090dad9f54bff20ae111b2ae1b0128edba77be6084f0c9c5e3b81e7793704a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://26b84c57d72b499b698629e1522b3bff5c17ae3c5a5ad66a3fdc25cc3722e1f6\",\"dweb:/ipfs/QmYhfjmUbsDtPEcoLCeJjrfE1juxhzxQ3TmseRDSV7y9rP\"]},\"src/57_Flashloan/src/Lib.sol\":{\"keccak256\":\"0x9e0c02dca8bfcc0e98333a287ee8547fbef18c11e9f842794bb9f5d93d9619dc\",\"urls\":[\"bzz-raw://ffa2bcdd6f7cb221a4161c7e638c32f6ac7277050840174ffec5fa31d3b7c9be\",\"dweb:/ipfs/QmU1JPevALbdoq8sj4hMEReqCzCJ7VGLbDcDM9CPcmoXwc\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.34+commit.80d5c536"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"executeOperation(address,uint256,uint256,address,bytes)":{"details":"确保合约能够归还债务 + 额外费用,例如,具有 足够的资金来偿还,并已批准 Pool 提取总金额","params":{"amount":"闪电借款资产的数量","asset":"闪电借款资产的地址","initiator":"发起闪电贷款的地址","params":"初始化闪电贷款时传递的字节编码参数","premium":"闪电借款资产的费用"},"returns":{"_0":"如果操作的执行成功则返回 True,否则返回 False"}}},"version":1},"userdoc":{"kind":"user","methods":{"executeOperation(address,uint256,uint256,address,bytes)":{"notice":"在接收闪电借款资产后执行操作"}},"version":1}},"settings":{"remappings":["@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/"],"optimizer":{"enabled":false,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/57_Flashloan/src/AaveV3Flashloan.sol":"IFlashLoanSimpleReceiver"},"evmVersion":"prague","libraries":{}},"sources":{"src/57_Flashloan/src/AaveV3Flashloan.sol":{"keccak256":"0x61090dad9f54bff20ae111b2ae1b0128edba77be6084f0c9c5e3b81e7793704a","urls":["bzz-raw://26b84c57d72b499b698629e1522b3bff5c17ae3c5a5ad66a3fdc25cc3722e1f6","dweb:/ipfs/QmYhfjmUbsDtPEcoLCeJjrfE1juxhzxQ3TmseRDSV7y9rP"],"license":"MIT"},"src/57_Flashloan/src/Lib.sol":{"keccak256":"0x9e0c02dca8bfcc0e98333a287ee8547fbef18c11e9f842794bb9f5d93d9619dc","urls":["bzz-raw://ffa2bcdd6f7cb221a4161c7e638c32f6ac7277050840174ffec5fa31d3b7c9be","dweb:/ipfs/QmU1JPevALbdoq8sj4hMEReqCzCJ7VGLbDcDM9CPcmoXwc"],"license":null}},"version":1},"id":114}
2 changes: 1 addition & 1 deletion out/AaveV3Flashloan.t.sol/UniswapV2FlashloanTest.json

Large diffs are not rendered by default.

Loading