IOP _ ThunderNFT 34957 - [Smart Contract - Critical] executionResults always returns an amount of le
Submitted on Sun Sep 01 2024 20:02:08 GMT-0400 (Atlantic Standard Time) by @SimaoAmaro for IOP | ThunderNFT
Report ID: #34957
Report type: Smart Contract
Report severity: Critical
Target: https://github.com/ThunderFuel/smart-contracts/tree/main/contracts-v1/libraries
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Brief/Intro
Executed orders always transfer 1 nft to the taker, when the maker order may have deposited more than 1 amount of the given collection and token id nft to the ThunderExchange.
Vulnerability Details
When executing orders in ThunderExchange::executeOrder(), it gets the result of the execution from the picked strategy, strategy_fixed_price_sale in this case, more precisely from ExecutionResult::s1(), which always returns an amount of 1.
However, orders may be place with an amount bigger than 1 as the ThunderExchange supports erc1155 style nfts. Thus, The following scenario will happen:
User places an order of a certain erc1155 style nft with an amount bigger than 1.
Another user executes the order, but only receives 1 nft, instead of the whole amount in the order. The remaining nfts get stuck in the
ThunderExchange.
Impact Details
Stuck nfts in the ThunderExchange.
References
https://github.com/ThunderFuel/smart-contracts/blob/main/contracts-v1/libraries/src/execution_result.sw#L31
Proof of concept
Proof of Concept
To run a proof of concept, the exchange was modified to allow a maker of type Contract, as Sway tests do not support pranking an EOA.
Additionally, 3 new contracts were created, one user contract simulating a user placing an order, another user contract simulating a user executing the order and a erc1155 contract, simulating an erc1155 token.
The full changes were pushed to a github repository which can be shared with the team if requested.
The main test file is the following:
The user contract placing the order is:
The user contract executing the order is:
The erc1155 is the same as the erc721, but the mint function had the checks removed to allow more than 1 coin per token id:
Last updated
Was this helpful?