Skip to content

Emissions: fund sysio.dclaim immediately on incoming OPP claim#354

Open
heifner wants to merge 5 commits into
masterfrom
feature/emissions-dclaim-instant-funding
Open

Emissions: fund sysio.dclaim immediately on incoming OPP claim#354
heifner wants to merge 5 commits into
masterfrom
feature/emissions-dclaim-instant-funding

Conversation

@heifner
Copy link
Copy Markdown
Contributor

@heifner heifner commented May 23, 2026

Summary

Replaces the curve-driven capital BPS share with immediate funding tied to actual OPP claim load. sysio.dclaim::onreward now inline-calls a new sysio.system::fundclaim action that transfers the exact credit amount from sysio's pool to sysio.dclaim, so a staker can claim in the next block instead of waiting for the next pay-epoch.

Model

  • payepoch transfers compute + capex + governance only. The "capital bucket" is gone -- the slot it used to occupy is now an implicit capital reserve (period_emission - compute - capex - governance) that stays in sysio's balance.
  • fundclaim drains the pool against the implicit reserve in real time, one inline action per onreward. The reserve naturally absorbs the rounding dust from per-share split_bps floors.
  • When fundclaim is asked for more than the pool has left, it transfers what's available and bumps t5_state.capital_shortfall_total by the unfunded delta. It never throws (the OPP inbound dispatch chain must not be aborted by emissions-side conditions).

ABI changes

  • emission_config.capital_bps removed. setemitcfg now requires compute_bps + capex_bps + governance_bps <= 10000.
  • epoch_log.capital_amount removed.
  • t5_state.capital_shortfall_total (int64) added.
  • New sysio.system::fundclaim(int64_t amount) action, auth=sysio.dclaim.

Pre-launch, so no migration shim.

heifner added 2 commits May 23, 2026 16:57
dclaim::onreward now inline-calls a new sysio.system::fundclaim action
that drains the t5 pool to dclaim for the exact reward amount, so a
staker can claim in the next block instead of waiting for the next
pay-epoch. payepoch no longer transfers capital; the implicit capital
reserve (period_emission minus compute / capex / governance) stays in
sysio's balance until fundclaim pulls it.

- Remove capital_bps from emission_config; setemitcfg validates
  compute + capex + governance <= 10000. The remainder is the implicit
  capital reserve.
- Add t5_state.capital_shortfall_total; fundclaim accrues any unfunded
  delta here when the pool runs short, preserving the never-throw
  contract for opp inbound dispatch.
- Remove epoch_log.capital_amount (always zero under this model).
…emissions-dclaim-instant-funding

# Conflicts:
#	contracts/sysio.dclaim/sysio.dclaim.wasm
auto state = t5s.get();

const auto cfg = get_emit_cfg(get_self());
const int64_t remaining = cfg.t5_distributable - cfg.t5_floor - state.total_distributed;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This caps fundclaim only by lifetime emission headroom, but ignores state.pending_emission_amount, which has already accrued for the current pay period at emissions.cpp (line 474). With pay_cadence_epochs > 1, a capital draw between accrue and payepoch can consume funds already scheduled for compute/capex/governance. The next payepoch then either blocks on insufficient balance or treasury exhaustion while pending_emission_amount remains unpaid. Cap the claim pool to the current period’s implicit capital reserve, or at least exclude pending payepoch obligations from the transferable amount.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 2b4e0d1. fundclaim now subtracts state.pending_emission_amount from the lifetime headroom cap, so a capital draw between accrueepoch and payepoch cannot consume the funds already scheduled for the next payepoch's compute/capex/governance distribution.

const int64_t shortfall = amount - to_transfer;

if (to_transfer > 0) {
send_wire_transfer(get_self(), CAPITAL_ACCOUNT, to_transfer, memo::capital);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This still performs a real token transfer after only checking accounting headroom. If sysio’s actual WIRE balance is below to_transfer, sysio.token::transfer throws overdrawn balance at sysio.token.cpp (line 98). Since sysio.dclaim::onreward sends this inline at sysio.dclaim.cpp (line 252), the inbound OPP handler can still abort despite the “never throws” guarantee. Include actual sysio WIRE balance in the cap before sending the transfer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 2b4e0d1. fundclaim now caps to sysio's actual WIRE balance (also less pending_emission_amount) before sending the transfer, so sysio.token::transfer cannot throw overdrawn balance from inside the inline STAKING_REWARD dispatch. The final transfer amount is std::min({amount, lifetime_headroom - pending, balance - pending}); any unfunded delta accrues to capital_shortfall_total.

heifner added 2 commits May 25, 2026 18:05
…emissions-dclaim-instant-funding

# Conflicts:
#	contracts/sysio.system/sysio.system.wasm
Addresses PR #354 review:

- Subtract state.pending_emission_amount from the lifetime headroom cap so
  fundclaim cannot consume funds already accrued (via accrueepoch) for the
  next payepoch's compute/capital/capex/governance distribution.

- Add an actual sysio WIRE balance cap (also less pending) so the inline
  sysio.token::transfer cannot throw "overdrawn balance". STAKING_REWARD
  dispatch from sysio.msgch is bound by the never-throw contract for OPP
  inbound handlers; an aborting transfer would propagate up and break
  envelope consensus.

Transfer cap is now std::min({amount, accounting_available, balance_available}).
Shortfall accrual to capital_shortfall_total is unchanged.
Base automatically changed from feature/sysio-cap to master May 26, 2026 02:46
…claim-instant-funding

# Conflicts:
#	contracts/sysio.system/sysio.system.wasm
Copy link
Copy Markdown
Collaborator

@jglanz jglanz left a comment

Choose a reason for hiding this comment

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

looks good; personally I'd like to chat about how the different basis points (bps) are applied/related, but generally the code seems fine

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.

3 participants