diff --git a/clawmes/lib/chains.py b/clawmes/lib/chains.py index 9b55636..5201f26 100644 --- a/clawmes/lib/chains.py +++ b/clawmes/lib/chains.py @@ -103,6 +103,24 @@ class Chain: block_explorer_url="https://blastscan.io", is_l2=True, ), + 4663: Chain( + chain_id=4663, + name="Robinhood Chain", + short_name="robinhood", + native_symbol="ETH", + native_decimals=18, + block_explorer_url="https://robinhoodchain.blockscout.com", + is_l2=True, + ), + 46630: Chain( + chain_id=46630, + name="Robinhood Chain Testnet", + short_name="robinhood-testnet", + native_symbol="ETH", + native_decimals=18, + block_explorer_url="https://robinhoodchain-testnet.blockscout.com", + is_l2=True, + ), } diff --git a/clawmes/services/clawnch.py b/clawmes/services/clawnch.py index d5ce778..f81eb0e 100644 --- a/clawmes/services/clawnch.py +++ b/clawmes/services/clawnch.py @@ -290,19 +290,25 @@ def prepare_deploy( farcaster: str | None = None, discord: str | None = None, burn_tx_hash: str | None = None, + chain: str | None = None, ) -> dict[str, Any]: - """Get unsigned Clanker factory calldata for a non-custodial deploy. + """Get unsigned factory calldata for a non-custodial deploy. - Hits ``GET /api/prepare/deploy``. Returns the envelope shape: + ``chain`` (``"base"`` or ``"robinhood"``) is forwarded as the + ``chain`` query param to ``GET /api/prepare/deploy``. The server + resolves it into Clanker-vs-Bags calldata. Default is Base. + + Returns the envelope shape: { "ok": True, - "data": {"to": "0xE85A…", "data": "0xdf40224a…", "value": "0x0", "chainId": 8453}, + "data": {"to": "0x…", "data": "0x…", "value": "0x…", "chainId": 8453}, "meta": { "platformFeeBps": 2000, "userFeeBps": 8000, - "vaultPercentage": 0, - "source": "base-mcp", + "vaultPercentage": 0, # 0 on the Robinhood path + "creationFeeWei": "0", # non-zero on Robinhood + "chain": "base" | "robinhood", ... }, } @@ -315,16 +321,15 @@ def prepare_deploy( - No API key required (``/api/prepare/deploy`` is public). - No captcha solving — the wallet signs the deploy tx directly. - The user's wallet pays gas. - - Same 20% platform fee preserved in the rewards array. + - Same 20% platform fee preserved in the rewards array (Base) + or the Bags claimer array (Robinhood). - ``burn_tx_hash`` is **mandatory upstream**: every launch + ``burn_tx_hash`` is **mandatory upstream on Base**. Every launch requires a verified 1,000,000+ $CLAWNCH burn from - ``from_address`` to the dead address within 24h. Calling - without one raises ``ClawnchError`` with - ``code="burn_required"`` (HTTP 402) whose ``meta`` carries - ``minBurnTokens`` + ``burnAddress``. A verified burn also sets - the vault clause baked into the returned calldata (1M = 1%, - up to 10M = 10%). + ``from_address`` to the dead address within 24h; the Robinhood + path doesn't enforce it (Bags doesn't burn). Calling without one + raises ``ClawnchError`` with ``code="burn_required"`` whose + ``meta`` carries ``minBurnTokens`` + ``burnAddress``. """ if not from_address: raise ClawnchError("bad_request", "from_address is required") @@ -354,6 +359,8 @@ def prepare_deploy( params["discord"] = discord if burn_tx_hash: params["burnTxHash"] = burn_tx_hash + if chain: + params["chain"] = chain.lower() # Public endpoint — no auth header sent. body = self._get("/api/prepare/deploy", params=params) diff --git a/clawmes/services/rpc.py b/clawmes/services/rpc.py index 76be2e2..1f4f87e 100644 --- a/clawmes/services/rpc.py +++ b/clawmes/services/rpc.py @@ -57,6 +57,11 @@ 10: "https://mainnet.optimism.io", # Polygon — official public RPC 137: "https://polygon-rpc.com", + # Robinhood Chain — official public RPC. Rate-limited; Alchemy / + # QuickNode / Chainstack / dRPC offer dedicated endpoints on 4663. + 4663: "https://rpc.mainnet.chain.robinhood.com", + # Robinhood Chain Testnet — official public RPC. + 46630: "https://rpc.testnet.chain.robinhood.com", } diff --git a/clawmes/tools/clawnch_fees.py b/clawmes/tools/clawnch_fees.py index f7d30ed..140e2a6 100644 --- a/clawmes/tools/clawnch_fees.py +++ b/clawmes/tools/clawnch_fees.py @@ -8,11 +8,14 @@ far). Uses Clawnch's ``/api/launches?address=…`` endpoint. Claim-side ops aren't implemented here today: Clanker pays creator -rewards via its own LP-fee accumulator (FeeLocker), not via a -launchpad-controlled "claim()" function. Users claim through their -Clanker dashboard or directly against the FeeLocker contract. Once -v2 ships (the ClawnchFactory fork that drops Clanker), we'll revisit -adding a launchpad-orchestrated claim action. +rewards via its own LP-fee accumulator (FeeLocker) on Base, and Bags +pays creator rewards via its own per-token ``BagsFeeShare`` ledger on +Robinhood Chain (the per-token ``claim()`` on the feeShare contract +returned by a Bags launch). Neither flows through Clawnch's HTTP claim +path — Clawnch only reads launch metadata. Users claim through their +Clanker dashboard (Base) or against the token's feeShare contract +(Robinhood). Once v2 ships (the ClawnchFactory fork that drops +Clanker), we'll revisit adding a launchpad-orchestrated claim action. Requires ``CLAWNCH_API_KEY`` for ``my_launches``; ``launch_info`` is public and works without a key. diff --git a/clawmes/tools/clawnch_launch.py b/clawmes/tools/clawnch_launch.py index 2c17602..3fe661a 100644 --- a/clawmes/tools/clawnch_launch.py +++ b/clawmes/tools/clawnch_launch.py @@ -151,14 +151,17 @@ def _normalize_social(value: str, base_url: str) -> str: name="clawnch_launch", toolset="clawmes-defi", description=( - "Deploy a token on Base via the Clawnch launchpad. Clawnch " - "handles the deploy + initial liquidity atomically via the " - "Clanker SDK; the user's wallet signs a captcha challenge to " - "prove identity. Every deploy requires burn_tx_hash — a " - "verified 1,000,000+ $CLAWNCH burn (use /burn to submit one). " - "Supports image + social metadata (twitter / website / " - "telegram / farcaster / discord). Requires CLAWNCH_API_KEY " - "(register an agent with /register_agent)." + "Deploy a token via the Clawnch launchpad. Defaults to Base " + "(via Clanker); use --chain robinhood to launch on Robinhood " + "Chain via Bags.fm. Clawnch handles the deploy + initial " + "liquidity atomically; the user's wallet signs a captcha " + "challenge to prove identity (custodial) or signs the deploy tx " + "directly (non-custodial). Every deploy on Base requires a " + "verified 1,000,000+ $CLAWNCH burn (use /burn to submit one); " + "the Robinhood path currently doesn't enforce a burn. Supports " + "image + social metadata (twitter / website / telegram / " + "farcaster / discord). Requires CLAWNCH_API_KEY (register an " + "agent with /register_agent)." ), schema=_SCHEMA, emoji="\U0001f31f", @@ -202,12 +205,32 @@ def _handle_deploy(args: dict[str, Any]) -> str: bypass = read_str(args, "bypass_tx_hash") or None burn = read_str(args, "burn_tx_hash") or None + # Classic non-custodial prepare path. The API routes chain based on a + # `chain` query param, which we pass through if the caller supplied it. + start_deploy_chain = read_str(args, "chain") or None + try: - result = get_clawnch_service().deploy( - token_params=token_params, - bypass_tx_hash=bypass, - burn_tx_hash=burn, - ) + if start_deploy_chain == "robinhood": + result = get_clawnch_service().prepare_deploy( + from_address=args.get("from_address") or "", + name=name, + symbol=symbol, + description=token_params.get("description"), + image=token_params.get("image"), + twitter=token_params.get("twitter"), + website=token_params.get("website"), + telegram=token_params.get("telegram"), + farcaster=token_params.get("farcaster"), + discord=token_params.get("discord"), + burn_tx_hash=burn, + chain="robinhood", + ) + else: + result = get_clawnch_service().deploy( + token_params=token_params, + bypass_tx_hash=bypass, + burn_tx_hash=burn, + ) except ClawnchError as exc: if exc.code == "burn_required": meta = exc.meta or {} @@ -225,15 +248,21 @@ def _handle_deploy(args: dict[str, Any]) -> str: tx_hash = result.get("txHash") or result.get("tx_hash") token_address = result.get("tokenAddress") or result.get("token_address") - # Desktop UI: Clawnch launches are Base-only, so surface the tx explorer - # link plus Clanker / DexScreener / token-explorer links for the brand-new - # token as clickable Link artifacts. The enrich helpers no-op on missing or - # malformed values, so we call them unconditionally (passive descriptive - # keys — no preview auto-open from the tool itself). + + # Surface the actual chain from the launch response. The clawn.ch API + # returns chainId in `data.chainId` (prepare path) or the deploy + # metadata; default to Base when absent so historical Base launches + # stay Base-tagged. + chain_id = int(result.get("chainId") or result.get("chain_id") or 8453) + + # Desktop UI: surface the tx explorer link + token links for the + # brand-new token as clickable Link artifacts. Passive descriptive + # keys right now — no preview auto-open. enrich helpers no-op on + # missing values. from clawmes.lib.ui_artifacts import enrich_token_links, enrich_tx_links - enrich_tx_links(result, tx_hash=tx_hash or "", chain_id=8453) - enrich_token_links(result, token=token_address or "", chain_id=8453) + enrich_tx_links(result, tx_hash=tx_hash or "", chain_id=chain_id) + enrich_token_links(result, token=token_address or "", chain_id=chain_id) # Desktop UI: render a launch-receipt card and surface its path at the # envelope top level (json_result ``preview=``) so the desktop opens it in