Problem
The driver can now use multiple EOAs for settlement submission with EIP-7702, but it does not check whether the selected EOA is actually usable before relying on it.
Auxiliary EOAs are selected from a FIFO queue. This means the selection order is fair, but it is not health-aware. If the next EOA in the queue has no funds, a bad nonce, or cannot replace a pending transaction, the driver can still select it.
Once that EOA is selected, the driver submits the settlement using that same signer. If submission fails because the selected EOA is unusable, the settlement fails. The driver does not try another available EOA.
For example:
EOA1 is next in the auxiliary queue
EOA1 has no native token for gas
EOA2 is funded and available
- the driver selects
EOA1
- submission fails
- the driver does not retry with
EOA2
So the issue is not that auxiliary EOAs are selected unfairly. The issue is that the selection is not health-aware, and there is no fallback when the selected EOA cannot submit.
Impact
Impact: high.
A valid settlement can fail even when another usable EOA is available.
This reduces the reliability of EIP-7702 parallel settlement submission and can cause missed settlement opportunities. It also makes operations harder because an underfunded or nonce-stuck EOA can keep causing failures until operators notice and fix it manually.
To reproduce (not tested manually)
- Use latest
origin/main at commit 754bb6a0a.
- Configure a solver with multiple EIP-7702
submission_accounts.
- Make the next auxiliary EOA in the FIFO queue unusable, for example by leaving it without enough native token for gas.
- Keep another auxiliary EOA funded and available.
- Trigger a delegated settlement submission.
- Observe that the driver selects the unusable EOA.
- Observe that submission fails.
- Observe that the driver does not retry the same settlement with the funded auxiliary EOA.
Expected behaviour
Before selecting or using an EOA, the driver should check simple health signals where possible:
- native token balance is enough to pay for gas
- nonce state is okay (no pending transaction, e.g. rebalancing ERC20 assets while driver attempts to use that EOA for submission)
- account is not already known to be stuck or failing (some sort of blacklist?)
If the selected EOA fails for an account-specific reason, the driver should skip it and try another eligible EOA while the settlement is still valid. Account-specific failures include:
- insufficient funds for gas
- bad or stuck nonce
- replacement transaction underpriced etc.
The driver should not retry with another EOA for settlement-specific failures, such as:
- bad calldata
- target revert
- invalid on-chain state
- expired submission deadline
The driver should also temporarily mark unhealthy EOAs as unavailable so they are not selected again immediately.
Screenshots/logs
Current behavior from code inspection on latest origin/main at commit 754bb6a0a:
services version/commit hash and environment
Version / commit hash: 754bb6a0a
Additional context
The production runbook expects this kind of fallback behavior.
For underfunded or nonce-stuck auxiliary EOAs, the runbook expects:
- skip the bad auxiliary EOA
- use another funded auxiliary EOA if available
- fall back to direct submission when safe
- stop assigning new submissions to stuck nonce lanes until fixed
The driver should be updated so the implementation matches that operational model.
Problem
The driver can now use multiple EOAs for settlement submission with EIP-7702, but it does not check whether the selected EOA is actually usable before relying on it.
Auxiliary EOAs are selected from a FIFO queue. This means the selection order is fair, but it is not health-aware. If the next EOA in the queue has no funds, a bad nonce, or cannot replace a pending transaction, the driver can still select it.
Once that EOA is selected, the driver submits the settlement using that same signer. If submission fails because the selected EOA is unusable, the settlement fails. The driver does not try another available EOA.
For example:
EOA1is next in the auxiliary queueEOA1has no native token for gasEOA2is funded and availableEOA1EOA2So the issue is not that auxiliary EOAs are selected unfairly. The issue is that the selection is not health-aware, and there is no fallback when the selected EOA cannot submit.
Impact
Impact: high.
A valid settlement can fail even when another usable EOA is available.
This reduces the reliability of EIP-7702 parallel settlement submission and can cause missed settlement opportunities. It also makes operations harder because an underfunded or nonce-stuck EOA can keep causing failures until operators notice and fix it manually.
To reproduce (not tested manually)
origin/mainat commit754bb6a0a.submission_accounts.Expected behaviour
Before selecting or using an EOA, the driver should check simple health signals where possible:
If the selected EOA fails for an account-specific reason, the driver should skip it and try another eligible EOA while the settlement is still valid. Account-specific failures include:
The driver should not retry with another EOA for settlement-specific failures, such as:
The driver should also temporarily mark unhealthy EOAs as unavailable so they are not selected again immediately.
Screenshots/logs
Current behavior from code inspection on latest
origin/mainat commit754bb6a0a:Auxiliary EOAs are inserted into an
mpscchannel in config order:https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/competition/mod.rs#L100-L112
The driver always tries the direct solver EOA first. Delegated EOAs are only considered if the direct slot is busy:
https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/competition/mod.rs#L124-L147
The next delegated EOA is selected with
channel.recv(). There is no balance or nonce health check before selecting it:https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/competition/mod.rs#L149-L160
The selected submitter is used once for the settlement. If execution fails, the result is returned as
SubmissionError; there is no retry with another EOA:https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/competition/mod.rs#L898-L921
Mempools::execute()races configured mempools, but all attempts use the same selectedSubmissionMode:https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/mempools.rs#L64-L96
The selected signer is derived once from the prepared transaction and used for nonce lookup and submission:
https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/mempools.rs#L133-L170
https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/mempools.rs#L212-L220
send_transactionfailures are logged and returned as a generic submission error path:https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/infra/mempool/mod.rs#L145-L179
https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/mempools.rs#L633-L636
Delegated EOAs are returned to the channel after the guard is dropped, so an unhealthy EOA can become selectable again later: https://github.com/cowprotocol/services/blob/754bb6a0a/crates/driver/src/domain/competition/mod.rs#L213-L222
services version/commit hash and environment
Version / commit hash:
754bb6a0aAdditional context
The production runbook expects this kind of fallback behavior.
For underfunded or nonce-stuck auxiliary EOAs, the runbook expects:
The driver should be updated so the implementation matches that operational model.