feat(deploy): make tnt-core deployable on Tempo — split StakingDelegationsFacet + ServiceFeeDistributor library (30M per-tx cap)#207
Conversation
…tor for Tempo 30M per-tx deploy cap Tempo (chain 42431) caps a tx at 30M gas and meters code deposit ~6.7x, so contracts near the EIP-170 24KB limit exceed the deploy cap: - StakingDelegationsFacet (24358B, 33.1M CREATE): split the single-step redeem path (executeDelegatorUnstakeAndWithdraw + helpers) into new StakingUnstakeWithdrawFacet; both share StakingFacetBase so storage/behavior identical, one selector relocates. Now 21237B/~29M. - ServiceFeeDistributor (24302B, 33.4M CREATE): extract heavy math into deployed library ServiceFeeDistributorLib + storage-struct refactor (layout byte-identical). Now 19288B/~26.5M. Registered the new facet at all 22 deploy/test sites + FacetSize assertion. Tests: staking/delegation 223 (6 formerly-UnknownSelector now pass); rewards 174/174 (agent). WIP: pending fresh Tempo broadcast to confirm every CREATE < 30M.
Full-stack FullDeploy broadcast to Tempo Moderato testnet succeeded (143 txs, ~707M gas / $2.38) after the split+shrink brought every CREATE under Tempo's 30M per-tx cap. Verified on-chain: proxies have code, TNT token symbol() reads, and executeDelegatorUnstakeAndWithdraw routes to the new StakingUnstakeWithdrawFacet. tangle=0xff137b9c879c47c28ce389e84501925438ab4cda staking=0x9484d07899b98384f1d66bd5b2659f3ed346f89e
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 4f029422
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-07-07T23:38:48Z
tangletools
left a comment
There was a problem hiding this comment.
⚪ Value Audit — audit-incomplete
| Verdict | audit-incomplete |
| Concerns | 0 (none) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 7.4s (2 bridge agents) |
| Total | 7.4s |
💰 Value — error
value agent produced no parseable value-audit JSON.
- Model: opencode/deepseek/deepseek-v4-pro
- Bridge attempts: 3
- Bridge error: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content; opencode/zai-coding-plan/glm-5.2: bridge stream ended without value-audit content; opencode/deepseek/deepseek-v4-pro: bridge stream ended without value-audit content
🎯 Usefulness — error
usefulness agent produced no parseable value-audit JSON.
- Model: opencode/deepseek/deepseek-v4-pro
- Bridge attempts: 3
- Bridge error: opencode/zai-coding-plan/glm-5.2: bridge stream ended without value-audit content; opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content; opencode/deepseek/deepseek-v4-pro: bridge stream ended without value-audit content
No PR concerns were produced because the value/usefulness agent pass did not complete. Treat this audit as incomplete, not as approval.
What this audit checks
It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.
| Pass | What it asks |
|---|---|
| Heuristic | Vague title? Whitespace-only or cruft-bearing diff? (content signals only) |
| Duplication | Do added function/class names already exist elsewhere in the repo? |
| Value Audit | What does it do? What goal does it achieve? Is it good? Better architecture or already-exists? |
| Usefulness Audit | Does it integrate and fit? Will it hold up in real use and actually get used? |
Findings are concerns, not blocks — the human reviewer decides what to do with them.
…join-seed + SFD deploy-once Boil-the-ocean pre-testnet hardening pass, all folded onto the Tempo-deployability branch: - SIZE GATE (durable): new test_DeployablesUnderTempoDeployCap asserts every deployable contract (26 facets + near-ceiling impls) stays < 21,500 B — Tempo's 30M per-tx cap meters code-deposit ~1,372 gas/byte, so the deploy ceiling is ~21,870 B, STRICTER than EIP-170. CI now fails before any contract can grow past the point where a Tempo broadcast reverts. - BEACON SHRINK: ValidatorPodManager 21,760 -> 19,929 B via a delegatecall-linked ValidatorPodManagerLib (delegateTo/queueUndelegation/completeUndelegation/_slash extracted), storage + behavior byte-identical. Gives beacon real Tempo headroom (was 40 B). - FAIL-CLOSED REFINEMENT (audit LOW): an operator joining an already-USD-pinned subscription while the oracle is off now seeds an identity snapshot (1e18) so its leg bills at raw scale instead of being zeroed. Gated strictly on the service being ALREADY USD-pinned so the "snapshot present <=> USD-pinned" witness is never corrupted. _subscriptionPinnedInUsd moved to shared Base (ServicesLifecycle + Payments are separate facets; one definition avoids drift). - SFD DEPLOY-ONCE: FullDeploy deployed ServiceFeeDistributor impl twice (inherited DeployV2._configureServiceFeeDistributor + FullDeploy's own path, the first orphaned). New virtual seam _deploysServiceFeeDistributorExternally() lets FullDeploy skip the inherited deploy; base DeployV2 behavior unchanged. Saves one ~26.7M-gas orphaned CREATE. - Tests: fail-closed branch now covered (join-seed + fail-closed + non-USD invariant, 3 tests); the fail-closed test locates its storage slot dynamically (survives reorders) rather than hardcoding it. Verified: src builds; every gated contract < 21,500 B (ValidatorPodManager 19,929, SFD 19,288, StakingDelegationsFacet 21,237); FacetSize gate 3/3; PaymentsBilling 6/6; behavior sweep green.
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — b07970f8
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-07-08T01:29:12Z
tangletools
left a comment
There was a problem hiding this comment.
⚪ Value Audit — audit-incomplete
| Verdict | audit-incomplete |
| Concerns | 0 (none) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 176.6s (2 bridge agents) |
| Total | 176.6s |
💰 Value — error
value agent produced no parseable value-audit JSON.
- Model: opencode/deepseek/deepseek-v4-pro
- Bridge attempts: 3
- Bridge error: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content; opencode/zai-coding-plan/glm-5.2: bridge stream ended without value-audit content; opencode/deepseek/deepseek-v4-pro: bridge stream ended without value-audit content
🎯 Usefulness — error
usefulness agent produced no parseable value-audit JSON.
- Model: opencode/deepseek/deepseek-v4-pro
- Bridge attempts: 3
- Bridge error: opencode/zai-coding-plan/glm-5.2: bridge stream ended without value-audit content; opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content; opencode/deepseek/deepseek-v4-pro: bridge stream ended without value-audit content
No PR concerns were produced because the value/usefulness agent pass did not complete. Treat this audit as incomplete, not as approval.
What this audit checks
It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.
| Pass | What it asks |
|---|---|
| Heuristic | Vague title? Whitespace-only or cruft-bearing diff? (content signals only) |
| Duplication | Do added function/class names already exist elsewhere in the repo? |
| Value Audit | What does it do? What goal does it achieve? Is it good? Better architecture or already-exists? |
| Usefulness Audit | Does it integrate and fit? Will it hold up in real use and actually get used? |
Findings are concerns, not blocks — the human reviewer decides what to do with them.
Problem
Tempo (chain 42431) caps a transaction at 30M gas and meters contract code deposit ~6.7× mainnet. Contracts near the EIP-170 24KB runtime limit therefore blow the per-tx deploy cap: a
FullDeployto Tempo failed onStakingDelegationsFacet(24,358 B → 33.1M CREATE > 30M). A full size audit found two over-cap contracts in the Tempo path; every other CREATE fits.Changes
1. Split
StakingDelegationsFacet(24,358 → 21,237 B). The single-step redeem path —executeDelegatorUnstakeAndWithdraw+ its 9 private helpers + theFixedModeBondlessContextstruct (~300 lines) — moves into a newStakingUnstakeWithdrawFacet. Both extend the sameStakingFacetBase, so storage and behavior are identical; only that one selector routes to the new facet. Registered at all 22 deploy/test sites + aFacetSizeassertion.2. Shrink
ServiceFeeDistributor(24,302 → 19,288 B). Heavy math/bookkeeping (USD conversion, slash factors, the two USD-total + two distribution loops, immediate-distribute, fixed-score delta, expired-lock decay, harvest/debt settlement, transfers) moves into a new deployed libraryServiceFeeDistributorLib(public functions → delegatecall-linked, code lives in the library). All 32 state vars move into a singleLayoutstruct at slot 0 in the exact original field order — storage layout verified byte-for-byte identical (hard requirement for this live UUPS contract). Foundry auto-links the library at broadcast; no deploy-script change. (Explorer verification needs--libraries— metadata only.)Result: every Tempo CREATE now < 30M (heaviest: StakingDelegationsFacet 28.96M, ServiceFeeDistributor 26.7M, InflationPool 27.8M).
Verified
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL, 143 txs, ~707M gas / $2.38. Live checks: proxies have code;TNT.symbol()reads;executeDelegatorUnstakeAndWithdrawroutes to the new facet and executes its guard (revertsZeroAmount, notUnknownSelector) — the split works on-chain.0xff137b9c879c47c28ce389e84501925438ab4cda· staking0x9484d07899b98384f1d66bd5b2659f3ed346f89eStakingFacetBase;ServiceFeeDistributorsignatures/events/errors unchanged (contract isn't in the Rust bindings).