Skip to content

fix(forge-multisig): remove pre-transfer executed=true write in execu…#518

Merged
Austinaminu2 merged 2 commits into
Austinaminu2:mainfrom
observerr411:fix/494-multisig-execute-double-write
Apr 27, 2026
Merged

fix(forge-multisig): remove pre-transfer executed=true write in execu…#518
Austinaminu2 merged 2 commits into
Austinaminu2:mainfrom
observerr411:fix/494-multisig-execute-double-write

Conversation

@observerr411
Copy link
Copy Markdown
Contributor

…te()

Closes #494

execute() was setting proposal.executed = true and writing to storage twice: once before the token transfer and once after. The pre-transfer write permanently marks the proposal as executed even if the transfer traps, making the proposal unretryable and locking funds forever.

Remove the first write. Keep only the write after the transfer succeeds, consistent with the existing comment 'Mark executed AFTER the transfer succeeds'.

Also fix a pre-existing nested function definition in the test module that caused a compile error (test_get_approval_count_tracks_lifecycle_ through_execution had a duplicate fn header inside its body).

The test test_execute_does_not_mark_executed_on_failed_transfer already covers the invariant: proposal.executed must remain false when the transfer fails due to InsufficientFunds.

Summary

[Provide a clear and concise summary of the changes made in this PR]

Related issue

[Link to the issue, e.g., #123]

Related Issue

[Link to the issue this PR addresses, e.g. Closes #123]

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Testing

Tests Performed

[Describe the tests you ran to verify your changes. Include:

  • Unit tests run
  • Integration tests performed
  • Manual testing steps
  • Any specific scenarios tested]

Test Results

[All tests should pass. Include any test output or screenshots if relevant]

Checklist

  • My code follows the project's style guidelines
  • I have run cargo fmt to format the code
  • I have run cargo clippy to lint the code
  • All new and existing tests pass locally
  • I have added necessary documentation (if applicable)
  • I have updated the CHANGELOG.md (if applicable)
  • I have labeled this PR appropriately (e.g., 'good first issue', 'documentation', 'bug')
  • I have requested review from the appropriate maintainers

Additional Notes

[Any additional context, screenshots, or information that reviewers should be aware of]

…te()

Closes Austinaminu2#494

execute() was setting proposal.executed = true and writing to storage
twice: once before the token transfer and once after. The pre-transfer
write permanently marks the proposal as executed even if the transfer
traps, making the proposal unretryable and locking funds forever.

Remove the first write. Keep only the write after the transfer succeeds,
consistent with the existing comment 'Mark executed AFTER the transfer
succeeds'.

Also fix a pre-existing nested function definition in the test module
that caused a compile error (test_get_approval_count_tracks_lifecycle_
through_execution had a duplicate fn header inside its body).

The test test_execute_does_not_mark_executed_on_failed_transfer already
covers the invariant: proposal.executed must remain false when the
transfer fails due to InsufficientFunds.
@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented Apr 26, 2026

@observerr411 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Austinaminu2 Austinaminu2 merged commit efba25d into Austinaminu2:main Apr 27, 2026
1 check failed
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.

forge-multisig execute() sets proposal.executed = true twice — first write before transfer is never cleaned up if transfer succeeds

2 participants