// AUTO-GENERATED by scaffold-stacks. DO NOT EDIT.
// Re-run `stacksdapp generate` to update.
"use client";
import { useState, useCallback, useEffect } from 'react';
import { ClarityValue } from '@stacks/transactions';
import * as contracts from './contracts';
import { scaffoldConfig } from '../scaffold.config';
type TxLifecycleStatus = 'pending' | 'success' | 'abort_by_response' | 'error';
{% for contract in contracts %}
{% for fn in contract.functions %}
{% if fn.access == "public" or fn.access == "read_only" %}
export function use{{ contract.contract_name | upper_camel }}_{{ fn.name | upper_camel }}() {
const [data, setData] = useState<unknown>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
const [txid, setTxid] = useState<string | null>(null);
const [txStatus, setTxStatus] = useState<TxLifecycleStatus | null>(null);
const [txStatusError, setTxStatusError] = useState<string | null>(null);
const isReadOnly = {% if fn.access == "read_only" %}true{% else %}false{% endif %};
const call = useCallback(async (functionArgs: ClarityValue[] = []) => {
setLoading(true);
setError(null);
setTxid(null);
setTxStatus(null);
setTxStatusError(null);
try {
// Use the generated contract function from the index
const fn = (contracts as any).{{ contract.contract_name | camel }}_{{ fn.name | camel }};
const result = isReadOnly
? await fn(functionArgs)
: await fn(functionArgs, []); // Default empty post-conditions for public
if (!isReadOnly && result?.txid) {
setTxid(result.txid);
setTxStatus('pending');
}
setData(result ?? null);
return result;
} catch (e) {
console.error(e);
setError(e as Error);
throw e; // Re-throw so the caller can handle it if needed
} finally {
setLoading(false);
}
// Dependency array is stable because isReadOnly is a constant literal
}, [isReadOnly]);
useEffect(() => {
if (isReadOnly || !txid || !scaffoldConfig.nodeUrl) return;
let mounted = true;
let timer: ReturnType<typeof setTimeout> | null = null;
const headers: Record<string, string> = {};
if (scaffoldConfig.hiroApiKey) {
headers['x-api-key'] = scaffoldConfig.hiroApiKey;
}
const poll = async () => {
try {
const response = await fetch(
`${scaffoldConfig.nodeUrl}/extended/v1/tx/${txid}`,
{
headers,
cache: 'no-store',
},
);
if (!response.ok) {
throw new Error(`tx status request failed with ${response.status}`);
}
const payload = await response.json();
const status = String(payload?.tx_status ?? '').toLowerCase();
if (!mounted) return;
if (status.includes('success')) {
setTxStatus('success');
setTxStatusError(null);
return;
}
if (status.includes('abort')) {
setTxStatus('abort_by_response');
setTxStatusError(String(payload?.tx_result?.repr ?? 'Transaction aborted.'));
return;
}
if (status.includes('pending')) {
setTxStatus('pending');
timer = setTimeout(() => {
void poll();
}, 2500);
return;
}
setTxStatus('error');
setTxStatusError(payload?.tx_status ? `Unexpected tx status: ${payload.tx_status}` : 'Unknown tx status.');
} catch (err) {
if (!mounted) return;
setTxStatusError(err instanceof Error ? err.message : 'Failed to poll transaction status.');
timer = setTimeout(() => {
void poll();
}, 4000);
}
};
void poll();
return () => {
mounted = false;
if (timer) clearTimeout(timer);
};
}, [isReadOnly, txid]);
const explorerUrl = txid
? `${scaffoldConfig.explorerBaseUrl}${txid}${scaffoldConfig.explorerChainQuery}`
: null;
return { data, loading, error, txid, txStatus, txStatusError, explorerUrl, call };
}
{% endif %}
{% endfor %}
{% endfor %}