Skip to content

chore(tnt-core-v0.13.0): regenerate ABIs + slashing UX polish#3198

Merged
drewstone merged 9 commits intodevelopfrom
chore/tnt-core-v0.13.0-sync
May 8, 2026
Merged

chore(tnt-core-v0.13.0): regenerate ABIs + slashing UX polish#3198
drewstone merged 9 commits intodevelopfrom
chore/tnt-core-v0.13.0-sync

Conversation

@drewstone
Copy link
Copy Markdown
Contributor

Picks up the v0.13.0 surface changes from tnt-core (audit follow-ups landed
in PR #124 and
PR #125) and uses
the resync as a chance to close the loop on a handful of UX gaps that the
new contract fields make actionable.

REQUIRED — ABI sync

  • chore(abi): regenerate from tnt-core v0.13.0 — runs yarn sync:tnt-core-assets against tnt-core@v0.13.0. Generated ABIs now contain SlashCancelled, SlashConfigUpdated, SlashDisputed events; the 6-field SlashConfig; the 14-field SlashProposal; forceRemoveAllowsBelowMin on IBlueprintServiceManager; the requester-first JobQuoteDetails; and the now-routable expireServiceRequest selector. Sync script swapped to OperatorStatusRegistry.json (impl ABI) since tnt-core v0.13.0 stopped emitting the interface JSON.
  • chore(abi-sync): run prettier on generated ABIs — drops the JSON-style output the sync script was producing in favour of the codebase's prettier style so yarn format:check stays clean across regenerations.

RECOMMENDED — UX polish (each in its own commit)

a. DisputeSlashModal surfaces the required disputeBond

feat(slashing-ui): surface dispute bond + resolution deadline on DisputeSlashModal

The modal now reads the active SlashConfig and renders the required bond inline as X ETH (refunded if dispute upheld), matching the message the useDisputeSlashTx hook already attaches as msg.value. When the slash is already in Disputed state, also surface the on-chain disputer address and a live countdown to disputeDeadline (the field added by tnt-core v0.13.0). User-facing: the "Submit Dispute" CTA is no longer a black box — operators see what bond they're posting before signing.

b. ProposeSlashModal enforces SlashConfig.maxSlashBps

feat(slashing-ui): enforce SlashConfig.maxSlashBps cap on ProposeSlashModal

Pulls maxSlashBps from useSlashConfig, surfaces it in both the BPS input placeholder and a helper line under the field, and short-circuits validation client-side. User-facing: proposers stop wasting simulation gas on out-of-range values.

c. SlashProposal extended with dispute lifecycle fields

feat(slashing): extend SlashProposal with dispute lifecycle fields

SlashProposal now exposes disputer, disputeBond, disputedAt, and disputeDeadline. normalizeOnChainSlashProposal reads positions 10–13 of the new getSlashProposal tuple; the GraphQL fallback path defaults the new columns to zero-values with a comment so callers needing authoritative dispute data can hit useSlashProposalDetails (on-chain). useSlashConfig is now exported from data/graphql so feature code consumes it via the public surface.

d. New "Expire request" action

feat(services): permissionless expire-service-request action

New useExpireServiceRequestTx hook + REQUEST_EXPIRY_GRACE_PERIOD_SECONDS / isServiceRequestExpired helpers in libs/tangle-shared-ui/src/data/services/useExpireServiceRequest.ts. Wired into the request-detail modal as an "Expire request" button gated on now > createdAt + grace and !rejected, with full loading / error / success handling and serviceRequestDetails cache invalidation. Available in both default and viewOnly footers because the call is permissionless. User-facing: anyone can clean up a stale request, refunding the requester and freeing the operator candidates without a manual contract call.

e. SlashConfig parameters card

feat(slashing-ui): surface SlashConfig parameters at top of operator management

New read-only SlashingParametersCard rendered above the slashing summary on apps/tangle-cloud/src/pages/operators/manage. Surfaces maxSlashBps, disputeWindow, disputeResolutionDeadline, disputeBond, maxPendingSlashesPerOperator, and instantSlashEnabled. User-facing: proposers and operators see the active policy levers up front instead of discovering them via failed simulations.

Verification

  • TNT_CORE_DIR=/home/drew/code/tnt-core yarn sync:tnt-core-assets — green; regenerated ABIs contain the expected new entries.
  • yarn nx run tangle-cloud:typecheck — green
  • yarn nx run tangle-cloud:build — green
  • yarn nx run tangle-cloud:lint — green
  • yarn nx run tangle-dapp:typecheck / :build / :lint — green (no behavioural changes there; the regenerated ABIs are the only shared touchpoint)
  • yarn nx run tangle-shared-ui:test — 32 passed, 0 failed
  • yarn nx run tangle-shared-ui:lint — green
  • yarn format:check — green

Test plan

  • Open the operator-management page on a network with SlashConfig.disputeBond > 0 and confirm the new SlashingParametersCard renders the bond, deadlines, and caps.
  • Trigger ProposeSlashModal with a BPS above the active cap; expect the validation error to fire client-side without a simulation roundtrip.
  • Trigger DisputeSlashModal on a Pending slash; expect the "Required Dispute Bond" row to render the bond. Submit; expect msg.value to match.
  • Trigger DisputeSlashModal on a Disputed slash; expect the disputer address + countdown rows to render.
  • Open the request-detail modal on a request whose createdAt + 1h < now and is not yet rejected; click "Expire request"; expect a successful tx, modal close, and the request to disappear from the parent list.

drewstone added 8 commits May 8, 2026 15:00
- Run yarn sync:tnt-core-assets against tnt-core@v0.13.0 (PR #124, #125).
- ITangleFull: SlashConfig now exposes 6 fields including disputeResolutionDeadline,
  disputeBond, maxPendingSlashesPerOperator. SlashProposal grows disputer/disputeBond/
  disputedAt/disputeDeadline. New events SlashCancelled, SlashConfigUpdated, SlashDisputed.
  JobQuoteDetails now puts requester first (wildcard rejected). expireServiceRequest is
  permissionless on the proxy. Types.ServiceRequest.activated moved to end of struct.
- IBlueprintServiceManager: new forceRemoveAllowsBelowMin(uint64) -> bool hook.
- Sync script: tnt-core no longer ships IOperatorStatusRegistry.json; switch to the
  implementation ABI (OperatorStatusRegistry.json) which carries the same external
  surface and is what the dapp consumes. Future regenerations now succeed cleanly.

Refs: tangle-network/tnt-core#124, tangle-network/tnt-core#125
tnt-core v0.13.0 adds disputer, disputeBond, disputedAt, and disputeDeadline
to the SlashProposal struct returned by getSlashProposal. Surface these on the
SlashProposal interface so the UI can render the disputer and an authoritative
dispute resolution countdown once a slash flips to Disputed.

- Update normalizeOnChainSlashProposal to read positions 10-13 of the tuple
  (the source of truth for an in-flight dispute).
- Default the GraphQL fallback path to zero-values; the indexer schema does
  not yet ship these columns, and consumers that need authoritative dispute
  data should hit useSlashProposalDetails (on-chain read).
- Re-export useSlashConfig from data/graphql so feature code can pull the
  active SlashConfig (disputeBond, maxSlashBps, etc.) without reaching into
  the implementation file directly.
…uteSlashModal

Operators repeatedly hit "insufficient funds" when admins enable a non-zero
dispute bond because the modal never tells them how much ETH the contract
will demand. Pull the active SlashConfig from the Tangle proxy and render
the required bond inline as "X ETH (refunded if dispute upheld)" so users
see the cost before signing — matches the message attached to the
disputeSlash hook in useSlashing.

When the slash is already in `Disputed` state, also render the on-chain
disputer address and a live countdown to disputeDeadline (the new field
from getSlashProposal in tnt-core v0.13.0). This gives the operator and
the admin a shared view of how long the resolution window has left.
…hModal

Operators were burning simulation gas on slash proposals that the contract
will deterministically reject because slashBps > SlashConfig.maxSlashBps.
Pull the active cap from useSlashConfig and:

- Render the cap in the BPS field placeholder + a helper line so users see
  the upper bound before typing.
- Short-circuit the validation pipeline once the cap loads — proposals
  above maxSlashBps are blocked client-side with an explicit message.

Falls through to the contract hard ceiling (10_000) while the config is
still loading, preserving the previous behaviour for the first paint.
tnt-core v0.13.0 routes expireServiceRequest through the proxy so anyone can
call it once `now > req.createdAt + REQUEST_EXPIRY_GRACE_PERIOD`. The path
refunds the requester and frees the operator candidates — without it stale
requests linger forever with their payment locked. Surface this as a real
action on the request-detail modal:

- New useExpireServiceRequestTx hook (libs/tangle-shared-ui/src/data/services/
  useExpireServiceRequest.ts) wired through useContractWrite so it gets the
  same simulation, receipt-wait, and toast machinery as the rest of the tx
  hooks. On success it invalidates serviceRequestDetails, serviceRequests,
  and services so the calling surface refetches without a hard reload.
- REQUEST_EXPIRY_GRACE_PERIOD_SECONDS constant + isServiceRequestExpired /
  getServiceRequestExpiryEligibleAt helpers, mirroring ProtocolConfig.sol
  (1 hour). The contract permits admins to override the grace period but
  exposes no getter, so we use the protocol default — conservative because
  any custom override is always >= 1 hour in practice.
- "Expire request" button on ServiceRequestDetailModal, shown both in the
  default and viewOnly footers since the call is permissionless. Gated on
  `isServiceRequestExpired(createdAt)` AND `!rejected` so we don't waste
  gas on a guaranteed revert. Loading + error states are handled inline
  and the modal closes on success.
…management

tnt-core v0.13.0 grew SlashConfig from 3 to 6 fields — disputeResolutionDeadline,
disputeBond, and maxPendingSlashesPerOperator are now operator-visible policy
levers, not just internal contract state. Add a read-only SlashingParametersCard
above the slashing summary on the operator-management page so both proposers
and operators see the active caps and bond up front:

- maxSlashBps (rendered as bps + %)
- disputeWindow + disputeResolutionDeadline (humanised durations)
- disputeBond (ETH-formatted, "None" when zero)
- maxPendingSlashesPerOperator ("Unlimited" when zero)
- instantSlashEnabled flag

The card is read-only and self-loads via useSlashConfig — no extra props
required from the page beyond the data the page already fetches.
…eRequest

Lets the @typescript-eslint/no-inferrable-types rule pass without changing
the call surface. The defaults still resolve to bigints because both the
Date.now() expression and REQUEST_EXPIRY_GRACE_PERIOD_SECONDS are bigints.
…quest modals

The sync script previously emitted raw JSON.stringify output (double-quoted,
no trailing commas) which drifted from the rest of the codebase's prettier
config and caused yarn format:check to fail after every regeneration. Pipe
the four generated ABI files through `npx prettier --write` at the end of
the sync, and reformat the existing artifacts in the same pass. Also pick
up minor prettier-driven whitespace fixes on the two modals touched in
the slashing UX commits.

No behaviour changes — prettier rewrites are pure-formatting only.
@drewstone drewstone requested a review from AtelyPham as a code owner May 8, 2026 21:17
@netlify
Copy link
Copy Markdown

netlify Bot commented May 8, 2026

Deploy Preview for tangle-cloud ready!

Name Link
🔨 Latest commit 92bcf05
🔍 Latest deploy log https://app.netlify.com/projects/tangle-cloud/deploys/69fe54dbf55963000880a4f6
😎 Deploy Preview https://deploy-preview-3198--tangle-cloud.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 8, 2026

Deploy Preview for tangle-dapp ready!

Name Link
🔨 Latest commit 92bcf05
🔍 Latest deploy log https://app.netlify.com/projects/tangle-dapp/deploys/69fe54db4192d10008eda81b
😎 Deploy Preview https://deploy-preview-3198--tangle-dapp.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 8, 2026

Deploy Preview for tangle-leaderboard ready!

Name Link
🔨 Latest commit 92bcf05
🔍 Latest deploy log https://app.netlify.com/projects/tangle-leaderboard/deploys/69fe54db9d62b500072b5bbd
😎 Deploy Preview https://deploy-preview-3198--tangle-leaderboard.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Both `https://nx.dev/packages/storybook/generators/migrate-7` and
`https://nx.dev/packages/storybook/documents/storybook-7-setup` now
return 404 — Nx restructured their docs site and the documents/<slug>
URL scheme is retired. The link-check CI on this PR was correctly
flagging the 404; the file was last touched in #3183 so this isn't a
regression introduced here, just a passing-through fix.

Replaced the bracketed links with a plain-text pointer to the Nx docs
root. The bigger Storybook upstream links above are still valid.
@drewstone drewstone merged commit ca5a459 into develop May 8, 2026
19 of 20 checks passed
@drewstone drewstone deleted the chore/tnt-core-v0.13.0-sync branch May 8, 2026 21:41
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