Skip to content

0xleventis/BEEF

Repository files navigation

Clanker Legacy Rewards

Scan, claim, and swap legacy (v0–v3.1) Clanker creator fees for a given creator address on Base — using Bankr to sign and submit transactions by default, so you never need to export a raw private key (though a local-signer mode is available too — see below).

Background: two independent reward mechanisms

Legacy Clanker tokens can have unclaimed value under either or both of these — they are unrelated, so this tool checks both:

  1. Safe/Merkle mechanism — a contract called ClankerSafeErc20Spender (0x10F4485d6f90239B72c6A5eaD2F2320993D285E4) holds accumulated fees in the token itself (not WETH) for each legacy token, gated by a Merkle-proof-based creator registry built from Clanker's published creator snapshot (bundled with the clanker-sdk npm package). Claiming requires:

    1. initializeTokenCreator(token, newCreator, proof) — a one-time registration per token.
    2. tokenCreatorTransfer(safe, token, recipient) — moves the balance from whichever Safe wallet holds it.

    There's no on-chain registry mapping each token to its Safe, so this repo discovers the correct Safe empirically (see KNOWN_SAFES in scan-legacy-rewards.mjs) by checking which one actually holds a nonzero balance.

  2. Standard LP-fee mechanism — ordinary Uniswap V3 LP trading fees, claimed directly via factory.claimRewards(token) on the v2/v3/v3.1 factory contracts. No init step, but also no way to know the payout in advance — a successful call can still yield exactly zero if nothing has accrued. This mechanism is easy to miss if you only check the Safe balance; a token can show zero there and still have real value here, or vice versa.

What's in here

Script Purpose
scan-legacy-rewards.mjs Read-only. Finds every legacy token recorded for CREATOR_ADDRESS, checks both mechanisms' live on-chain state, computes Merkle proofs, and reports what's actually claimable. No wallet or API key needed.
claim-legacy-rewards.mjs Submits the real claim transactions for both mechanisms found by the scan. Idempotent — safe to re-run, it skips anything already done. Supports Bankr or a local private key.
swap-to-eth.mjs Swaps claimed token balances to ETH via Bankr's Agent API, which routes through Uniswap and — importantly — refuses tokens with no real liquidity rather than executing a near-worthless swap. Bankr-only (no local-signer equivalent).
force-swap.mjs For tokens you've already confirmed are illiquid but still want swapped anyway. Bypasses Bankr's safety check and swaps directly via Uniswap V3 SwapRouter02 with zero slippage protection. Supports Bankr or a local private key. Only use this on tokens you've already verified are effectively worthless — see warning in the file.

Setup

npm install

Option A — Bankr (recommended, no raw private key):

  • Wallet API access, read-write (not the read-only default) — required for claim and force-swap.
  • Agent API access, plus either Bankr Club or LLM credits — required for swap-to-eth.mjs specifically (403 subscription_required otherwise; fall back to force-swap.mjs if you don't have this).

Option B — local private key: set PRIVATE_KEY instead of BANKR_API_KEY for claim-legacy-rewards.mjs / force-swap.mjs. There's no local-signer path for swap-to-eth.mjs (it inherently needs Bankr's agent for liquidity-aware routing) — use force-swap.mjs instead if you're not using Bankr at all.

Never commit a secret or paste it anywhere public. Store it in a local .env file (already gitignored) or an environment variable:

BANKR_API_KEY=bk_your_key_here
# or, for local signing:
PRIVATE_KEY=0xyour_private_key_here

Usage

# 1. Scan (read-only, no key needed) — checks BOTH mechanisms automatically
CREATOR_ADDRESS=0xYourCreatorAddress node scan-legacy-rewards.mjs > final-report.json

# 2. Review final-report.json, then claim everything found
RECIPIENT_ADDRESS=0xYourRecipient BANKR_API_KEY=bk_... node claim-legacy-rewards.mjs
#   ...or with a local key:
RECIPIENT_ADDRESS=0xYourRecipient PRIVATE_KEY=0x... node claim-legacy-rewards.mjs

# 3. Swap claimed tokens to ETH (needs Agent API + Bankr Club/credits)
RECIPIENT_ADDRESS=0xYourRecipient BANKR_API_KEY=bk_... node swap-to-eth.mjs

# 4. If step 3 hits the subscription gate, or for known-illiquid leftovers: force-swap directly
RECIPIENT_ADDRESS=0xYourRecipient BANKR_API_KEY=bk_... node force-swap.mjs

CREATOR_ADDRESS and RECIPIENT_ADDRESS are usually the same wallet, but don't have to be for the Safe mechanism — claim-legacy-rewards.mjs sets RECIPIENT_ADDRESS as both the destination for claimed tokens and the new on-chain creator record. The actual transaction signer must equal RECIPIENT_ADDRESS exactly (whether that's your Bankr wallet or a PRIVATE_KEY's derived address) — the Merkle proof validates against msg.sender, and the script hard-fails if a provided PRIVATE_KEY doesn't match.

Environment variables

Variable Required for Description
CREATOR_ADDRESS scan The 0x address to look up legacy tokens for
RECIPIENT_ADDRESS claim, swap, force-swap Must match the address that actually signs
BANKR_API_KEY claim, force-swap; required for swap Read-write Wallet API access; Agent API + Bankr Club/credits needed for swap-to-eth.mjs specifically
PRIVATE_KEY claim, force-swap (alternative to BANKR_API_KEY) Local signer. Takes priority over BANKR_API_KEY if both are set. No equivalent for swap-to-eth.mjs.
BANKR_API_URL all (Bankr) Defaults to https://api.bankr.bot
RPC_URL all Defaults to https://mainnet.base.org; the public endpoint rate-limits under heavy load, all scripts retry automatically but a private RPC will be faster and more reliable

Important notes

  • Real money moves here. Every step past the scan submits actual on-chain transactions. Read the scripts before running them.
  • The msg.sender on the initializeTokenCreator call must exactly match the address recorded as the token's creator in Clanker's snapshot — the Merkle proof will not validate for any other address, even if you pass a different newCreator.
  • Many legacy tokens are years-old, abandoned meme coins with zero real liquidity. The scan will still report them as claimable under either mechanism if a nonzero balance exists — that doesn't mean the tokens are worth anything.
  • force-swap.mjs sets amountOutMinimum to 0, meaning no slippage or MEV protection. Only use it on tokens you've already confirmed have negligible real liquidity (e.g. by checking a pool's actual paired-asset reserves, not just its liquidity() value, which can look nonzero while holding almost nothing of value).
  • Don't trust an immediate before/after balance diff as proof of "nothing received." Base's public RPC is load-balanced across nodes; a read moments after a transaction can land on a node that hasn't caught up yet and silently return a stale value. This produced real false "zero" reports in practice, on claims that actually delivered large amounts. claim-legacy-rewards.mjs handles this correctly for the LP-fee mechanism: it submits all claims first, waits, then does a separate, heavily-retried absolute-balance pass (verifiedBalanceFormatted in the output) — trust that field, not a same-call diff.
  • Duplicate token symbols across different contract addresses are common among legacy tokens. Always operate by contract address, never by symbol/name.

License

MIT

About

Scan, claim, and swap Clanker legacy (v0-v3.1) creator fees via Bankr's Wallet/Agent API

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages