Modern Hazel Buffalo
High
The "buyer" newer gets the receiptID
ERC721 token from the "seller" in exchange for token
, because the receipt ERC721 token remains stuck in the BuyOrder
contract with no way to rescue / transfer it
Due to a mistake in the sellNFT
function, the buyInformation.owner
will never receive the purchased ERC721 token, as it will always be stuck in the address(this)
buyOrder
contract.
function sellNFT(uint receiptID) public {
require(buyInformation.isActive, "Buy order is not active");
require(
buyInformation.availableAmount > 0,
"Buy order is not available"
);
IERC721(buyInformation.wantedToken).transferFrom(
msg.sender,
address(this),
receiptID
);
Generally none.
None.
- Stephany creates a buy order through the
buyOrderFactory
contract in order to sell100e18
AERO
tokens and get aveNFT
in return, which would represent an equivalent amount of collateral tokens locked in a voting escrow. - A instance of the
buyOrder
contract is programmatically deployed and initialized viabuyOrderFactory
when thecreateBuyOrder
function is called. - Naomi has a
veNFT
that fits Stephany's requirements, and she callsbuyOrder
'ssellNFT
method. - In spite of exchange executed flawlessly, Stephany hasn't received the "bought"
veNFT
, because instead of transferring to Stephany, thebuyOrder
contract transferred the ERC721 token to itself.
Stephany never gets the "bought" veNFT, and just wastes the whole sold tokens amount meaninglessly.
Neither the buyOrder
's sellNFT
nor deleteBuyOrder
are able to rescue the "bought" ERC721 token / transfer it to Stephany.
// file: buyOrderFactory.sol
// ...
/**
* @dev create buy order
* @param _token token address you want to use to buy the wanted token
* @param wantedToken the token address you want to buy
* @param _amount amount of token you want to use to buy the wanted token
* @param ratio ratio you want to use to buy the wanted token (5e17:0.5)
*/
function createBuyOrder(
address _token,
address wantedToken,
uint _amount,
uint ratio
) public returns (address) {
// CHECKS
require(_amount > 0, "Amount must be greater than 0");
require(ratio > 0, "Ratio must be greater than 0");
DebitaProxyContract proxy = new DebitaProxyContract(
implementationContract
);
BuyOrder _createdBuyOrder = BuyOrder(address(proxy));
// INITIALIZE THE BUY ORDER
_createdBuyOrder.initialize(
msg.sender,
_token,
wantedToken,
address(this),
_amount,
ratio
);
// TRANSFER TOKENS TO THE BUY ORDER
SafeERC20.safeTransferFrom(
IERC20(_token),
msg.sender,
address(_createdBuyOrder),
_amount
);
// INDEX
isBuyOrderLegit[address(_createdBuyOrder)] = true;
BuyOrderIndex[address(_createdBuyOrder)] = activeOrdersCount;
allActiveBuyOrders[activeOrdersCount] = address(_createdBuyOrder);
activeOrdersCount++;
historicalBuyOrders.push(address(_createdBuyOrder));
emit BuyOrderCreated(
address(_createdBuyOrder),
msg.sender,
wantedToken,
_token,
_amount,
ratio
);
return address(_createdBuyOrder);
}
// file: buyOrder.sol
// ...
function initialize(
address _owner,
address _token,
address wantedToken,
address factory,
uint _amount,
uint ratio
) public initializer {
buyInformation = BuyInfo({
buyOrderAddress: address(this),
wantedToken: wantedToken,
buyRatio: ratio,
availableAmount: _amount,
capturedAmount: 0,
owner: _owner,
buyToken: _token,
isActive: true
});
buyOrderFactory = factory;
}
function deleteBuyOrder() public onlyOwner {
require(buyInformation.isActive, "Buy order is not active");
// save amount on memory
uint amount = buyInformation.availableAmount;
buyInformation.isActive = false;
buyInformation.availableAmount = 0;
SafeERC20.safeTransfer(
IERC20(buyInformation.buyToken),
buyInformation.owner,
amount
);
IBuyOrderFactory(buyOrderFactory)._deleteBuyOrder(address(this));
IBuyOrderFactory(buyOrderFactory).emitDelete(address(this));
}
function sellNFT(uint receiptID) public {
require(buyInformation.isActive, "Buy order is not active");
require(
buyInformation.availableAmount > 0,
"Buy order is not available"
);
IERC721(buyInformation.wantedToken).transferFrom(
msg.sender,
address(this),
receiptID
);
veNFR receipt = veNFR(buyInformation.wantedToken);
veNFR.receiptInstance memory receiptData = receipt.getDataByReceipt(
receiptID
);
uint collateralAmount = receiptData.lockedAmount;
uint collateralDecimals = receiptData.decimals;
uint amount = (buyInformation.buyRatio * collateralAmount) /
(10 ** collateralDecimals);
require(
amount <= buyInformation.availableAmount,
"Amount exceeds available amount"
);
buyInformation.availableAmount -= amount;
buyInformation.capturedAmount += collateralAmount;
uint feeAmount = (amount *
IBuyOrderFactory(buyOrderFactory).sellFee()) / 10000;
SafeERC20.safeTransfer(
IERC20(buyInformation.buyToken),
msg.sender,
amount - feeAmount
);
SafeERC20.safeTransfer(
IERC20(buyInformation.buyToken),
IBuyOrderFactory(buyOrderFactory).feeAddress(),
feeAmount
);
if (buyInformation.availableAmount == 0) {
buyInformation.isActive = false;
IBuyOrderFactory(buyOrderFactory).emitDelete(address(this));
IBuyOrderFactory(buyOrderFactory)._deleteBuyOrder(address(this));
} else {
IBuyOrderFactory(buyOrderFactory).emitUpdate(address(this));
}
}
function sellNFT(uint receiptID) public {
require(buyInformation.isActive, "Buy order is not active");
require(
buyInformation.availableAmount > 0,
"Buy order is not available"
);
IERC721(buyInformation.wantedToken).transferFrom(
msg.sender,
- address(this),
+ buyInformation.owner,
receiptID
);