To register, a user needs to provide a Merkle branch showing some index i, where either
i=0 and A[i]=0, ori > 0 and A[i] = 0 and A[i-1] != 0. The Merkle tree is updated so thatA[i]now equals the msg.sender’s address,
This seems to only allow 1 registration per block in practice. If both Bob and Alice try to update the same Merkle root for slot i, then one will fail.
To deposit or withdraw, a user needs to provide a Merkle branch showing some index i, where
A[i]equals the msg.sender’s address, along with the corresponding branch forB[i], and the amount they want to deposit or withdraw,D… The contract then updates the Merkle root so thatB[i] += D.
This also seems hard to achieve in practice, since users technically always need to know what the current root is in order to provide the proper path and the root changes with every transaction.
Note that anyone can be a relayer; there is no assumption of even an untrusted special “operator” existing. Because all the data needed to update the Merkle tree goes on chain, there are no data availability issues.
This also has the problem that having multiple relayers will lead to collisions and only one will succeed. This introduce a race condition to generate the proof, which can be fine, but now relayers might start to only include the highest fees to make sure they don’t lose the race, so higher cost for everyone.
I believe most of these concerns are addressed by having an operator or close set of operators and a deposit/withdraw queue.