Skip to content

Remove tx.origin from drop execution#55

Merged
punk6529 merged 3 commits into
mainfrom
codex/remove-tx-origin-drop-execution
Jun 10, 2026
Merged

Remove tx.origin from drop execution#55
punk6529 merged 3 commits into
mainfrom
codex/remove-tx-origin-drop-execution

Conversation

@punk6529

@punk6529 punk6529 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Removes executable tx.origin usage from StreamDrops drop execution.
  • Adds an explicit fixed-price recipient parameter and stores that recipient as the fixed-price execution address.
  • Keeps auction _recipient reserved as address(0), rejects non-zero auction recipients, rejects zero posters, and stores the poster as the current no-bid execution fallback so settlement does not target zero.
  • Updates characterization/integration tests, admin selector coverage, roadmap/state docs, ADR references, and the Slither baseline for the new legacy API.

Closes #18.

Notes

This intentionally does not implement the full EIP-712 authorization schema, signature replay model, or field-substitution guarantees. Those remain assigned to P0-AUTH-002 / issue #10.

Validation

  • forge test --match-contract StreamDropsCharacterizationTest -vvv (9 tests)
  • forge test --match-contract StreamDropsIntegrationCharacterizationTest -vvv (10 tests)
  • make check (24 tests)
  • powershell -ExecutionPolicy Bypass -File scripts\check.ps1 (24 tests)
  • forge fmt --check for formatted touched Solidity files, preserving existing provider-interface style to avoid unrelated churn
  • git diff --check
  • rg -n "tx\.origin" smart-contracts returned no matches
  • stale signature/name greps for the old legacy drop API returned no matches

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, push a new commit or reopen this pull request to trigger a review.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Removes tx.origin from drop execution by adding explicit _recipient to mintDrop and retrieveMessageAndDropID; updates ADR, roadmap, ops state, StreamDrops logic, test helpers, characterization/integration tests, and Slither/selector/documentation baselines to validate recipient-based execution and drop-id construction.

Changes

P0-AUTH-001: Remove tx.origin and Add Explicit Recipient

Layer / File(s) Summary
Design requirements: ADR, roadmap, and blockers
docs/adr/0001-drop-authorization.md, docs/known-blockers.md, ops/ROADMAP.md
Rewrites ADR problem/baseline wording, tightens migration constraint for legacy mintDrop path, and updates roadmap/known-blockers to require EIP-712-signed recipient/payer/deadline and replay-protection fields.
Operational state and PR queue tracking
ops/AUTONOMOUS_RUN.md
Advances durable ops state: records PR #54 merge, opens PR #55 (P0-AUTH-001) worklog, adds validation checklist (including grep/no-tx.origin), and appends decision-log entries.
StreamDrops: recipient parameter and drop ID hashing
smart-contracts/StreamDrops.sol
Changes mintDrop signature to include _recipient; includes recipient in dropId computation; enforces non-zero recipient for fixed-price, zero recipient for auctions; sets executionAddress from recipient/poster; updates retrieval helper signature.
Test infrastructure: deployment and cheatcode helpers
test/helpers/CharacterizationTestBase.sol, test/helpers/StreamFixture.sol
Adds Vm.warp(uint256) cheatcode and deployStreamWithSigner helper; deployStream delegates to the helper using address(this) as default signer.
Characterization & integration tests: recipient-based execution
test/StreamDropsCharacterization.t.sol, test/StreamDropsIntegrationCharacterization.t.sol
Adds RECIPIENT test constant; updates all fixed-price and auction tests to pass explicit recipient or address(0); replaces tx.origin assertions with explicit recipient ownership/execution checks; adds negative tests and AuthorizedDropExecutor for contract-signer flows.
Documentation, selector & Slither baseline updates
test/README.md, test/StreamAdmins.t.sol, smart-contracts/IArrngController.sol, ops/SLITHER_BASELINE.md
Expands test README framing; updates function selector computation for new mintDrop signature; changes tx.origin wording to “transaction origin” in interface docs; refreshes Slither baseline entries to match new signatures and locations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Poem

A rabbit hops through packed encodings,
Swapping origin ghosts for explicit signings,
Recipient named, the mint now sings,
Drop IDs tied to clearer things. 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Remove tx.origin from drop execution' directly and clearly describes the main change in the changeset, which removes tx.origin from StreamDrops drop execution logic and introduces explicit recipient parameters.
Linked Issues check ✅ Passed All objectives from issue #18 are met: explicit recipient parameter added, fixed-price execution now uses recipient instead of tx.origin, auction recipient reserved as address(0), zero recipient rejected, characterization tests updated, and no tx.origin remains in protocol source.
Out of Scope Changes check ✅ Passed All changes are directly related to removing tx.origin and implementing explicit recipient handling per issue #18; documentation and test updates appropriately scope themselves to P0-AUTH-001 and defer EIP-712 work to P0-AUTH-002.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/remove-tx-origin-drop-execution

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor Author

@claude please review this PR.

Focus areas:

  • whether the explicit-recipient legacy API cleanly removes executable tx.origin usage without overclaiming EIP-712 completion;
  • fixed-price recipient/execution semantics;
  • auction recipient reservation as address(0), non-zero auction recipient rejection, and poster fallback for no-bid settlement;
  • test/docs traceability for P0-AUTH-001 vs the remaining P0-AUTH-002 work.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ops/AUTONOMOUS_RUN.md`:
- Around line 992-997: Update the section heading "PR TBD: Remove `tx.origin`
from drop execution (Queue Item 14)" to include the actual PR number 55 instead
of "TBD" (e.g., "PR `#55`: Remove `tx.origin` from drop execution (Queue Item
14)"); locate the header text in AUTONOMOUS_RUN.md that currently contains the
branch name `codex/remove-tx-origin-drop-execution` or the pull request URL
`https://github.com/6529-Collections/6529Stream/pull/55` and replace "PR TBD"
with the concrete "PR `#55`".

In `@smart-contracts/StreamDrops.sol`:
- Around line 81-89: The mintDrop function currently allows a zero-address
_poster which can cause ETH to be sent to address(0) and break auction fallback
logic; add a require/assert to validate _poster is not address(0) at the start
of mintDrop and apply the same non-zero check to the other related minting
function(s) in this file (the second mintDrop overload/variant around lines
108-137) so any incoming _poster argument is rejected when zero before
proceeding with price/auction logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a7f72c8f-c8ce-4da0-82b4-ed5d4c8e14f4

📥 Commits

Reviewing files that changed from the base of the PR and between d06b48f and 9dbcc5e.

📒 Files selected for processing (13)
  • docs/adr/0001-drop-authorization.md
  • docs/known-blockers.md
  • ops/AUTONOMOUS_RUN.md
  • ops/ROADMAP.md
  • ops/SLITHER_BASELINE.md
  • smart-contracts/IArrngController.sol
  • smart-contracts/StreamDrops.sol
  • test/README.md
  • test/StreamAdmins.t.sol
  • test/StreamDropsCharacterization.t.sol
  • test/StreamDropsIntegrationCharacterization.t.sol
  • test/helpers/CharacterizationTestBase.sol
  • test/helpers/StreamFixture.sol

Comment thread ops/AUTONOMOUS_RUN.md Outdated
Comment thread smart-contracts/StreamDrops.sol

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
smart-contracts/StreamDrops.sol (1)

132-137: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject ETH on the auction path.

This branch still accepts msg.value, but it never forwards or refunds it. Any ETH sent with an auction mint stays trapped in StreamDrops, and this file does not expose a withdrawal path.

Suggested fix
         } else if (_opt == 2) {
+            require(msg.value == 0, "Auction value");
             require(recipient == address(0), "Auction recipient");
             tokenid = minterContract.mintAndAuction(payOutAddress, tokData, 0, colID, _endDate);
             posterAuctionAddress[tokenid] = poster;
             auctionPrice[tokenid] = _price;
             executionAddress = poster;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@smart-contracts/StreamDrops.sol` around lines 132 - 137, The auction branch
(_opt == 2) currently accepts msg.value but never forwards or refunds it,
trapping ETH in StreamDrops; update the branch handling in the minting function
to reject any ETH by adding a require(msg.value == 0, "Do not send ETH for
auction") at the start of the _opt == 2 branch (near the call to
minterContract.mintAndAuction) so no ETH can be sent accidentally; reference
symbols: StreamDrops minting function branch for _opt == 2,
minterContract.mintAndAuction, posterAuctionAddress, auctionPrice,
executionAddress.
🧹 Nitpick comments (1)
smart-contracts/StreamDrops.sol (1)

91-105: ⚡ Quick win

Deduplicate the drop payload encoding.

The auth payload is assembled twice by hand. These paths need to stay byte-for-byte identical, so a later field change can silently break signing if only one side gets updated.

Refactor sketch
+    function _buildDropMessage(
+        address _poster,
+        address _recipient,
+        string memory _tokenData,
+        uint256 _collectionID,
+        uint256 _opt,
+        uint256 _price,
+        uint256 _endDate
+    ) internal pure returns (string memory) {
+        return string(
+            abi.encodePacked(
+                Strings.toHexString(uint256(uint160(_poster)), 20),
+                Strings.toHexString(uint256(uint160(_recipient)), 20),
+                _tokenData,
+                _collectionID.toString(),
+                _opt.toString(),
+                _price.toString(),
+                _endDate.toString()
+            )
+        );
+    }
+
     function mintDrop(
         address _poster,
         address _recipient,
         string memory _tokenData,
         uint256 _collectionID,
@@
     ) public payable authorized {
         require(_poster != address(0), "Zero poster");
-        bytes32 dropId = keccak256(
-            abi.encodePacked(
-                string(
-                    abi.encodePacked(
-                        Strings.toHexString(uint256(uint160(_poster)), 20),
-                        Strings.toHexString(uint256(uint160(_recipient)), 20),
-                        _tokenData,
-                        _collectionID.toString(),
-                        _opt.toString(),
-                        _price.toString(),
-                        _endDate.toString()
-                    )
-                )
-            )
-        );
+        string memory message = _buildDropMessage(
+            _poster,
+            _recipient,
+            _tokenData,
+            _collectionID,
+            _opt,
+            _price,
+            _endDate
+        );
+        bytes32 dropId = keccak256(abi.encodePacked(message));
@@
     ) public pure returns (string memory, bytes32) {
-        string memory message = string(
-            abi.encodePacked(
-                Strings.toHexString(uint256(uint160(_poster)), 20),
-                Strings.toHexString(uint256(uint160(_recipient)), 20),
-                _tokenData,
-                _collectionID.toString(),
-                _opt.toString(),
-                _price.toString(),
-                _endDate.toString()
-            )
-        );
+        string memory message = _buildDropMessage(
+            _poster,
+            _recipient,
+            _tokenData,
+            _collectionID,
+            _opt,
+            _price,
+            _endDate
+        );
         bytes32 hashedMessage = keccak256(abi.encodePacked(message));
         return (message, hashedMessage);
     }

Also applies to: 236-257

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@smart-contracts/StreamDrops.sol` around lines 91 - 105, The drop payload
encoding is duplicated (used to compute dropId and later for auth) which risks
mismatches; create a single helper (e.g., buildDropPayload or encodeDropPayload)
that takes _poster, _recipient, _tokenData, _collectionID, _opt, _price,
_endDate and returns the exact bytes used for signing (using abi.encodePacked
with the same string/hex conversions), then replace both the
keccak256(abi.encodePacked(...)) call that computes dropId and the other auth
payload assembly (lines ~236-257) to call that helper and reuse its result so
both sides remain byte-identical. Ensure the helper is internal/pure and used in
both places.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@smart-contracts/StreamDrops.sol`:
- Around line 132-137: The auction branch (_opt == 2) currently accepts
msg.value but never forwards or refunds it, trapping ETH in StreamDrops; update
the branch handling in the minting function to reject any ETH by adding a
require(msg.value == 0, "Do not send ETH for auction") at the start of the _opt
== 2 branch (near the call to minterContract.mintAndAuction) so no ETH can be
sent accidentally; reference symbols: StreamDrops minting function branch for
_opt == 2, minterContract.mintAndAuction, posterAuctionAddress, auctionPrice,
executionAddress.

---

Nitpick comments:
In `@smart-contracts/StreamDrops.sol`:
- Around line 91-105: The drop payload encoding is duplicated (used to compute
dropId and later for auth) which risks mismatches; create a single helper (e.g.,
buildDropPayload or encodeDropPayload) that takes _poster, _recipient,
_tokenData, _collectionID, _opt, _price, _endDate and returns the exact bytes
used for signing (using abi.encodePacked with the same string/hex conversions),
then replace both the keccak256(abi.encodePacked(...)) call that computes dropId
and the other auth payload assembly (lines ~236-257) to call that helper and
reuse its result so both sides remain byte-identical. Ensure the helper is
internal/pure and used in both places.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f86c270e-a168-4701-a2c8-e92adcc92bb1

📥 Commits

Reviewing files that changed from the base of the PR and between 9dbcc5e and 1e09d7a.

📒 Files selected for processing (3)
  • ops/AUTONOMOUS_RUN.md
  • smart-contracts/StreamDrops.sol
  • test/StreamDropsCharacterization.t.sol
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/StreamDropsCharacterization.t.sol

@punk6529 punk6529 merged commit f7e34ee into main Jun 10, 2026
2 checks passed
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.

[P0-AUTH-001] Remove tx.origin from drop execution

1 participant