Agent skill
midnight-dapp:transaction-flows
Use when submitting transactions to Midnight contracts, tracking transaction status, implementing retry logic, building responsive UIs during proof generation, or understanding the build-prove-submit-confirm flow.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/transaction-flows
SKILL.md
Transaction Flows
Submit, track, and handle transactions through the complete Midnight lifecycle: build, prove, submit, and confirm.
When to Use
- Submitting transactions to Midnight contracts
- Tracking transaction status and confirmation
- Implementing retry logic for failed submissions
- Building responsive UIs during proof generation
- Understanding the differences from Ethereum transactions
Key Concepts
Build-Prove-Submit-Confirm Flow
Midnight transactions go through four distinct phases:
- Build: Create transaction with
contract.callTx.*and witness data - Prove: Wallet generates ZK proof via local proof server (seconds)
- Submit: Send proven transaction with
walletAPI.submitTransaction() - Confirm: Wait for finality on the Midnight network
// Complete transaction flow
const tx = await contract.callTx.transfer(recipient, amount, witnesses);
const provenTx = await walletAPI.balanceAndProveTransaction(tx, newCoins);
const txHash = await walletAPI.submitTransaction(provenTx);
// Wait for confirmation...
User Experience Implications
Unlike Ethereum's instant signing, Midnight proof generation takes several seconds. Your UI must:
- Show loading states during proof generation
- Provide progress indicators when possible
- Handle timeouts gracefully
- Support cancellation
- Allow retries on failure
References
| Document | Description |
|---|---|
| transaction-lifecycle.md | Complete transaction flow with state transitions |
| signing-flow.md | Wallet signing and proof generation details |
| confirmation-patterns.md | Polling, finality, and UI update strategies |
| web3-comparison.md | Ethereum transaction patterns vs Midnight |
Examples
| Example | Description |
|---|---|
| submit-transaction/ | Complete transaction submission flow |
| tx-status-tracker/ | Transaction status tracking UI |
| retry-patterns/ | Exponential backoff and retry UI |
Quick Start
1. Build the Transaction
import type { WitnessContext } from "@midnight-ntwrk/midnight-js-types";
// Define witnesses for private data
const witnesses = {
get_secret: ({ privateState }: WitnessContext<PrivateState>): bigint => {
return privateState.secret;
},
};
// Build transaction
const tx = await contract.callTx.transfer(recipient, amount, witnesses);
2. Prove and Submit
// Show loading - this takes several seconds
setStatus("Generating proof...");
// Prove transaction (invokes local proof server)
const provenTx = await walletAPI.balanceAndProveTransaction(tx, newCoins);
// Submit to network
setStatus("Submitting...");
const txHash = await walletAPI.submitTransaction(provenTx);
setStatus("Submitted!");
console.log("Transaction hash:", txHash);
3. Track Status
function useTxStatus(txHash: string | null) {
const [status, setStatus] = useState<TxStatus>("pending");
useEffect(() => {
if (!txHash) return;
const checkStatus = async () => {
// Poll for transaction confirmation
const result = await checkTransaction(txHash);
setStatus(result.status);
};
const interval = setInterval(checkStatus, 3000);
return () => clearInterval(interval);
}, [txHash]);
return status;
}
4. Handle Errors with Retry
async function submitWithRetry(
buildTx: () => Promise<Transaction>,
maxRetries = 3
): Promise<string> {
let lastError: Error | null = null;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const tx = await buildTx();
const provenTx = await walletAPI.balanceAndProveTransaction(tx, newCoins);
return await walletAPI.submitTransaction(provenTx);
} catch (error) {
lastError = error as Error;
// Don't retry user rejection
if (error.message.includes("rejected")) {
throw error;
}
// Exponential backoff
if (attempt < maxRetries) {
await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, attempt)));
}
}
}
throw lastError ?? new Error("Transaction failed");
}
Common Patterns
Transaction State Machine
type TxState =
| { status: "idle" }
| { status: "building" }
| { status: "proving" }
| { status: "submitting" }
| { status: "pending"; txHash: string }
| { status: "confirmed"; txHash: string }
| { status: "failed"; error: Error };
function txReducer(state: TxState, action: TxAction): TxState {
switch (action.type) {
case "START":
return { status: "building" };
case "PROVING":
return { status: "proving" };
case "SUBMITTING":
return { status: "submitting" };
case "SUBMITTED":
return { status: "pending", txHash: action.txHash };
case "CONFIRMED":
return { status: "confirmed", txHash: action.txHash };
case "FAILED":
return { status: "failed", error: action.error };
case "RESET":
return { status: "idle" };
default:
return state;
}
}
Optimistic UI Updates
async function transferWithOptimisticUpdate(
recipient: Uint8Array,
amount: bigint
) {
// Optimistically update UI
const previousBalance = balance;
setBalance((prev) => prev - amount);
try {
const tx = await contract.callTx.transfer(recipient, amount, witnesses);
const provenTx = await walletAPI.balanceAndProveTransaction(tx, newCoins);
await walletAPI.submitTransaction(provenTx);
// Success - optimistic update was correct
} catch (error) {
// Revert optimistic update
setBalance(previousBalance);
throw error;
}
}
Performance Considerations
| Concern | Mitigation |
|---|---|
| Proof generation (5-30s) | Show progress UI, allow cancellation |
| Network latency | Implement retry with exponential backoff |
| Timeout during proof | Set appropriate timeout (60s+), retry on timeout |
| User waits for confirmation | Show pending state, allow background monitoring |
Related Skills
wallet-integration- Wallet connection before transactionsproof-handling- Witness construction and proof generationstate-management- Reading state before/after transactionserror-handling- Transaction error messages and recovery
Related Commands
/dapp-check- Validates transaction provider configuration/dapp-debug transactions- Diagnose transaction submission issues
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?