Skip to content

SundaeSwap-finance/antitrust

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@sundaeswap/antitrust

React hooks and components for detecting — and fixing — silent governance delegation on Cardano.

The problem

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.

Install

npm install @sundaeswap/antitrust
# or
bun add @sundaeswap/antitrust

Peer dependencies

  • react >= 18
  • @blaze-cardano/sdk >= 0.2 (needed for transaction building)

Quick start

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.

API

<AntitrustProvider>

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>

Hooks

useIsYoroiDelegated()

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"

useCurrentDRepDelegation()

Returns the wallet's current dRep delegation info.

const { delegation, isLoading, error, refetch } = useCurrentDRepDelegation();
// delegation: { drepId: string | null, isRegistered: boolean } | null

useRedelegateTx()

Builds, 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"

useDRepList()

Paginated list of registered dReps with CIP-119 metadata.

const { dreps, isLoading, error, fetchMore, hasMore } = useDRepList();

Components

<RedelegationBanner>

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>

<DRepPicker>

Browsable list of dReps with expandable metadata panels.

<DRepPicker
  onSelect={(drep) => redelegate(drep.drepId)}
  style={customStyle}
  itemStyle={customItemStyle}
  expandedStyle={customExpandedStyle}
  delegateButtonStyle={customButtonStyle}
/>

Query providers

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[]>;
}

CORS note

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")

Example

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 example

Development

bun install
bun run build       # Build the library
bun run typecheck   # Type-check without emitting
bun run dev         # Build in watch mode

License

MIT

About

A small drop-in react component for prompting users to redelegate away from high-concentration dReps

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors