Omniscia Tangible Audit
SellFeeDistributorV2 Manual Review Findings
SellFeeDistributorV2 Manual Review Findings
SFD-01M: Inexistent Protection of Fee Distribution
Type | Severity | Location |
---|---|---|
Logical Fault | SellFeeDistributorV2.sol:L123-L125 |
Description:
The SellFeeDistributorV2::distributeFee
function does not impose any access control.
Impact:
While it does not lead to any active vulnerability manifesting, it is still advisable to reduce the potential attack surface of the contract by restricting callers of its balance-managing SellFeeDistributorV2::distributeFee
function.
Example:
123function distributeFee(IERC20 _paymentToken, uint256 _feeAmount) external {124 _distributeFee(_paymentToken, _feeAmount);125}
Recommendation:
We advise it to be solely invoke-able by the MarketplaceV2
implementation, based on the workflow employed in MarketplaceV2::_buy
.
Alleviation (2ad448279d9e8e4b6edd94bcd2eb22129b6f7357):
The Tangible team specifies that this is intentional to allow external integration of the fee distribution workflow.
As a result, we consider this exhibit to pertain to desirable behaviour and thus nullified.
SFD-02M: Inexistent Tangible Token Burn Workflow (Satellite Chain)
Type | Severity | Location |
---|---|---|
Logical Fault | SellFeeDistributorV2.sol:L161-L167 |
Description:
The SellFeeDistributorV2::_distributeFee
function will only burn the TNGBL
tokens it acquires if the contract has been deployed on the mainnet whilst in any other case the funds will simply remain within the contract.
Impact:
The contract will significantly misbehave if it ever receives a fee distribution whereby the _paymentToken
is the TNGBL
asset as it will re-distribute supposedly "burned" TNGBL
units.
Example:
134function _distributeFee(IERC20 _paymentToken, uint256 _feeAmount) internal {135 //take 66.6666% and send to revenueShare136 uint256 amountForRevenue = (_feeAmount * revenuePercent) / FULL_PORTION;137 uint256 amountForBurn = _feeAmount - amountForRevenue;138 if (address(_paymentToken) != address(USDC)) {139 //we need to convert the payment token to usdc140 _paymentToken.approve(address(exchange), amountForRevenue);141 amountForRevenue = exchange.exchange(142 address(_paymentToken),143 address(USDC),144 amountForRevenue,145 exchange.quoteOut(address(_paymentToken), address(USDC), amountForRevenue)146 );147 }148 USDC.safeTransfer(revenueShare, amountForRevenue);149 emit FeeDistributed(revenueShare, amountForRevenue);150
151 //convert 33.334% to tngbl and burn it152 // exchange usdc for tngbl153 _paymentToken.approve(address(exchange), amountForBurn);154 uint256 tngblToBurn = exchange.exchange(155 address(_paymentToken),156 address(TNGBL),157 amountForBurn,158 exchange.quoteOut(address(_paymentToken), address(TNGBL), amountForBurn)159 );160
161 if (isMainnet) {162 //burn the tngbl163 TNGBL.approve(address(this), tngblToBurn);164 ERC20Burnable(address(TNGBL)).burn(tngblToBurn);165
166 emit TangibleBurned(tngblToBurn);167 }168}
Recommendation:
We advise the code to instead transfer the funds to a known "dead" address, such as 0xdeaDDeADDEaDdeaDdEAddEADDEAdDeadDEADDEaD
, properly taking the TNGBL
units acquired out of circulation.
Alleviation (2ad448279d9e8e4b6edd94bcd2eb22129b6f7357):
The code has been updated to properly distribute the tngblToBurn
funds to the 0xdeaDDeADDEaDdeaDdEAddEADDEAdDeadDEADDEaD
address in case the contract is deployed in a satellite chain, alleviating this exhibit in full.
SFD-03M: Insecure On-Chain Trades
Type | Severity | Location |
---|---|---|
Logical Fault | SellFeeDistributorV2.sol:L145, L158 |
Description:
The SellFeeDistributorV2::_distributeFee
function will insecurely perform two swaps to the USDC
and TNGBL
asset from the _paymentToken
as it will specify the minimum-outputs it accepts using on-chain data, as evidenced by the Exchange::quoteOut
implementation.
Impact:
Presently, all funds swapped via the SellFeeDistributorV2::_distributeFee
function are susceptible to on-chain slippage attacks, such as sandwich attacks.
Example:
134function _distributeFee(IERC20 _paymentToken, uint256 _feeAmount) internal {135 //take 66.6666% and send to revenueShare136 uint256 amountForRevenue = (_feeAmount * revenuePercent) / FULL_PORTION;137 uint256 amountForBurn = _feeAmount - amountForRevenue;138 if (address(_paymentToken) != address(USDC)) {139 //we need to convert the payment token to usdc140 _paymentToken.approve(address(exchange), amountForRevenue);141 amountForRevenue = exchange.exchange(142 address(_paymentToken),143 address(USDC),144 amountForRevenue,145 exchange.quoteOut(address(_paymentToken), address(USDC), amountForRevenue)146 );147 }148 USDC.safeTransfer(revenueShare, amountForRevenue);149 emit FeeDistributed(revenueShare, amountForRevenue);150
151 //convert 33.334% to tngbl and burn it152 // exchange usdc for tngbl153 _paymentToken.approve(address(exchange), amountForBurn);154 uint256 tngblToBurn = exchange.exchange(155 address(_paymentToken),156 address(TNGBL),157 amountForBurn,158 exchange.quoteOut(address(_paymentToken), address(TNGBL), amountForBurn)159 );160
161 if (isMainnet) {162 //burn the tngbl163 TNGBL.approve(address(this), tngblToBurn);164 ERC20Burnable(address(TNGBL)).burn(tngblToBurn);165
166 emit TangibleBurned(tngblToBurn);167 }168}
Recommendation:
We advise the code to instead utilize a decentralized way of measuring the outputs of the swaps, potentially via the usage of Chainlink oracles or TWAP mechanisms, ensuring that the trades performed by the SellFeeDistributorV2
are not susceptible to sandwich attacks.
Alleviation (2ad448279d9e8e4b6edd94bcd2eb22129b6f7357):
The code of the Exchange::quoteOut
function was significantly refactored to utilize a TWAP mechanism, ensuring that the output estimations it yields are less susceptible to manipulation.
While we consider this solution adequate for small exchanges, we advise the Tangible team to incorporate a manipulation-less mechanism to estimate outputs if they deem the exchanges they are used in to be of high value (i.e. surpassing 6 figures).
We will mark this exhibit as alleviated and will request the Tangible to revisit in case they wish to perform further changes.