MDK Logo

Write actions

How to add an approval flow to your MDK app

Overview

This guide demonstrates how to submit approval-gated write actions from a React app, review the server-side voting queue, and approve, reject, or cancel pending actions through the App Node.

Prerequisites

Submit staged actions

1.1 Submit a single action

Use useSubmitSingleAction() when the UI lets an operator submit one staged action by id.

import { useSubmitSingleAction } from "@tetherto/mdk-react-adapter/hooks";

function SubmitActionButton({ actionId }: { actionId: number }) {
  const submit = useSubmitSingleAction();

  return (
    <button
      type="button"
      disabled={!submit.canSubmit || submit.submittingActionId === actionId}
      onClick={() => submit.submitSingle(actionId)}
    >
      Submit action
    </button>
  );
}

1.2 Submit all staged actions

Use useSubmitPendingActions() when the UI has a review tray or bulk-submit control that should send the whole local staging queue.

import { useSubmitPendingActions } from "@tetherto/mdk-react-adapter/hooks";

function SubmitActionsButton() {
  const submitPending = useSubmitPendingActions();

  return (
    <button
      type="button"
      disabled={submitPending.isSubmitting || !submitPending.canSubmit}
      onClick={() => submitPending.submit()}
    >
      Submit staged actions
    </button>
  );
}

Review the server-side queue

After submission, actions move from the local staging queue into the App Node /auth/actions* voting surface.

2.1 Review with usePendingActions()

Use usePendingActions() for a pending-action review table. Pass refetchInterval to override the default poll cadence (see hook reference).

import { usePendingActions } from "@tetherto/mdk-react-adapter/hooks";

function PendingActionsList() {
  const { data: pending = [], isLoading } = usePendingActions({
    refetchInterval: 5000,
  });

  if (isLoading) return <p>Loading pending actions...</p>;

  return (
    <ul>
      {pending.map((action) => (
        <li key={action.id}>{action.id}</li>
      ))}
    </ul>
  );
}

2.2 Review with useLiveActions()

Use useLiveActions() when the UI needs to separate the current user's actions from others and gate approve/reject controls on canApprove. For polling cadence and role logic, see the hook reference.

Approve or reject an action

Use useVoteOnAction() to cast an approval or rejection. The hook calls PUT /auth/actions/voting/:id/vote and invalidates the relevant action caches. Disable direct vote buttons when canVote is false. Review-tray UIs that approve other users' actions should combine this mutation with useLiveActions().canApprove.

import { useVoteOnAction } from "@tetherto/mdk-react-adapter/hooks";

function VoteButtons({ actionId }: { actionId: string }) {
  const vote = useVoteOnAction();

  return (
    <>
      <button
        type="button"
        disabled={!vote.canVote}
        onClick={() => vote.vote({ id: actionId, approve: true })}
      >
        Approve
      </button>
      <button
        type="button"
        disabled={!vote.canVote}
        onClick={() => vote.vote({ id: actionId, approve: false })}
      >
        Reject
      </button>
    </>
  );
}

Cancel pending actions

Use useCancelAction() when the current operator should withdraw one or more pending actions before the vote thresholds are met. The App Node exposes the voting cancel route at DELETE /auth/actions/voting/cancel.

import { useCancelAction } from "@tetherto/mdk-react-adapter/hooks";

function CancelActionButton({ actionId }: { actionId: string }) {
  const cancel = useCancelAction();

  return (
    <button type="button" onClick={() => cancel.cancel({ ids: [actionId] })}>
      Cancel
    </button>
  );
}

Verify the result

Approved actions become command requests after the configured vote thresholds are met. Watch the feature state that initiated the action, or poll the action list with usePendingActions() / useLiveActions() until the item leaves the voting queue.

For Pool Manager screens, use the existing actions sidebar USAGE and Pool Manager blueprint as the integration examples.

Next steps

On this page