run forge fmt and leave audit notes up to claimNft
This commit is contained in:
parent
1157105b63
commit
9055f078ba
@ -16,10 +16,7 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|||||||
* as possible.This is the first project that i code alone, in blockchain, foundry and solidity.
|
* as possible.This is the first project that i code alone, in blockchain, foundry and solidity.
|
||||||
* Thank you so much for read it.
|
* Thank you so much for read it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
contract TokenDivider is IERC721Receiver, Ownable {
|
contract TokenDivider is IERC721Receiver, Ownable {
|
||||||
|
|
||||||
error TokenDivider__NotFromNftOwner();
|
error TokenDivider__NotFromNftOwner();
|
||||||
error TokenDivider__NotEnoughErc20Balance();
|
error TokenDivider__NotEnoughErc20Balance();
|
||||||
error TokenDivider__NftTransferFailed();
|
error TokenDivider__NftTransferFailed();
|
||||||
@ -45,15 +42,13 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
uint256 amount;
|
uint256 amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev balances Relates a user with an amount of a erc20 token, this erc20 tokens is an nft fraction
|
* @dev balances Relates a user with an amount of a erc20 token, this erc20 tokens is an nft fraction
|
||||||
|
*
|
||||||
@dev nftToErc20Info Relates an nft with the erc20 pegged, and othe data like the erc20 amount, or the tokenId
|
* @dev nftToErc20Info Relates an nft with the erc20 pegged, and othe data like the erc20 amount, or the tokenId
|
||||||
|
*
|
||||||
@dev s_userToSellOrders Relates a user with an array of sell orders, that each sell order
|
* @dev s_userToSellOrders Relates a user with an array of sell orders, that each sell order
|
||||||
has a seller, an erc20 that is the token to sell, a price and an amount of erc20 to sell
|
* has a seller, an erc20 that is the token to sell, a price and an amount of erc20 to sell
|
||||||
|
|
||||||
*/
|
*/
|
||||||
mapping(address user => mapping(address erc20Address => uint256 amount)) balances;
|
mapping(address user => mapping(address erc20Address => uint256 amount)) balances;
|
||||||
mapping(address nft => ERC20Info) nftToErc20Info;
|
mapping(address nft => ERC20Info) nftToErc20Info;
|
||||||
@ -67,7 +62,6 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
event OrderPublished(uint256 indexed amount, address indexed seller, address indexed nftPegged);
|
event OrderPublished(uint256 indexed amount, address indexed seller, address indexed nftPegged);
|
||||||
event OrderSelled(address indexed buyer, uint256 price);
|
event OrderSelled(address indexed buyer, uint256 price);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Only the owner of the nft can call a function with this modifier
|
* Only the owner of the nft can call a function with this modifier
|
||||||
@ -81,15 +75,13 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
|
|
||||||
constructor() Ownable(msg.sender) {}
|
constructor() Ownable(msg.sender) {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Handles the receipt of an ERC721 token. This function is called whenever an ERC721 token is transferred to this contract.
|
* @dev Handles the receipt of an ERC721 token. This function is called whenever an ERC721 token is transferred to this contract.
|
||||||
*/
|
*/
|
||||||
function onERC721Received(
|
function onERC721Received(
|
||||||
address /* operator */,
|
address, /* operator */
|
||||||
address /* from */,
|
address, /* from */
|
||||||
uint256 /* tokenId */,
|
uint256, /* tokenId */
|
||||||
bytes calldata /* data */
|
bytes calldata /* data */
|
||||||
) external pure override returns (bytes4) {
|
) external pure override returns (bytes4) {
|
||||||
// Return this value to confirm the receipt of the NFT
|
// Return this value to confirm the receipt of the NFT
|
||||||
@ -105,25 +97,31 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
* @dev in this function, the nft passed as parameter, is locked by transfering it to this contract, then, it gives to the
|
* @dev in this function, the nft passed as parameter, is locked by transfering it to this contract, then, it gives to the
|
||||||
* person calling this function an amount of erc20, beeing like a fraction of this nft.
|
* person calling this function an amount of erc20, beeing like a fraction of this nft.
|
||||||
*/
|
*/
|
||||||
|
function divideNft(address nftAddress, uint256 tokenId, uint256 amount)
|
||||||
function divideNft(address nftAddress, uint256 tokenId, uint256 amount) onlyNftOwner(nftAddress, tokenId) onlyNftOwner(nftAddress ,tokenId) external {
|
external
|
||||||
|
onlyNftOwner(nftAddress, tokenId)
|
||||||
|
onlyNftOwner(nftAddress, tokenId)
|
||||||
if(nftAddress == address(0)) { revert TokenDivider__NftAddressIsZero(); }
|
{
|
||||||
if(amount == 0) { revert TokenDivider__AmountCantBeZero(); }
|
if (nftAddress == address(0)) revert TokenDivider__NftAddressIsZero();
|
||||||
|
if (amount == 0) revert TokenDivider__AmountCantBeZero();
|
||||||
|
// @audit: there is no checking of inExistence tokenId, it might handled on modifier but need to check
|
||||||
|
|
||||||
ERC20ToGenerateNftFraccion erc20Contract = new ERC20ToGenerateNftFraccion(
|
ERC20ToGenerateNftFraccion erc20Contract = new ERC20ToGenerateNftFraccion(
|
||||||
string(abi.encodePacked(ERC721(nftAddress).name(), "Fraccion")),
|
string(abi.encodePacked(ERC721(nftAddress).name(), "Fraccion")),
|
||||||
string(abi.encodePacked("F", ERC721(nftAddress).symbol())));
|
string(abi.encodePacked("F", ERC721(nftAddress).symbol()))
|
||||||
|
);
|
||||||
|
|
||||||
|
// @audit: can we mint again? out of this function?
|
||||||
erc20Contract.mint(address(this), amount);
|
erc20Contract.mint(address(this), amount);
|
||||||
address erc20 = address(erc20Contract);
|
address erc20 = address(erc20Contract);
|
||||||
|
|
||||||
IERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenId, "");
|
IERC721(nftAddress).safeTransferFrom(msg.sender, address(this), tokenId, "");
|
||||||
|
|
||||||
if(IERC721(nftAddress).ownerOf(tokenId) == msg.sender) { revert TokenDivider__NftTransferFailed(); }
|
// @audit: what if we send the NFT to other address during this period?
|
||||||
|
if (IERC721(nftAddress).ownerOf(tokenId) == msg.sender) revert TokenDivider__NftTransferFailed();
|
||||||
|
|
||||||
balances[msg.sender][erc20] = amount;
|
balances[msg.sender][erc20] = amount;
|
||||||
|
// @audit: what happen if the given nft address already registered in this CA, then another token id register again?
|
||||||
nftToErc20Info[nftAddress] = ERC20Info({erc20Address: erc20, tokenId: tokenId});
|
nftToErc20Info[nftAddress] = ERC20Info({erc20Address: erc20, tokenId: tokenId});
|
||||||
erc20ToMintedAmount[erc20] = amount;
|
erc20ToMintedAmount[erc20] = amount;
|
||||||
erc20ToNft[erc20] = nftAddress;
|
erc20ToNft[erc20] = nftAddress;
|
||||||
@ -143,30 +141,31 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
* @dev in this function, if you have all the erc20 minted for the nft, you can call this function to claim the nft,
|
* @dev in this function, if you have all the erc20 minted for the nft, you can call this function to claim the nft,
|
||||||
* giving to the contract all the erc20 and it will give you back the nft
|
* giving to the contract all the erc20 and it will give you back the nft
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function claimNft(address nftAddress) external {
|
function claimNft(address nftAddress) external {
|
||||||
|
|
||||||
if (nftAddress == address(0)) {
|
if (nftAddress == address(0)) {
|
||||||
revert TokenDivider__NftAddressIsZero();
|
revert TokenDivider__NftAddressIsZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @audit: what if the nft address is not stored?
|
||||||
ERC20Info storage tokenInfo = nftToErc20Info[nftAddress];
|
ERC20Info storage tokenInfo = nftToErc20Info[nftAddress];
|
||||||
|
|
||||||
if (balances[msg.sender][tokenInfo.erc20Address] < erc20ToMintedAmount[tokenInfo.erc20Address]) {
|
if (balances[msg.sender][tokenInfo.erc20Address] < erc20ToMintedAmount[tokenInfo.erc20Address]) {
|
||||||
revert TokenDivider__NotEnoughErc20Balance();
|
revert TokenDivider__NotEnoughErc20Balance();
|
||||||
}
|
}
|
||||||
|
|
||||||
ERC20ToGenerateNftFraccion(tokenInfo.erc20Address).burnFrom(msg.sender, erc20ToMintedAmount[tokenInfo.erc20Address]);
|
ERC20ToGenerateNftFraccion(tokenInfo.erc20Address).burnFrom(
|
||||||
|
msg.sender, erc20ToMintedAmount[tokenInfo.erc20Address]
|
||||||
|
);
|
||||||
|
|
||||||
balances[msg.sender][tokenInfo.erc20Address] = 0;
|
balances[msg.sender][tokenInfo.erc20Address] = 0;
|
||||||
erc20ToMintedAmount[tokenInfo.erc20Address] = 0;
|
erc20ToMintedAmount[tokenInfo.erc20Address] = 0;
|
||||||
|
|
||||||
emit NftClaimed(nftAddress);
|
emit NftClaimed(nftAddress);
|
||||||
|
|
||||||
|
// @audit: what happen if there is overlaps in same NFT address with different token id? will someone get a different NFT?
|
||||||
IERC721(nftAddress).safeTransferFrom(address(this), msg.sender, tokenInfo.tokenId);
|
IERC721(nftAddress).safeTransferFrom(address(this), msg.sender, tokenInfo.tokenId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param nftAddress The nft address pegged to the erc20
|
* @param nftAddress The nft address pegged to the erc20
|
||||||
@ -175,9 +174,7 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
*
|
*
|
||||||
* @dev you can use this function to transfer nft franctions 100% securily and registered by te contract
|
* @dev you can use this function to transfer nft franctions 100% securily and registered by te contract
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function transferErcTokens(address nftAddress, address to, uint256 amount) external {
|
function transferErcTokens(address nftAddress, address to, uint256 amount) external {
|
||||||
|
|
||||||
if (nftAddress == address(0)) {
|
if (nftAddress == address(0)) {
|
||||||
revert TokenDivider__NftAddressIsZero();
|
revert TokenDivider__NftAddressIsZero();
|
||||||
}
|
}
|
||||||
@ -217,7 +214,6 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
* firstly, once you call this function, the amount of tokens that you passed into as a parameter, get blocked, by sending it
|
* firstly, once you call this function, the amount of tokens that you passed into as a parameter, get blocked, by sending it
|
||||||
* to this contract, then a new order is created and published.
|
* to this contract, then a new order is created and published.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function sellErc20(address nftPegged, uint256 price, uint256 amount) external {
|
function sellErc20(address nftPegged, uint256 price, uint256 amount) external {
|
||||||
if (nftPegged == address(0)) {
|
if (nftPegged == address(0)) {
|
||||||
revert TokenDivider__NftAddressIsZero();
|
revert TokenDivider__NftAddressIsZero();
|
||||||
@ -235,12 +231,7 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
balances[msg.sender][tokenInfo.erc20Address] -= amount;
|
balances[msg.sender][tokenInfo.erc20Address] -= amount;
|
||||||
|
|
||||||
s_userToSellOrders[msg.sender].push(
|
s_userToSellOrders[msg.sender].push(
|
||||||
SellOrder({
|
SellOrder({seller: msg.sender, erc20Address: tokenInfo.erc20Address, price: price, amount: amount})
|
||||||
seller: msg.sender,
|
|
||||||
erc20Address: tokenInfo.erc20Address,
|
|
||||||
price: price,
|
|
||||||
amount: amount
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
|
|
||||||
emit OrderPublished(amount, msg.sender, nftPegged);
|
emit OrderPublished(amount, msg.sender, nftPegged);
|
||||||
@ -248,7 +239,6 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
IERC20(tokenInfo.erc20Address).transferFrom(msg.sender, address(this), amount);
|
IERC20(tokenInfo.erc20Address).transferFrom(msg.sender, address(this), amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param orderIndex The index of the order in all the orders array of the seller (the seller can have multiple orders active)
|
* @param orderIndex The index of the order in all the orders array of the seller (the seller can have multiple orders active)
|
||||||
@ -257,14 +247,11 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
* @dev when the buyer call this function, the eth or any token accepted to pay, is sent to the seller
|
* @dev when the buyer call this function, the eth or any token accepted to pay, is sent to the seller
|
||||||
* if the transfer executed correctly, then this contract, wich has all the tokens, send the tokens to the msg.sender
|
* if the transfer executed correctly, then this contract, wich has all the tokens, send the tokens to the msg.sender
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function buyOrder(uint256 orderIndex, address seller) external payable {
|
function buyOrder(uint256 orderIndex, address seller) external payable {
|
||||||
if (seller == address(0)) {
|
if (seller == address(0)) {
|
||||||
revert TokenDivider__InvalidSeller();
|
revert TokenDivider__InvalidSeller();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SellOrder memory order = s_userToSellOrders[seller][orderIndex];
|
SellOrder memory order = s_userToSellOrders[seller][orderIndex];
|
||||||
|
|
||||||
if (msg.value < order.price) {
|
if (msg.value < order.price) {
|
||||||
@ -274,12 +261,10 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
uint256 fee = order.price / 100;
|
uint256 fee = order.price / 100;
|
||||||
uint256 sellerFee = fee / 2;
|
uint256 sellerFee = fee / 2;
|
||||||
|
|
||||||
|
|
||||||
if (msg.value < order.price + sellerFee) {
|
if (msg.value < order.price + sellerFee) {
|
||||||
revert TokenDivider__InsuficientEtherForFees();
|
revert TokenDivider__InsuficientEtherForFees();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
balances[msg.sender][order.erc20Address] += order.amount;
|
balances[msg.sender][order.erc20Address] += order.amount;
|
||||||
|
|
||||||
s_userToSellOrders[seller][orderIndex] = s_userToSellOrders[seller][s_userToSellOrders[seller].length - 1];
|
s_userToSellOrders[seller][orderIndex] = s_userToSellOrders[seller][s_userToSellOrders[seller].length - 1];
|
||||||
@ -297,17 +282,16 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
|
|
||||||
(bool taxSuccess,) = payable(owner()).call{value: fee}("");
|
(bool taxSuccess,) = payable(owner()).call{value: fee}("");
|
||||||
|
|
||||||
|
|
||||||
if (!taxSuccess) {
|
if (!taxSuccess) {
|
||||||
revert TokenDivider__TransferFailed();
|
revert TokenDivider__TransferFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
IERC20(order.erc20Address).transfer(msg.sender, order.amount);
|
IERC20(order.erc20Address).transfer(msg.sender, order.amount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Getters */
|
/**
|
||||||
|
* Getters
|
||||||
|
*/
|
||||||
function getBalanceOf(address user, address token) public view returns (uint256) {
|
function getBalanceOf(address user, address token) public view returns (uint256) {
|
||||||
return balances[user][token];
|
return balances[user][token];
|
||||||
}
|
}
|
||||||
@ -323,5 +307,4 @@ contract TokenDivider is IERC721Receiver,Ownable {
|
|||||||
function getOrderPrice(address seller, uint256 index) public view returns (uint256 price) {
|
function getOrderPrice(address seller, uint256 index) public view returns (uint256 price) {
|
||||||
price = s_userToSellOrders[seller][index].price;
|
price = s_userToSellOrders[seller][index].price;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user