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_arb
function 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
recipient
address (do_arb
) andpayee
addresses (withdraw
andsweep
) 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
sweep
function should utilizesafeTransfer
to 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).max
for 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_arb
needs 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. -
inputTokens
should be renamed tolinearPools
or similar to distinguish it from a generic array of ERC-20 tokens. -
lt
(line 25) should be renamed tolinearPool
or 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
. -
outputTokens
is unnecessary because we already validate it againstlinearPool.mainToken()
. Just use that getter directly. -
dustFactors
is a strange way to fuzz the output — could alternatively calculate the amount of fees the pool will collect as it’s drained. - The
payee
in theinternal_sweep
function does not need to bepayable
since it does not handle ETH. - The
@author
tag misspells one of the author’s names.
Gas Optimizations
-
inputTokens
,outputTokens
anddustFactor
can becalldata
instead ofmemory
. - In the for loops, change
i++
to++i
. - Instead of calling
lt.getPoolId()
3 times, use thepoolId
variable from line 38. - The whole
do_arb
function 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