Repository navigation
fix(fund): assign multicall3 nonces up front to stop batches replacing each other - #1030
Merged
Merged
Conversation
…g each other fundWalletsWithMulticall3 sent every batch from its own goroutine with a nil nonce, so each goroutine asked the node for the pending nonce independently. Two batches that read the same value collided: the second broadcast was rejected with "replacement transaction underpriced" and its wallets were never funded, or, if its fee estimate happened to be higher, it silently replaced the first and the receipt wait blocked on a hash that would never be mined. Read the pending nonce once, hand each batch its own nonce, and keep the concurrent fan-out. Retry each send with backoff before treating its nonce as a gap. When a send still fails, confirm the transactions below the gap, then report which batches were not sent and that the higher-nonce transactions stay pending until the gap is filled. In ERC20 mode a single approval for the total amount now covers every batch instead of one approval per batch that each waited to be mined. Multicall3FundAccountsWithERC20Token no longer approves, and the new Multicall3ApproveERC20Token returns an error when the approval is mined but fails instead of returning nil. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
minhd-vu
approved these changes
Sep 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
polycli fundsends one multicall3 transaction per batch of wallets, each from its own goroutine. Every goroutine leftNoncenil, so each one asked the node for the pending nonce on its own. Two batches that read the same value collided: the second broadcast was rejected withreplacement transaction underpricedand its wallets were never funded. If the second batch's fee estimate happened to come out higher, it instead silently replaced the first, and the receipt wait blocked on a hash that would never be mined. A 10,000-wallet run lost three of 25 batches this way.Changes:
polycli fix-nonce-gap). Previously a single send failure returned before confirming anything.util.Multicall3FundAccountsWithERC20Tokenno longer approves; the newutil.Multicall3ApproveERC20Tokendoes, and it returns an error when the approval is mined but fails instead of returningnil.batch=N of=M nonce=... accounts=...instead of a wallet count that arrived out of order.Breaking: the signature of
util.Multicall3FundAccountsWithERC20Tokenchanged. Its only caller wascmd/fund.Jira / Linear Tickets
Testing
go build ./...,go vet ./..., shadow analyzer on changed packagesgo test -race ./cmd/fund/)--key-fileof 10,000 wallets (native token), confirming all 25 batches land and noreplacement transaction underpricederrors--token-address) confirming a single approval followed by the batch transfers🤖 Generated with Claude Code