Skip to content

[DRAFT] fix: prevent BREAD from being credited to the token contract address - #35

Draft
bagelface wants to merge 1 commit into
mainfrom
fix/prevent-transfers-to-token-contract
Draft

[DRAFT] fix: prevent BREAD from being credited to the token contract address#35
bagelface wants to merge 1 commit into
mainfrom
fix/prevent-transfers-to-token-contract

Conversation

@bagelface

Copy link
Copy Markdown

Closes #34.

What changed

BREAD can no longer be credited to the token contract's own address. The check lives in _update, so it covers every balance-changing path in one place:

function _update(address from, address to, uint256 value) internal override {
    if (to == address(this)) revert InvalidRecipient();
    super._update(from, to, value);
}

transfer, transferFrom, both mint overloads and claimYield now revert with InvalidRecipient() when the recipient is the token contract. A transfer-only check would have left the mint paths open, which is why the guard sits in _update rather than in the two public transfer functions.

Notes on the issue as filed

Two corrections worth recording:

Tokens sent this way were recoverable, not lost. rescueToken(address(bread), amount) already worked for them — tok != sexyDai passes the guard and the contract calls its own transfer. So this was a low-severity UX and trust problem (owner has to notice, and the funds land at the owner rather than the sender), not permanent loss. Nothing is currently stranded either: the deployed token holds 0 BREAD at its own address. This change is preventative.

There was also a quieter side effect: the existing transfer override self-delegated the recipient, so a stranded balance also parked voting power on an address that can never vote.

Rejecting native xDAI is deliberately not done here. BREAD sits behind EIP173ProxyWithReceive, whose receive() accepts xDAI and never delegatecalls the implementation — a receive()/fallback() added to Bread.sol would be dead code that reads as protection while changing nothing. It also cannot be done at all without redeploying the proxy, which means a new token address and a holder migration.

More importantly, a blanket ETH rejection would break redemptions: burn() is paid out by wxDai.withdraw() sending xDAI to the contract with empty calldata. test_burn_receives_native_after_recipient_check pins that behaviour so it can't be regressed later. xDAI sent directly to the token contract therefore stays put; a sweep function can be added in a later upgrade if it's ever needed.

Tests

19/19 pass against a Gnosis fork (14 pre-existing, no regressions). Five new tests cover each credit path rejecting, plus the burn/native-receive invariant.

forge test --fork-url "https://rpc.gnosischain.com"

Deploying

Needs a new implementation plus upgradeTo from proxy admin 0x918dEf5d593F46735f74F9E2B280Fe51AF3A99aD. No new state variables, so storage layout is unchanged and the upgrade is layout-safe.

Tradeoffs

  • Roughly +100 gas on every transfer, mint and burn (measured: 313,300 -> 313,491 across a mint+transferFrom pair). A permanent cost for a check that only fires on user error.
  • Guarding _update is broader than a strict ERC20 reading, which says transfers to any non-zero address should succeed. Any integration that deliberately sends BREAD to the token contract would now revert; none was found, and the yield distribution flow does not do this. Narrowing to transfer/transferFrom would be more conservative but would leave the mint paths open.
  • Treating a send to the contract as a redemption instead of a revert was considered and rejected. It handles the direct case nicely, but a contract forwarding someone else's BREAD to a caller-specified recipient would burn its own balance and keep the xDAI, so the end user loses funds in a case where a revert loses nothing.

@bagelface
bagelface marked this pull request as draft August 7, 2026 13:05
@bagelface bagelface changed the title fix: prevent BREAD from being credited to the token contract address [DRAFT] fix: prevent BREAD from being credited to the token contract address Aug 7, 2026
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.

Prevent users from sending Bread tokens to the token contract address (address(this))

1 participant