Skip to content

feat(rewarding): add AutoDeposit compound bridge for IIP-59 (PR 4.6)#4922

Draft
envestcc wants to merge 1 commit into
masterfrom
iip-59/pr4.6-autodeposit-bridge
Draft

feat(rewarding): add AutoDeposit compound bridge for IIP-59 (PR 4.6)#4922
envestcc wants to merge 1 commit into
masterfrom
iip-59/pr4.6-autodeposit-bridge

Conversation

@envestcc

Copy link
Copy Markdown
Member

Summary

Adds a read-only bridge to the on-chain AutoDeposit contract so the (upcoming) PR 3' rework of distributeVoterReward can decide per-voter compound-vs-credit routing at epoch reward distribution time, per IIP-59 §3.6.

Structural clone of PR 4.5's delegateprofile.Bridge — same shape, same ContractReader interface, same per-item fallback discipline — so both on-chain reads present a uniform surface.

What lands

New package action/protocol/rewarding/autodeposit

  • Bridge wraps a pinned contract deployment; LookupBucket(ctx, reader, voter) returns (bucketID, present, err).
  • ContractReader is package-local so tests can supply a fake without pulling the EVM simulator into scope.
  • Route / Decision types match IIP-59 §3.5's DelegateDistributed.routings[] wire encoding, giving PR 4.7 a single source of truth.
  • IsBucketEligibleForCompound applies §3.6 preconditions 2–4 (bucket exists, is native, AutoStake==true, currently active, Owner==voter). Precondition 1 (positive bucket ID) is enforced inside LookupBucket.

Semantics

Per IIP-59 §3.6 the drain path must not halt on a single voter's malformed registration:

Contract returns LookupBucket result
positive int256 fitting in uint64 (id, true, nil)
zero, negative, or > 2⁶³−1 (0, false, nil) — silent fallback to credit
ABI drift / RPC error / nil reader / nil voter (0, false, err) — wiring bug, hard error

Genesis

  • New Blockchain.AutoDepositContractAddress field, default empty. Empty means compound routing is inactive and every voter share is credited to unclaimedBalance for pull-claim — functionally identical to legacy behaviour, so no fork gate churn.

Staking

  • Exported VoteBucket.IsUnstaked() and IsNative() wrappers on top of the existing unexported predicates, so the autodeposit eligibility helper doesn't have to duplicate staking-internal invariants.

Explicit non-goals

  • No AddDeposit invocation. Applying the compound (mutating bucket state) is PR 3''s job via staking's native handler_stake_add_deposit.go path.
  • No poll integration. Unlike DelegateProfile, AutoDeposit is read live at drain time, not frozen at PutPollResult.
  • No paused() / registrants() reads. Neither affects routing (paused() blocks writes; view calls always succeed; registrants() is redundant because bucket(voter)==0 already means unregistered).
  • No batched API. PR 3' iterates voters and calls LookupBucket per voter; total volume is bounded (~2k reads/epoch per spec).

Feature-flag matrix

NoVoterRewardDistribution AutoDepositContractAddress Compound routing
true (pre-fork) any Drain not running; bridge never called.
false (post-fork) empty Drain runs; PR 3' skips bridge; every voter → unclaimedBalance.
false (post-fork) non-empty Bridge called per voter; positive bucket(voter) + eligibility → compound; else credit.

Test plan

  • go build ./... clean
  • gofmt -l clean on touched files
  • go vet clean on touched packages
  • go test ./action/protocol/rewarding/autodeposit/... -count=1 -v — 20 tests, all green
  • Regression go test ./action/protocol/rewarding/... ./action/protocol/staking/... ./blockchain/genesis/... -count=1 — 426 tests, all green
  • bridge_test.go TestLookupBucket_CallDataShape guards against ABI drift by asserting selector keccak256("bucket(address)")[:4] and address layout in the encoded call data.

Stack

Branched from upstream/master directly rather than stacking on the earlier IIP-59 PRs — this PR shares no code with them, so a flat branch means cleaner review and no rebase pressure if PR 4.5 / PR 2' churn.

  • Depended on by: PR 3' (rework distributeVoterReward), PR 4.7 (batched DelegateDistributed log).
  • Depends on: nothing from this stack.

🤖 Generated with Claude Code

…ound routing

Introduce a read-only bridge to the on-chain AutoDeposit contract so PR 3'
(distributeVoterReward rework) can decide per-voter compound-vs-credit
routing at epoch reward distribution time per IIP-59 §3.6.

- New action/protocol/rewarding/autodeposit package:
  * Bridge: stateless wrapper around the pinned AutoDeposit contract,
    exposing LookupBucket(ctx, reader, voter) → (bucketID, present, err).
  * ContractReader: package-local view-call primitive so unit tests can
    stand in a fake without pulling the EVM simulator into scope.
  * Route / Decision types with wire format shared with PR 4.7's
    DelegateDistributed.routings[] encoding.
  * IsBucketEligibleForCompound helper applies §3.6 preconditions 2-4
    (bucket exists, native bucket, AutoStake=true, active, Owner==voter).
  * Structurally mirrors PR 4.5's delegateprofile.Bridge so both bridges
    present a uniform surface to callers.

- Per-item fallback semantic (IIP-59 §3.6): malformed on-chain data
  (negative int256, oversized-for-uint64 value) silent-fallbacks to
  RouteCredit rather than erroring the block. Only wiring bugs (nil
  reader, nil voter, ABI drift, RPC error) hard-error.

- New genesis field Blockchain.AutoDepositContractAddress with empty
  default (compound routing inactive → every voter share → unclaimedBalance).

- New exported staking.VoteBucket.IsUnstaked() and IsNative() wrappers so
  the autodeposit package can gate eligibility without duplicating the
  staking-internal invariants.

AutoDeposit is read live at drain time, not frozen at PutPollResult
(unlike DelegateProfile) — see IIP-59 §3.6.

Ships independently of the earlier stack (PR 4.5 / PR 2') since it shares
no code with them.
@sonarqubecloud

Copy link
Copy Markdown

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.

1 participant