Skip to content

feat: expose transaction_context::fee_payer and senders to Move#252

Merged
beer-1 merged 1 commit into
mainfrom
feat/tx-context-fee-payer
May 28, 2026
Merged

feat: expose transaction_context::fee_payer and senders to Move#252
beer-1 merged 1 commit into
mainfrom
feat/tx-context-fee-payer

Conversation

@beer-1
Copy link
Copy Markdown
Member

@beer-1 beer-1 commented May 27, 2026

Summary

Exposes two new natives in initia_std::transaction_context and minitia_std::transaction_context:

  • senders(): vector<address> — full sender vector of the current transaction.
  • fee_payer(): Option<address> — optional fee payer, plumbed from a new fee_payer field on types::Env.

Plumbing

  • Env gains fee_payer: Option<AccountAddress> (BCS-breaking; Go binding regenerated).
  • UserTransactionContext now carries the full senders vector and the optional fee_payer, populated for both Execute and Script payloads.
  • VM passes senders.clone() and env.fee_payer() into the context.
  • Two new gas params: transaction_context.senders.{base,per_address} and transaction_context.fee_payer.base.
  • Test-only setters (set_senders_internal, set_fee_payer_internal) behind #[cfg(feature = "testing")].

Compatibility

  • Breaking: Env BCS layout changes — Go and Rust must ship together.
  • Move stdlib: additive only; existing on-chain modules unaffected.
  • Script execution: UserTransactionContext is now populated for scripts too, but entry_function_payload() still returns None — observable Move behavior unchanged.

Test plan

  • Move unit tests (Initia stdlib): 9/9 pass — set/get, default-empty, default-none, abort-on-no-context.
  • Move unit tests (Minitia stdlib): 9/9 pass — same coverage.
  • Rust e2e test_fee_payer_flows_from_env_to_move: publishes probe module, sets fee_payer on Env, asserts Move reads back the same address.
  • Rust e2e test_senders_flow_from_env_to_move: single-sender + two-sender cases via store_senders / store_senders_two.
  • Go TestExecuteEntryFunctionWithFeePayer: publishes TxContextTests, calls store_fee_payer, reads back via read_stored_fee_payer view function.
  • Go TestExecuteEntryFunctionSenders: same pattern for store_senders / read_stored_senders.
  • cargo test --workspace: full suite passes (158 tests).
  • go test ./...: all packages pass.
  • cargo clippy --all-targets -- -D warnings: clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Transactions now support an optional fee payer account separate from the transaction sender
    • Multi-signer transactions with multiple participant addresses are now supported
    • New transaction context APIs allow querying the fee payer and senders involved in a transaction

Add two new natives in `initia_std::transaction_context` and
`minitia_std::transaction_context`:

- `senders(): vector<address>` — full sender vector of the current
  transaction (previously only senders[0] was retained anywhere).
- `fee_payer(): Option<address>` — optional fee payer, plumbed from a
  new `fee_payer` field on `types::Env` (BCS-breaking, Go binding
  regenerated).

Plumbing:
- `Env` gains `fee_payer: Option<AccountAddress>` and a getter.
- `UserTransactionContext` now carries the full `senders` vector and the
  optional fee_payer, populated for both Execute and Script payloads.
- VM passes `senders.clone()` and `env.fee_payer()` into the context.
- Two new gas params: `transaction_context.senders.{base,per_address}`
  and `transaction_context.fee_payer.base`.
- Test-only setters (`set_senders_internal`, `set_fee_payer_internal`)
  behind `#[cfg(feature = "testing")]` for Move unit tests, with
  `ensure_user_transaction_context` initializing an empty context when
  needed.

Tests:
- Move unit tests in both stdlibs (9 each): set/get, default, abort-on-
  no-context via `#[expected_failure(abort_code = 393216)]`.
- Rust e2e (`test_fee_payer_flows_from_env_to_move`,
  `test_senders_flow_from_env_to_move`) — publishes a probe module,
  sets fee_payer / senders on Env, reads the stored resource back.
- Go (`TestExecuteEntryFunctionWithFeePayer`,
  `TestExecuteEntryFunctionSenders`) — extends `publishModuleBundle`
  with TxContextTests.mv, calls entry functions, verifies via view
  function reads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@beer-1 beer-1 requested a review from a team as a code owner May 27, 2026 08:23
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

Walkthrough

This PR threads multi-sender and optional fee payer support throughout the Move VM stack: updating core type contracts (Env, UserTransactionContext) to carry senders as a vector and an optional fee payer; refactoring VM execution to pass the full sender list and fee payer; implementing native accessors with proportional gas costs; exposing public Move APIs for reading transaction context; and adding comprehensive e2e and integration tests that verify the data flows correctly from the execution environment into Move code.

Changes

Transaction Context Multi-Sender and Fee Payer

Layer / File(s) Summary
Type contracts and VM execution
crates/types/src/env.rs, crates/types/src/user_transaction_context.rs, crates/vm/src/initia_vm.rs, types/bcs.go
Env gains optional fee_payer field with accessor. UserTransactionContext switches from single sender: AccountAddress to senders: Vec<AccountAddress> and adds fee_payer: Option<AccountAddress>. VM execute_script_or_entry_function refactored to extract entry-function payload once and pass full sender vector plus fee payer to UserTransactionContext::new. BCS serialization adds FeePayer field and option helpers for AccountAddress.
Native implementations and gas costs
crates/natives/src/transaction_context.rs, crates/gas/src/initia_stdlib.rs
New production natives senders() and fee_payer_internal() read from UserTransactionContext with gas costs proportional to sender count (base + per-address) and base cost respectively. Test-only natives set_senders_internal and set_fee_payer_internal allow mutation of context state during testing. All natives registered in make_all().
Move stdlib transaction context APIs
precompile/modules/initia_stdlib/sources/transaction_context.move, precompile/modules/minitia_stdlib/sources/transaction_context.move
Both stdlib modules gain public senders(): vector<address> (native) and fee_payer(): Option<address> (public wrapper) with abort documentation. Test-only helpers set_senders and set_fee_payer allow test code to configure context. Extended test suites verify success paths (empty senders, None/Some fee payer) and abort paths (calling outside transaction context).
Rust e2e test harness
crates/e2e-move-tests/src/harness.rs
MoveHarness gains public fee_payer: Option<AccountAddress> field initialized to None and public set_fee_payer() method. All execution paths (initialize, run_view_function_with_state, run_authenticate, run_message, run_message_with_state) updated to pass self.fee_payer into Env::new() instead of hardcoded None.
Rust e2e transaction context tests
crates/e2e-move-tests/src/tests/mod.rs, crates/e2e-move-tests/src/tests/transaction_context.data/pack/Move.toml, crates/e2e-move-tests/src/tests/transaction_context.data/pack/sources/TxContextTests.move, crates/e2e-move-tests/src/tests/transaction_context.rs
New transaction_context test module with Move package manifest, test module TxContextTests that stores fee payer and senders observations to resources, and Rust harness tests verifying fee payer flows (unset and set to 0xCAFE) and multi-sender flows (single and two-signer entry functions).
Go integration tests
precompile/modules/tests/sources/TxContextTests.move, lib_test.go
New TxContextTests Move module with resource stores and view functions to read stored fee payer and senders. publishModuleBundle extended to include the new module. Two integration tests: TestExecuteEntryFunctionWithFeePayer verifies fee payer round-trips, and TestExecuteEntryFunctionSenders verifies senders list round-trips.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 Hops through layers of senders flow,
Fee payers dance in Move's tableau,
Context threads from VM so bright,
Multi-signers spring to light,
Testing harnesses catch the sight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: expose transaction_context::fee_payer and senders to Move' directly and concisely describes the main objective of the changeset, which is exposing two new transaction context functions to Move.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 feat/tx-context-fee-payer

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
lib_test.go (1)

702-754: ⚡ Quick win

Strengthen senders coverage with a multi-sender transaction.

This test currently validates only a single sender, so it won’t catch regressions that truncate or reorder additional senders.

Proposed test adjustment
 	testAccount, err := types.NewAccountAddress("0x2")
 	require.NoError(t, err)
 	sender, err := types.NewAccountAddress("0x42")
 	require.NoError(t, err)
+	sender2, err := types.NewAccountAddress("0x43")
+	require.NoError(t, err)
@@
-		[]types.AccountAddress{sender},
+		[]types.AccountAddress{sender, sender2},
@@
-	// vector<address> with one element serialized as JSON is ["0x42"].
-	require.Equal(t, fmt.Sprintf("[\"%s\"]", sender.String()), viewRes.Ret)
+	require.Equal(t, fmt.Sprintf("[\"%s\",\"%s\"]", sender.String(), sender2.String()), viewRes.Ret)
 }
🤖 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 `@lib_test.go` around lines 702 - 754, Change the test to exercise multiple
senders instead of only one: when calling vm.ExecuteEntryFunction use a sender
slice with multiple distinct addresses (e.g., create extra
types.NewAccountAddress values) so TxContextTests.store_senders is invoked with
a multi-sender transaction, then call vm.ExecuteViewFunction on
TxContextTests.read_stored_senders with the appropriate JSON-serialized
argument(s) and assert viewRes.Ret contains all senders in the correct order
(not just a single-element vector). Update the variables around
ExecuteEntryFunction/ExecuteViewFunction and the final require.Equal assertion
to reflect the expected JSON array of addresses so the test will catch
truncation or reordering regressions.
🤖 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.

Nitpick comments:
In `@lib_test.go`:
- Around line 702-754: Change the test to exercise multiple senders instead of
only one: when calling vm.ExecuteEntryFunction use a sender slice with multiple
distinct addresses (e.g., create extra types.NewAccountAddress values) so
TxContextTests.store_senders is invoked with a multi-sender transaction, then
call vm.ExecuteViewFunction on TxContextTests.read_stored_senders with the
appropriate JSON-serialized argument(s) and assert viewRes.Ret contains all
senders in the correct order (not just a single-element vector). Update the
variables around ExecuteEntryFunction/ExecuteViewFunction and the final
require.Equal assertion to reflect the expected JSON array of addresses so the
test will catch truncation or reordering regressions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e041fccf-2833-4635-afae-d56507f8867b

📥 Commits

Reviewing files that changed from the base of the PR and between 8fb2810 and 8df3d69.

📒 Files selected for processing (17)
  • crates/e2e-move-tests/src/harness.rs
  • crates/e2e-move-tests/src/tests/mod.rs
  • crates/e2e-move-tests/src/tests/transaction_context.data/pack/Move.toml
  • crates/e2e-move-tests/src/tests/transaction_context.data/pack/sources/TxContextTests.move
  • crates/e2e-move-tests/src/tests/transaction_context.rs
  • crates/gas/src/initia_stdlib.rs
  • crates/natives/src/transaction_context.rs
  • crates/types/src/env.rs
  • crates/types/src/user_transaction_context.rs
  • crates/vm/src/initia_vm.rs
  • lib_test.go
  • precompile/binaries/minlib/transaction_context.mv
  • precompile/binaries/stdlib/transaction_context.mv
  • precompile/modules/initia_stdlib/sources/transaction_context.move
  • precompile/modules/minitia_stdlib/sources/transaction_context.move
  • precompile/modules/tests/sources/TxContextTests.move
  • types/bcs.go

Copy link
Copy Markdown
Contributor

@traviolus traviolus left a comment

Choose a reason for hiding this comment

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

LGTM

@beer-1 beer-1 merged commit f728f01 into main May 28, 2026
7 checks passed
@beer-1 beer-1 deleted the feat/tx-context-fee-payer branch May 28, 2026 01:54
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.

2 participants