Hi everyone, the Integrations Team also reviewed this last week. @joaobrunoah, @gerg, and myself each put eyes on the code. We agree that the do_arb function, in the context of the specified Gnosis transaction batch, is safe to execute. We also had the following comments which amount to an informational QA report; none of the issues mentioned has a material impact on execution when viewed in the context of this specific payload. Line numbers and function names refer to the bbeUSD_arb contract.
Trust Assumptions
All external functions are marked onlyOwner, so only the current owner or any future owner (after ownership transfer) has the power to execute. If we trust the current owner to properly execute and not to transfer ownership to a malicious entity, then we can trust the contract.
Quality Assurance Report
- The
do_arbfunction will fail for all pools if any one of the providedinputTokens[i]has a 0 balance or doesn’t contain the specifiedoutputTokens[i]. - For governance transparency, the
recipientaddress (do_arb) andpayeeaddresses (withdrawandsweep) should be immutable: either hard-coded or specified at construction time. - There is a comment implying that this is a single-use contract but nothing to enforce it.
- The
sweepfunction should utilizesafeTransferto account for tokens like USDT (out of scope for the specified payload). - The deadline (
block.timestamp + 30) on line 43 represents an infinite deadline. To specify a real deadline, the timestamp must be passed into this contract from off chain. For an infinite deadline, prefer something liketype(uint256).maxfor clarity. -
<payable>.transfer(amount)can fail. It is preferable to use(bool sent, bytes memory data) = <payable>.call{value: amount}, but if the payee is expected to be an EOA or a contract with minimal receive logic, it is fine. -
do_arbneeds more comments (NatSpec) to explain what the function does and the main parts of its code. It’s unclear when reading it and even harder to understand if the contract does what the author intended, because author’s intentions are not documented in the code. -
inputTokensshould be renamed tolinearPoolsor similar to distinguish it from a generic array of ERC-20 tokens. -
lt(line 25) should be renamed tolinearPoolor another more descriptive name. -
usdToken(line 26) is not used and should be removed. -
foo(line 27) is not used and should be removed. -
10 ** 50(line 43) seems arbitrary and could be replaced bytype(uint256).max. -
outputTokensis unnecessary because we already validate it againstlinearPool.mainToken(). Just use that getter directly. -
dustFactorsis a strange way to fuzz the output — could alternatively calculate the amount of fees the pool will collect as it’s drained. - The
payeein theinternal_sweepfunction does not need to bepayablesince it does not handle ETH. - The
@authortag misspells one of the author’s names.
Gas Optimizations
-
inputTokens,outputTokensanddustFactorcan becalldatainstead ofmemory. - In the for loops, change
i++to++i. - Instead of calling
lt.getPoolId()3 times, use thepoolIdvariable from line 38. - The whole
do_arbfunction can be rewritten to use a single batchSwap instead of multiple swaps:
before loop:
create empty array of assets (IAssets)
create empty array of swaps (BatchSwapStep)
create empty array of limits (uint256)
in loop:
add in/out tokens to assets array
populate BatchSwapStep array w/ indices of in/out tokens
populate limits
after loop:
populate FundManagement struct
set deadline (see comment above about block.timestamp being useless as a deadline)
execute batchSwap