Omniscia Native Audit
Pool Manual Review Findings
Pool Manual Review Findings
PLO-01M: Arbitrary Unique ID
| Type | Severity | Location |
|---|---|---|
| Code Style | ![]() | Pool.sol:L361 |
Description:
The pricingModelId of 99 uses a specialized calculation mechanism that is inexplicable.
Example:
361if (pricingModelId != 99) {362 if (isExactIn) {363 buyerTokenAmount = getAmountOut(364 sellerTokenAmount,365 _order.sellerToken,366 _order.buyerToken367 );368 } else {369 sellerTokenAmount = getAmountIn(370 buyerTokenAmount,371 _order.sellerToken,372 _order.buyerToken373 );374 }375} else {376 require(377 _order.sellerTokenAmount > 0 && _order.buyerTokenAmount > 0,378 "Non-zero amount required"379 );380
381 if (sellerTokenAmount > 0) {382 buyerTokenAmount = FullMath.mulDiv(383 sellerTokenAmount,384 _order.buyerTokenAmount,385 _order.sellerTokenAmount386 );387 } else if (buyerTokenAmount > 0) {388 sellerTokenAmount = FullMath.mulDiv(389 buyerTokenAmount,390 _order.sellerTokenAmount,391 _order.buyerTokenAmount392 );393 }394}Recommendation:
We advise the documentation of the codebase to be enhanced and the literal to be relocated to a contract-level constant, optimizing the legibility of the codebase. As an additional step, we advise the conditional mechanism to be omitted entirely and the pricing model employed in the else branch to simply be implemented in the pricing registry.
Alleviation:
The 99 value literal was relocated to a contract-level constant declaration labelled FIXED_PRICE_MODEL_ID. This indicates that the exchange ratio is dictated by the off-chain service of Native rather than on-chain data. As the payload is validated as signed in the swap function that invokes calculateTokenAmount, we consider this exhibit alleviated and behaving as expected.
PLO-02M: Inexplicable Loop Iteration
| Type | Severity | Location |
|---|---|---|
| Logical Fault | ![]() | Pool.sol:L235, L237-L250 |
Description:
The executeUpdatePairs function permits only one pair to be added due to the require check mandating _fees.length to be less-than-or-equal-to 1.
Example:
234function executeUpdatePairs(uint256[] memory _fees, address[] memory _tokenAs, address[] memory _tokenBs, uint256[] memory _pricingModelIds) private {235 require(_fees.length <= 1, "Each pool only supports 1 pair.");236 require(isPairAdded == false || pairExist(_tokenAs[0], _tokenBs[0]), "Please remove existing pair before adding a new pair.");237 for (uint i = 0; i < _fees.length; i++) {238 require(_tokenAs[i] != _tokenBs[i], "Identical addresses");239 (address token0, address token1) = _tokenAs[i] < _tokenBs[i]240 ? (_tokenAs[i], _tokenBs[i])241 : (_tokenBs[i], _tokenAs[i]);242 require(token0 != address(0), "Zero address in pair"); 243 if (pairExist(token0, token1) == false) {244 tokenAs.push(token0);245 tokenBs.push(token1);246 isPairAdded = true;247 pairCount++;248 } 249 pairs[token0][token1] = Pair(_fees[i], true, _pricingModelIds[i]);250 }251 252}Recommendation:
We advise the code to instead be revamped to implement a single pool instead, adjusting all relevant code that utilizes array based entries.
Alleviation:
The Native team evaluated this exhibit but opted not to apply a remediation for it as they consider it inconsequential.
PLO-03M: Inexistent Limitation of Fee
| Type | Severity | Location |
|---|---|---|
| Input Sanitization | ![]() | Pool.sol:L249 |
Description:
The _fees[i] value that is assigned to a particular pair is not sanitized in the executeUpdatePairs function.
Impact:
Mistyped fees can cause pairs to become inoperable or to charge abnormally high fees.
Example:
234function executeUpdatePairs(uint256[] memory _fees, address[] memory _tokenAs, address[] memory _tokenBs, uint256[] memory _pricingModelIds) private {235 require(_fees.length <= 1, "Each pool only supports 1 pair.");236 require(isPairAdded == false || pairExist(_tokenAs[0], _tokenBs[0]), "Please remove existing pair before adding a new pair.");237 for (uint i = 0; i < _fees.length; i++) {238 require(_tokenAs[i] != _tokenBs[i], "Identical addresses");239 (address token0, address token1) = _tokenAs[i] < _tokenBs[i]240 ? (_tokenAs[i], _tokenBs[i])241 : (_tokenBs[i], _tokenAs[i]);242 require(token0 != address(0), "Zero address in pair"); 243 if (pairExist(token0, token1) == false) {244 tokenAs.push(token0);245 tokenBs.push(token1);246 isPairAdded = true;247 pairCount++;248 } 249 pairs[token0][token1] = Pair(_fees[i], true, _pricingModelIds[i]);250 }251 252}Recommendation:
We advise it to be adequately sanitized as representing a valid percentage based on the IPricer implementations of the repository (UniswapV2Pricer & ConstantSumPricer).
Alleviation:
The fee is now mandated to be within a valid range, however, this is done inefficiently as it evaluates that _fees[i] >= 0 when _fees[i] represents an unsigned integer which will always be non-negative. In any case, we consider this exhibit alleviated as the upper bound is properly applied.
PLO-04M: Inexplicable Payable Function Attribute
| Type | Severity | Location |
|---|---|---|
| Language Specific | ![]() | Pool.sol:L148 |
Description:
The swap function is attributed as payable, however, it does not handle native funds causing them to be permanently locked.
Impact:
Any funds transmitted to the Pool contract as part of a swap call will be permanently locked in the contract.
Example:
148) external payable override nonReentrant whenNotPaused onlyRouter noDelegateCall returns (int256, int256) {Recommendation:
We advise the function to have its payable attribute omitted as it serves no purpose.
Alleviation:
The payable function attribute has been safely omitted as advised.
PLO-05M: Unsafe Casting Operations
| Type | Severity | Location |
|---|---|---|
| Language Specific | ![]() | Pool.sol:L480, L481 |
Description:
The referenced statements perform an unsafe casting operation from a uint256 data type to an int256 data type.
Impact:
As the casting overflow will benefit the user due to its presence in the executeSwapToTreasury function, a carefully crafted order payload can be exploited to extract a set of funds from the treasury whilst transmitting close to none.
Example:
480int256 outputSellerTokenAmount = int256(sellerTokenAmount);481int256 outputBuyerTokenAmount = -1 * int256(buyerTokenAmount);Recommendation:
We advise the casting operations to be performed safely as they can presently overflow and become corrupted.
Alleviation:
The limitations on the input variables have been properly applied, however, they inefficiently use the value of type(uint256).max / 2 as a comparator rather than the value of type(int256).max.


