Install
openclaw skills install torchdomainauctionbotDomain lending protocol on Solana. Domains become tokens. Tokens become collateral. Top holder controls the domain. Borrow SOL against your position -- but g...
openclaw skills install torchdomainauctionbotDomains become tokens. Tokens become collateral. Top holder controls the domain.
Every domain has a name. Every name has a price. But who decides that price?
On Torch Market, domains are launched as tokens with bonding curves. The market decides the price. After bonding completes and the token migrates to Raydium, the domain is permanently linked to that token. From that point forward:
This creates something that doesn't exist in traditional domain markets: a continuously-priced, borrowable, liquid domain asset with built-in consequences for overleveraging.
The bot in this kit runs the infrastructure side. It discovers promising domains, launches them as tokens, monitors all active lending positions, and liquidates underwater loans through a Torch Vault. When a liquidation happens, the domain automatically rotates.
A domain is launched as a Torch Market token. The bonding curve creates the initial market — early buyers get a lower price, the curve rises as demand increases. This is the price discovery phase.
domain "pixel.art" → token PIXEL → bonding curve → market cap grows
Anyone can buy in. The curve sets the price. Trading fees flow to the community treasury.
When the bonding curve completes, the token migrates to a Raydium liquidity pool. At this point, the domain is permanently linked to the token. There is no delisting, no expiry, no central authority. The token IS the domain.
After migration, Torch's built-in lending market activates. Any holder can lock their tokens as collateral and borrow SOL from the community treasury.
holder locks 10,000 PIXEL tokens → borrows 0.5 SOL → LTV = 40%
The loan accrues 2% interest per epoch (~weekly). As long as the loan stays healthy (LTV < 65%), the borrower keeps their position and their domain control.
If the token price drops or interest accrues enough to push LTV past 65%, the position becomes liquidatable. A keeper (this bot) pays off the debt using vault SOL and receives the borrower's collateral tokens at a 10% discount.
PIXEL price drops → LTV hits 68% → keeper liquidates → collateral moves to vault
→ top holder changes
→ domain lease rotates
The borrower loses their tokens. The domain rotates to whoever is now the largest holder. The keeper's vault profits from the 10% bonus.
This is the key insight: liquidation has real consequences beyond money. The borrower doesn't just lose capital — they lose control of the domain. This natural tension makes the lending market meaningful. Borrowers are incentivized to maintain healthy positions because the domain itself is at stake.
┌─────────────────────────────────────────────────────────────────┐
│ DOMAIN AUCTION BOT │
│ │
│ DISCOVER │
│ scrape expiring domains → evaluate quality → generate tickers │
│ │
│ LAUNCH │
│ buildCreateTokenTransaction → bonding curve → domain = token │
│ │
│ MONITOR │
│ for each domain token: │
│ scan lending markets (getLendingInfo) │
│ discover borrowers (getHolders → getLoanPosition) │
│ profile wallets (SAID verification, trade history) │
│ score risk (LTV proximity, momentum, wallet, interest) │
│ │
│ LIQUIDATE │
│ if position.health === 'liquidatable' && risk > threshold: │
│ buildLiquidateTransaction(vault = creator) │
│ sign with agent keypair → submit → confirm │
│ │
│ ROTATE │
│ after liquidation or any holder change: │
│ check top holder → update domain lease │
│ │
│ All SOL from vault. All collateral to vault. Agent holds nothing. │
└─────────────────────────────────────────────────────────────────┘
The bot runs a continuous loop:
The bot generates a fresh Keypair in-process on every startup. No private key file needed. The keypair is disposable — it signs transactions but holds nothing of value (~0.01 SOL for gas).
On first run, the bot verifies vault linkage. If the agent isn't linked, it prints instructions:
=== torch domain auction bot ===
agent wallet: 7xK9...
vault creator: 4yN2...
scan interval: 60000ms
--- ACTION REQUIRED ---
agent wallet is NOT linked to the vault.
link it by running (from your authority wallet):
buildLinkWalletTransaction(connection, {
authority: "<your-authority-pubkey>",
vault_creator: "4yN2...",
wallet_to_link: "7xK9..."
})
then restart the bot.
-----------------------
All economic activity routes through a Torch Vault:
| Direction | What Happens |
|---|---|
| Liquidation: SOL out | Vault SOL pays off the borrower's debt |
| Liquidation: tokens in | Borrower's collateral tokens go to vault ATA at 10% discount |
| Net per liquidation | Vault receives collateral worth 110% of SOL spent |
| Domain rotation | Collateral changes hands → top holder changes → lease rotates |
The human principal retains full control:
If the agent keypair is compromised, the attacker gets dust and vault access you revoke instantly.
npm install torch-domain-auction-bot@2.0.1
From your authority wallet:
import { Connection } from "@solana/web3.js";
import { buildCreateVaultTransaction, buildDepositVaultTransaction } from "torchsdk";
const connection = new Connection(process.env.SOLANA_RPC_URL);
// Create vault
const { transaction: createTx } = await buildCreateVaultTransaction(connection, {
creator: authorityPubkey,
});
// sign and submit...
// Fund with SOL for liquidations
const { transaction: depositTx } = await buildDepositVaultTransaction(connection, {
depositor: authorityPubkey,
vault_creator: authorityPubkey,
amount_sol: 5_000_000_000, // 5 SOL
});
// sign and submit...
VAULT_CREATOR=<vault-creator-pubkey> SOLANA_RPC_URL=<rpc-url> npx torch-domain-auction-bot monitor
First run prints the agent wallet. Link it from your authority wallet, restart.
| Variable | Required | Default | Description |
|---|---|---|---|
SOLANA_RPC_URL | Yes | -- | Solana RPC endpoint. Fallback: BOT_RPC_URL |
VAULT_CREATOR | Yes | -- | Vault creator pubkey |
SOLANA_PRIVATE_KEY | No | -- | Agent keypair (base58 or JSON). Omit to generate fresh on startup |
BOT_SCAN_INTERVAL_MS | No | 60000 | Scan cycle interval (min 5000) |
BOT_SCORE_INTERVAL_MS | No | 15000 | Score cycle interval |
BOT_MIN_PROFIT_LAMPORTS | No | 10000000 | Min profit to liquidate (0.01 SOL) |
BOT_RISK_THRESHOLD | No | 60 | Min risk score to liquidate (0-100) |
BOT_PRICE_HISTORY_DEPTH | No | 20 | Price snapshots to retain |
BOT_LOG_LEVEL | No | info | debug, info, warn, error |
packages/
└── kit/ Domain auction kit (bot + scraper)
├── src/
│ ├── index.ts Entry — vault verification, CLI, all exports
│ ├── config.ts Env validation, ephemeral keypair
│ ├── monitor.ts Scan loop (scan → score → liquidate → rotate)
│ ├── scanner.ts Lending market discovery
│ ├── liquidator.ts Vault-routed liquidation
│ ├── risk-scorer.ts Four-factor risk scoring
│ ├── wallet-profiler.ts SAID + trade history analysis
│ ├── launcher.ts Domain token creation
│ ├── domain-manager.ts Lease tracking + rotation
│ ├── ticker.ts Symbol generation
│ ├── logger.ts Structured logging (shared across all modules)
│ ├── types.ts All type definitions
│ ├── utils.ts Helpers + base58 decoder
│ └── scraper/ Domain discovery pipeline
│ ├── index.ts CLI entry, pipeline orchestration
│ ├── scanner.ts Domain scanning orchestrator
│ ├── evaluator.ts Scores domain quality
│ ├── ticker.ts Generates token symbols
│ ├── config.ts Scraper config
│ ├── types.ts Scraper types (re-exports LogLevel from parent)
│ └── providers/ Data sources (expiring domains, availability)
└── tests/
├── setup.ts Shared test helpers (Surfpool)
├── test_bot.ts Bot E2E tests
└── test_scraper.ts Scraper unit tests
clawhub/
├── agent.json Manifest
├── SKILL.md This file
├── design.md Architecture and design
├── audit.md Security audit
└── lib/
├── kit/ Compiled kit output (tsconfig outDir)
└── torchsdk/ Bundled SDK source
This kit demonstrates a composable pattern using Torch Market:
┌──────────────┐
│ DOMAIN │
│ (pixel.art) │
└──────┬───────┘
│ launch
▼
┌──────────────┐
│ TOKEN │
│ (PIXEL) │ ← bonding curve → migration → permanent
└──────┬───────┘
│ hold
▼
┌──────────────┐
│ COLLATERAL │
│ (lock tokens)│ ← borrow SOL against domain position
└──────┬───────┘
│ borrow
▼
┌──────────────┐
│ LOAN │
│ (SOL debt) │ ← 2% weekly interest, 65% liquidation threshold
└──────┬───────┘
│ if underwater
▼
┌──────────────┐
│ LIQUIDATION │
│ (keeper bot)│ ← vault pays debt, receives collateral at 10% bonus
└──────┬───────┘
│ collateral moves
▼
┌──────────────┐
│ ROTATION │
│ (new holder)│ ← top holder changes → domain lease updates
└──────────────┘
Each step uses a different piece of Torch's infrastructure:
Other builders can use this pattern for any asset class — not just domains. NFTs, real-world assets, prediction markets, governance tokens. The pattern is: tokenize → lend → liquidate → rotate control.
| Property | Guarantee |
|---|---|
| Full custody | Vault holds all SOL and collateral. Agent holds nothing. |
| Closed loop | Liquidation SOL from vault, collateral tokens to vault. No leakage. |
| Authority separation | Creator (PDA seed) vs Authority (admin) vs Controller (disposable signer). |
| Instant revocation | Authority unlinks agent in one transaction. |
| Authority-only withdrawals | Agent cannot extract value from the vault. |
| Parameter | Value |
|---|---|
| Max LTV | 50% |
| Liquidation Threshold | 65% |
| Interest Rate | 2% per epoch (~weekly) |
| Liquidation Bonus | 10% |
| Utilization Cap | 50% of treasury |
| Min Borrow | 0.1 SOL |
| Function | Purpose |
|---|---|
getTokens({ status: 'migrated' }) | Discover domain tokens |
getToken(mint) | Token detail (price, metadata) |
getLendingInfo(mint) | Lending market state |
getHolders(mint) | Token holders (potential borrowers) |
getLoanPosition(mint, wallet) | Loan health check |
getVault(creator) | Verify vault exists |
getVaultForWallet(wallet) | Verify agent linked |
buildLiquidateTransaction(params) | Vault-routed liquidation |
buildCreateTokenTransaction(params) | Launch domain token |
verifySaid(wallet) | Borrower reputation check |
The kit makes outbound HTTPS requests to the following services. The bot's runtime path contacts five of them. No credentials are sent to any external service. All requests are read-only GETs/HEADs. No private key material is ever transmitted to any external endpoint. If any service is unreachable, the bot degrades gracefully (catches errors, continues to next token or cycle).
| Service | URL | Purpose | Data Sent |
|---|---|---|---|
| ExpiredDomains.net | https://www.expireddomains.net/domain-name-search/ | Scrape expiring domain listings | None (GET, User-Agent header only) |
| RDAP | https://rdap.org/domain/{name}.{tld} | Check domain availability (404 = available) | Domain name in URL (public) |
| Service | URL | Purpose | Data Sent |
|---|---|---|---|
| Solana RPC | User-provided SOLANA_RPC_URL | All on-chain reads and transaction submission | Public keys, signed transactions |
| CoinGecko | https://api.coingecko.com/api/v3/simple/price | SOL/USD price for token valuations | None (GET only) |
| SAID Protocol | https://api.saidprotocol.com/api/verify/{wallet} | Wallet reputation / trust verification | Wallet address (public key, not sensitive) |
| Irys Gateway | https://gateway.irys.xyz/... | Token metadata retrieval (fallback) | None (GET only) |
The vault is the security boundary, not the key.
The agent keypair is generated fresh on every startup with Keypair.generate(). It holds ~0.01 SOL for gas fees. If the key is compromised, the attacker gets:
The agent never needs the authority's private key. The authority never needs the agent's private key. They share a vault, not keys.
All SDK calls are wrapped with a 30-second timeout (withTimeout in utils.ts). A hanging or unresponsive RPC endpoint cannot stall the bot indefinitely — the call rejects, the error is caught by the scan loop, and the bot continues to the next token or cycle.
Requires Surfpool mainnet fork:
surfpool start --network mainnet --no-tui
cd packages/kit && pnpm test:bot
cd packages/kit && pnpm test:scraper
Bot tests (10 passing): borrower creation, scanner, wallet profiler, risk scorer, liquidator (skip healthy), price history, lending info, cleanup. Scraper tests: ticker generation, domain evaluation, scanner integration with mock providers.
Traditional domain markets are opaque. Prices are set by registrars or private negotiation. There's no liquidity — you buy a domain and it sits in your account until you sell it.
This kit turns domains into liquid, borrowable, continuously-priced assets. The market sets the price. Anyone can buy in. Holders can extract liquidity without selling. And if they overleverage, the domain rotates to someone who values it more.
That's the power of composing Torch's primitives: bonding curves, lending markets, vaults, and liquidation keepers — working together as a single coherent system.
lib/torchsdk/8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeTbuildBuyTransaction now returns optional migrationTransaction), vault-routed Raydium CPMM swaps (buildVaultSwapTransaction), Token-2022 fee harvesting (buildHarvestFeesTransaction, buildSwapFeesToSolTransaction), bulk loan scanning (getAllLoanPositions), on-chain token metadata queries (getTokenMetadata), and ephemeral agent keypair factory (createEphemeralAgent).name/required format for compatibility with ClawHub and OpenClaw agent runners.