Skip to content

chore: add internal transfer fee#1245

Merged
MicBun merged 13 commits into
mainfrom
chore/transfer-fee
Nov 3, 2025
Merged

chore: add internal transfer fee#1245
MicBun merged 13 commits into
mainfrom
chore/transfer-fee

Conversation

@williamrusdyputra
Copy link
Copy Markdown
Contributor

@williamrusdyputra williamrusdyputra commented Nov 3, 2025

resolves: https://github.com/trufnetwork/truf-network/issues/1314

Summary by CodeRabbit

  • New Features

    • Bridge transfers now include a fixed 1 TRUF fee per transaction; senders must have amount + fee.
    • Collected fees are forwarded to the configured leader account before completing the transfer.
    • Recipients receive only the transfer amount; fees are not forwarded to recipients.
    • Error messages standardized to indicate insufficient balance and the required 1 TRUF fee.
  • Tests

    • Added coverage for fee scenarios: exact balance, insufficient balance, and multiple sequential transfers.

@williamrusdyputra williamrusdyputra self-assigned this Nov 3, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 3, 2025

Warning

Rate limit exceeded

@williamrusdyputra has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 45 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 87519c9 and 76dd196.

📒 Files selected for processing (3)
  • internal/migrations/erc20-bridge/002-public-transfer-actions.sql (2 hunks)
  • tests/extensions/erc20/common_test.go (3 hunks)
  • tests/extensions/erc20/erc20_bridge_transfer_actions_test.go (5 hunks)

Walkthrough

Adds a fixed 1 TRUF on‑chain fee to internal transfer actions (sepolia_transfer, ethereum_transfer): checks caller balance >= amount + fee, transfers the fee to the leader before the main transfer, and extends tests and test setup to exercise fee scenarios and leader proposer presence.

Changes

Cohort / File(s) Summary
Fee Collection Logic
internal/migrations/erc20-bridge/002-public-transfer-actions.sql
Adds a fixed 1 TRUF fee to sepolia_transfer and ethereum_transfer: reads caller balance from bridge, enforces balance >= amount + fee, transfers fee to leader_sender before executing the existing transfer.
Test Infrastructure
tests/extensions/erc20/common_test.go
Adds TestUserC and TestUserD. Updates EngineContext: sets BlockContext.Proposer using a generated leader public key and sets Authenticator to EthPersonalSignAuth, enabling leader-based fee collection in tests.
Fee Transfer Tests
tests/extensions/erc20/erc20_bridge_transfer_actions_test.go
Adds TestTransferActionFeeExactBalance, TestTransferActionFeeInsufficientBalance, TestTransferActionFeeMultipleTransfers. Updates TestSepoliaTransferActions and assertions to account for 1 TRUF fee per transfer and new insufficient-balance messages.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Bridge
    participant Leader
    participant Recipient
    Note right of Bridge: sepolia_transfer / ethereum_transfer (updated)

    User->>Bridge: sepolia_transfer(amount)
    activate Bridge
    Bridge->>Bridge: Read caller balance (balance)
    alt balance >= amount + 1 TRUF
        Bridge->>Leader: Transfer 1 TRUF fee (leader_sender)
        Bridge->>Bridge: Deduct amount from caller balance
        Bridge->>Recipient: Credit amount
        Note right of Bridge: Original transfer logic continues
    else insufficient
        Bridge-->>User: Error: Insufficient balance (requires extra 1 TRUF fee)
    end
    deactivate Bridge
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review precise numeric constants and arithmetic for 1 TRUF (1e18) in SQL migration.
  • Verify ordering: fee transfer occurs before main transfer.
  • Check tests for deterministic leader proposer setup and potential flakiness.

Possibly related PRs

Suggested labels

type: feat

Suggested reviewers

  • MicBun
  • outerlook

Poem

🐰 Hoppity-hop, one TRUF to pay,

Fee to the leader, the ledger will sway.
Exact or short, tests watch the hop,
Balances shift — then the carrots stop. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "chore: add internal transfer fee" accurately reflects the main change in the changeset. The primary modification is adding a 1 TRUF fee mechanism to the sepolia_transfer and ethereum_transfer actions, with the fee transferred to the leader before executing the main transfer. The title is concise, clear, and directly captures the core objective without unnecessary noise or vague terminology.
Linked Issues Check ✅ Passed The code changes comprehensively address all acceptance criteria from issue #1314. The PR implements fee collection in both sepolia_transfer and ethereum_transfer actions [#1314], enforces balance validation for transfer_amount + 1 TRUF fee [#1314], transfers the fee to leader_sender before executing the main transfer [#1314], and includes test scenarios that verify error messaging for insufficient balance [#1314]. The existing transfer logic remains intact after fee collection, and the new tests (TestTransferActionFeeExactBalance, TestTransferActionFeeInsufficientBalance, TestTransferActionFeeMultipleTransfers) provide comprehensive coverage of fee scenarios [#1314].
Out of Scope Changes Check ✅ Passed All changes in the pull request are directly scoped to the fee implementation requirements outlined in issue #1314. The SQL migration adds the fee mechanism to transfer actions, the test infrastructure changes (TestUserC, TestUserD, EngineContext updates with Proposer and Authenticator) are necessary supporting modifications to enable leader key generation and fee collection testing, and the new test functions directly validate the fee behavior across multiple scenarios. No unrelated functionality, "nice-to-have" features, or extraneous modifications were introduced.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@williamrusdyputra williamrusdyputra changed the title Chore/transfer fee chore: add internal transfer fee Nov 3, 2025
@williamrusdyputra williamrusdyputra marked this pull request as ready for review November 3, 2025 08:18
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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
internal/migrations/erc20-bridge/002-public-transfer-actions.sql (1)

16-26: Guard balance reads against NULL and compare with total requirement

sepolia_bridge.balance(@caller)/ethereum_bridge.balance(@caller) can come back NULL for first-time callers, which makes the subtraction/comparison evaluate to NULL and skip the friendly error branch. Coalescing to 0 and comparing against amount + fee keeps the custom message and avoids depending on downstream transfer failures. Please wrap both balance reads in COALESCE and compare directly against the summed requirement.

-  $caller_balance := sepolia_bridge.balance(@caller);
-  IF ($caller_balance - $amount::NUMERIC(78, 0)) < $fee {
+  $caller_balance := COALESCE(sepolia_bridge.balance(@caller), 0::NUMERIC(78, 0));
+  IF ($caller_balance < ($amount::NUMERIC(78, 0) + $fee)) {
     ERROR('Insufficient balance for transfer. Requires an extra 1 TRUF fee on top of the transfer amount');
   }
@@
-  $caller_balance := ethereum_bridge.balance(@caller);
-  IF ($caller_balance - $amount::NUMERIC(78, 0)) < $fee {
+  $caller_balance := COALESCE(ethereum_bridge.balance(@caller), 0::NUMERIC(78, 0));
+  IF ($caller_balance < ($amount::NUMERIC(78, 0) + $fee)) {
     ERROR('Insufficient balance for transfer. Requires an extra 1 TRUF fee on top of the transfer amount');
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87519c9 and 1956337.

📒 Files selected for processing (3)
  • internal/migrations/erc20-bridge/002-public-transfer-actions.sql (2 hunks)
  • tests/extensions/erc20/common_test.go (3 hunks)
  • tests/extensions/erc20/erc20_bridge_transfer_actions_test.go (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-12T01:19:04.545Z
Learnt from: outerlook
Repo: trufnetwork/node PR: 1147
File: tests/extensions/erc20/erc20_bridge_actions_smoke_test.go:40-47
Timestamp: 2025-09-12T01:19:04.545Z
Learning: In ERC20 bridge tests, the maintainer (outerlook) prefers fail-fast behavior through panics when schema changes occur. Direct indexing and type assertions in test row handlers should be maintained to immediately catch unexpected schema changes, rather than using graceful error handling.

Applied to files:

  • tests/extensions/erc20/erc20_bridge_transfer_actions_test.go
📚 Learning: 2025-10-23T07:00:26.796Z
Learnt from: williamrusdyputra
Repo: trufnetwork/node PR: 1228
File: internal/migrations/erc20-bridge/000-extension.sql:16-19
Timestamp: 2025-10-23T07:00:26.796Z
Learning: In internal/migrations/erc20-bridge/000-extension.sql, the active sepolia_bridge configuration is intentionally for test environments only and does not include the distribution_period parameter. The commented sepolia_bridge and ethereum_bridge blocks with distribution_period are production configurations.

Applied to files:

  • internal/migrations/erc20-bridge/002-public-transfer-actions.sql
🧬 Code graph analysis (1)
tests/extensions/erc20/erc20_bridge_transfer_actions_test.go (2)
tests/streams/utils/erc20/inject.go (1)
  • InjectERC20Transfer (24-85)
tests/extensions/erc20/common_test.go (10)
  • TestChain (20-20)
  • TestERC20 (24-24)
  • TestUserA (25-25)
  • TestUserB (26-26)
  • TestAmount1 (29-29)
  • TestUserC (27-27)
  • TestAmount2 (30-30)
  • TestEscrowA (22-22)
  • TestExtensionAlias (21-21)
  • TestUserD (28-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: acceptance-test
  • GitHub Check: lint
🔇 Additional comments (2)
tests/extensions/erc20/common_test.go (1)

65-82: Leader bootstrap change looks good

Generating a provisional proposer and wiring EthPersonalSignAuth keeps @leader_sender populated for the fee transfer path without touching the rest of the harness.

tests/extensions/erc20/erc20_bridge_transfer_actions_test.go (1)

250-354: Thorough coverage on the new fee scenarios

Really appreciate the trio of exact/insufficient/multiple transfer cases—these lock in the sender-fee semantics and the error string.

@holdex
Copy link
Copy Markdown

holdex Bot commented Nov 3, 2025

Time Submission Status

Member Status Time Action Last Update
williamrusdyputra ✅ Submitted 3h Update time Nov 3, 2025, 9:57 AM
MicBun ✅ Submitted 15min Update time Nov 3, 2025, 1:03 PM

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.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1956337 and 5aff827.

📒 Files selected for processing (1)
  • internal/migrations/erc20-bridge/002-public-transfer-actions.sql (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-23T07:00:26.796Z
Learnt from: williamrusdyputra
Repo: trufnetwork/node PR: 1228
File: internal/migrations/erc20-bridge/000-extension.sql:16-19
Timestamp: 2025-10-23T07:00:26.796Z
Learning: In internal/migrations/erc20-bridge/000-extension.sql, the active sepolia_bridge configuration is intentionally for test environments only and does not include the distribution_period parameter. The commented sepolia_bridge and ethereum_bridge blocks with distribution_period are production configurations.

Applied to files:

  • internal/migrations/erc20-bridge/002-public-transfer-actions.sql
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: acceptance-test
  • GitHub Check: lint
🔇 Additional comments (2)
internal/migrations/erc20-bridge/002-public-transfer-actions.sql (2)

24-25: Verify SQL variable declaration and address encoding approach.

Lines 24–25 declare and initialize $leader_addr in a single statement using encode(@leader_sender, 'hex')::TEXT. Confirm:

  • The SQL dialect supports this declaration/assignment syntax
  • encode(@leader_sender, 'hex')::TEXT correctly converts the leader's public key/identity into a valid Ethereum address format compatible with the bridge's transfer() method

If @leader_sender is a public key or binary identifier, ensure the hex encoding produces a string in the format expected by sepolia_bridge.transfer() (likely 0x... prefixed).


44-53: Verify consistency of address encoding in ethereum_transfer.

The ethereum_transfer action mirrors the fee-transfer pattern from sepolia_transfer (after the fix on line 20). Lines 52–53 use the same encode(@leader_sender, 'hex')::TEXT encoding strategy. Once you've verified the encoding approach in sepolia_transfer, confirm the same strategy is correct here as well.

Comment thread internal/migrations/erc20-bridge/002-public-transfer-actions.sql
@williamrusdyputra
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 3, 2025

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@MicBun MicBun left a comment

Choose a reason for hiding this comment

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

lgtm

@MicBun MicBun merged commit 23bf5bb into main Nov 3, 2025
7 checks passed
@MicBun MicBun deleted the chore/transfer-fee branch November 3, 2025 09:57
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