Skip to content

Remove GAS_CAP to support smart contract wallet reward distribution#38

Open
daatsuka wants to merge 1 commit intolayer3xyz:mainfrom
daatsuka:prevent-reward-distribution-dos
Open

Remove GAS_CAP to support smart contract wallet reward distribution#38
daatsuka wants to merge 1 commit intolayer3xyz:mainfrom
daatsuka:prevent-reward-distribution-dos

Conversation

@daatsuka
Copy link
Copy Markdown

The native ETH payout path in Escrow.sol::withdrawNative (line 230) and the identical path in TaskEscrow.sol::_distributeNative (line 188) both forwarded a hardcoded GAS_CAP of 35,000 with the low-level .call{value: …, gas: GAS_CAP}(""). That cap is too tight for any smart-contract wallet whose receive() touches storage — a single cold SSTORE costs 20,000 gas, so a wallet doing even modest bookkeeping on receive blows the budget and the call reverts with Escrow__NativePayoutError. Because the contract treats that revert as fatal, legitimate claimants using multisigs or account-abstraction wallets are permanently locked out of their native rewards. Removing the gas: parameter lets the EVM forward all available gas (minus the 1/64 retention), which is the standard Solidity pattern for value transfers that must support arbitrary receivers.

The change itself is intentionally narrow: delete the GAS_CAP constant declaration, and drop the gas: GAS_CAP argument from both .call sites — nothing else in the contract logic changes, and the existing if (!rewardSuccess) revert guard still protects against actual transfer failures. On the test side, test/unit/Escrow.t.sol gains a GasHeavyReceiver helper contract whose receive() burns well over 35,000 gas via a storage-write loop, paired with three new test cases: a zero-rake withdrawal to the heavy receiver, a 5 % rake split verifying both receiver and treasury balances, and a 100 % rake edge case where the receiver gets zero but the transaction still completes without revert.

The design deliberately avoids a pull-based (withdrawal-pattern) refactor or a configurable gas limit — both would widen the surface area and require migration work on Factory, while the root cause is simply that the cap is unnecessary given the existing revert guard. I ran forge test locally against the full suite; all 26 tests pass (including the three new smart-contract-wallet scenarios), and the GasHeavyReceiver contract confirms the old 35k cap would have reverted whereas the uncapped call succeeds cleanly.

Closes #37

@daatsuka daatsuka requested a review from petersng as a code owner March 24, 2026 08:56
@petersng petersng requested a review from zarifpour March 24, 2026 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Native Reward Distribution DoS for Smart Contract Wallets

1 participant