Missing payable and approval functionalities to send verifier fees to chainlink's feemanager contract.
In ChainlinkUtil.sol, there's the verifyReport
function which is used to verify chainlink prices using chainlinkVerifier contract. The function is intended to send the fee amount in ETH to VerifierProxy.sol, we can see that the call to chainlink verifier attempts to send the fee.amount
as ETH.
And as can be seen from VerifierProxy.sol, the function expects and uses msg.value as fee amount.
This is all well and good, however, none the functions calling the verifyReport
function are payable, nor do they have a receive functionality with which they can receive and later forward the ETH fee to the verifier contract.
To prove this, we'll follow the function logic.
Using the search functionality, we can see that the verifyReport
function is called in SettlementConfiguration.sol library in the verifyDataStreamsReport
function. The function as can be seen is not marked payable, nor does the library hold a source of receiving ETH.
And in searching for verifyDataStreamsReport
function, we discover it's also in use in the verifyOffchainPrice
function, also in SettlementConfiguration.sol. And as can be observed, the function is not marked payable, nor does the librarys have any way of receiving ETH.
Repeating the search process, we discover that verifyOffchainPrice
is used in two major functions in SettlementBranch.sol. The fillMarketOrder
and the fillOffchainOrders
which are called by their keeper respective keepers.
Notice that these functions are also not marked payable, neither does the contract have a way of receiving ETH due to its lack of the receive
functionality.
As a result, calls to these functions, will fail if the fee.amount
is > 0 as ETH is not sent.
Now, Chainlink probabaly expected this and therefore allows the subscribers to pay in WETH instead, as the native token if ETH is not sent. Following the logic chain from the verify
function in VerifierProxy.sol, the function attempts to process fees in the fee manager through the processFee
function.
In the processFee
function, the _handleFeesAndRewards
is called using parameters for i_nativeAddress
not i_linkaddress
since our chainlinkUtil library uses that as our fee token and fee amount source.
In _handleFeesAndRewards
, we can see how the fee is handled. If msg.value is not sent, an attempt is made to transfer the i_nativeAddress
from the subscriber, in this case, our msg.sender in VerifierProxy.sol, which is the contract that started the entire chain, (not the libraries) which is SettlementBranch.sol.
And by going through SettlementBranch.sol, or the entire codebase, there's no instance of the the FeeManager being approved to transfer i_nativeAddress
tokens, which according to arbiscan is WETH.
In conclusion, any of the functions that require offchain price verification stand the risk of failure, due to fees not being sent as ETH, or chainlink's fee manager being approved to transfer its wrapped counter part. And as a result, such functions will fail.
The function chain to follow goes like this:
verifyReport
-> verifyDataStreamsReport
-> verifyOffchainPrice
-> fillOffchainOrders
& fillMarketOrder
fillMarketOrder
is further user in MarketOrderKeeper.sol in the performUpkeep
function.
Manual Code Review
Introduce a payable or receive functionality in the needed contract. Alternatively, approve the feemanager to spend the feeamount of the nativeaddress token before verification.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.