React hooks and components for detecting — and fixing — silent governance delegation on Cardano.
Some Cardano wallets (notably Yoroi) automatically delegate users' governance voting power to the wallet vendor's own dRep, without informed consent. Yoroi's auto-delegation alone concentrates roughly 7% of all on-chain voting power under a single entity.
Antitrust detects this and gives users an easy path to re-delegate to a dRep of their choice.
npm install @sundaeswap/antitrust
# or
bun add @sundaeswap/antitrustreact>= 18@blaze-cardano/sdk>= 0.2 (needed for transaction building)
import {
AntitrustProvider,
RedelegationBanner,
KoiosQueryProvider,
} from "@sundaeswap/antitrust";
function App({ walletApi, blazeInstance }) {
return (
<AntitrustProvider
walletApi={walletApi}
blazeInstance={blazeInstance}
network="mainnet"
queryProvider={new KoiosQueryProvider("mainnet")}
>
<RedelegationBanner onRedelegate={() => console.log("user wants to redelegate")} />
</AntitrustProvider>
);
}The <RedelegationBanner> automatically checks if the connected wallet is delegated to a targeted dRep (Yoroi's by default) and renders a warning with a call-to-action. If the wallet is not affected, it renders nothing.
Wraps your app (or the relevant subtree) and provides configuration to all hooks and components.
<AntitrustProvider
walletApi={cip30Api} // CIP-30 wallet API (from wallet.enable())
network="mainnet" // "mainnet" | "preview" | "preprod"
blazeInstance={blaze} // Blaze instance (required for transactions)
queryProvider={provider} // Optional — defaults to KoiosQueryProvider
targetDRepIds={[...]} // Optional — dRep IDs to flag (defaults to Yoroi's)
>
{children}
</AntitrustProvider>Checks whether the connected wallet is delegated to one of the targeted dReps.
const { isDelegated, matchedDRepId, status, isLoading, error } = useIsYoroiDelegated();
// status: "loading" | "delegated" | "not-delegated" | "error"Returns the wallet's current dRep delegation info.
const { delegation, isLoading, error, refetch } = useCurrentDRepDelegation();
// delegation: { drepId: string | null, isRegistered: boolean } | nullBuilds, signs, and submits a vote delegation transaction.
const { redelegate, delegateAbstain, delegateNoConfidence, txStatus, txHash, error, reset } =
useRedelegateTx();
// Delegate to a specific dRep
await redelegate("drep1...");
// Or delegate to abstain / no confidence
await delegateAbstain();
await delegateNoConfidence();
// txStatus: "idle" | "building" | "signing" | "submitting" | "submitted" | "error"Paginated list of registered dReps with CIP-119 metadata.
const { dreps, isLoading, error, fetchMore, hasMore } = useDRepList();Drop-in banner that shows a warning when the wallet is auto-delegated.
<RedelegationBanner
onRedelegate={() => openDRepPicker()}
onDismiss={() => setDismissed(true)}
style={customStyle}
buttonStyle={customButtonStyle}
/>Supports a render-prop pattern for full control:
<RedelegationBanner>
{({ isDelegated, onRedelegate }) =>
isDelegated ? <MyCustomBanner onClick={onRedelegate} /> : null
}
</RedelegationBanner>Browsable list of dReps with expandable metadata panels.
<DRepPicker
onSelect={(drep) => redelegate(drep.drepId)}
style={customStyle}
itemStyle={customItemStyle}
expandedStyle={customExpandedStyle}
delegateButtonStyle={customButtonStyle}
/>The library ships with KoiosQueryProvider which queries the Koios API. You can also provide your own by implementing the ChainQueryProvider interface:
interface ChainQueryProvider {
getDelegation(stakeAddress: string): Promise<DelegationInfo>;
listDReps(offset: number, limit: number): Promise<DRepInfo[]>;
}Koios does not set CORS headers for browser requests. In development, proxy requests through your dev server:
// vite.config.ts
export default defineConfig({
server: {
proxy: {
"/koios": {
target: "https://api.koios.rest",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/koios/, ""),
},
},
},
});Then pass the proxy URL to the provider:
new KoiosQueryProvider("mainnet", "/koios/api/v1")A full working example lives in the example/ directory.
# Set your Blockfrost project ID
echo 'VITE_BLOCKFROST_PROJECT_ID=your_id_here' > example/.env
# Run it
bun run examplebun install
bun run build # Build the library
bun run typecheck # Type-check without emitting
bun run dev # Build in watch modeMIT