Execute ATX trading and wallet workflows on BSC. This skill is designed for
agents that need safe, repeatable commands for wallet management, ATX/USDT
quotes, swaps, V3 liquidity actions, and transfers.
atxswap-sdk on npm (source)~/.config/atxswap/keystore (fixed, not configurable)~/.config/atxswap/ (master.key + secrets.json)query.js), quotes, and arbitrary ERC20 token infoThis skill ships its own Node scripts and depends on atxswap-sdk.
SKILL.md is installed.npm install there before using any script.npm install fails, stop and report the dependency error instead of guessing.If the skill is installed via ClawHub or OpenClaw CLI, the install location is
typically ~/.clawhub/skills/atxswap/ (or the equivalent client-managed path).
If you cloned this repository directly, the location is skills/atxswap/.
Use the skill directory path to locate scripts. If ${SKILL_DIR} is available
(injected by skills.sh-compatible runtimes), use it; otherwise use the absolute
path to this skill's installed directory.
Example:
cd skills/atxswap && npm install
cd "${SKILL_DIR}" && node scripts/wallet.js list
All examples below use cd "${SKILL_DIR}" && for clarity. If your runtime does
not inject ${SKILL_DIR}, replace it with the absolute path of the installed
skill directory.
BSC_RPC_URL is optional and supports comma-separated values for fallback, e.g. BSC_RPC_URL="https://primary,https://backup1,https://backup2". When
unset, scripts use a built-in fallback list of 6 BSC public RPC endpoints
and viem will retry them in order.
~/.config/atxswap/keystore.~/.config/atxswap/ (master.key + secrets.json). exists, wallet.js create fails.
wallet.js list before creating a wallet.user asks to import a private key, refuse and tell them to use a dedicated
wallet tool of their choice.
wallet.js export prints the address'sencrypted MetaMask-compatible keystore V3 JSON to stdout (or writes it
to a file via --out ); it never prints the raw private key.
query.js quote can return a JSON error if the configured Quoter or RPCrejects the simulation. Surface the error and do not proceed to a write.
fresh on-chain data at request time. Do NOT answer from prior chat
output, memory, cached numbers, or earlier command results unless you rerun
the relevant query first.
First run liquidity.js quote-add or use liquidity.js add --base-token ... --amount ...
so the script computes the counter-asset from the live pool price and range.
When the user asks to create a wallet:
--password to the script when running non-interactively.the user who requested the wallet.
For swap, transfer, and liquidity operations, rely on auto-unlock
first. Only ask for the password if auto-unlock fails.
If the user says they forgot the wallet password or asks to recover it, first
explain that saved wallet passwords are encrypted at rest in the local
SecretStore (for example Keychain, Secret Service, or the file backend under
~/.config/atxswap/) and are not stored by the agent in chat memory. Even if
the user confirms, do not print the password in chat; guide them to use a
trusted local workflow instead.
or positions as appropriate.
before swap, transfer, or liquidity writes.
wallet.js export only emits the **encrypted MetaMask-compatible keystoreJSON**, never the raw private key. There is no command that prints the
unencrypted private key, and the agent must not attempt to derive or display
one.
wallet.js export --out and tell the user the filepath. Avoid pasting the keystore JSON itself into chat unless the user
explicitly asks for it.
material, ALWAYS remind the user to export and back up the encrypted
keystore first. Do not delete anything until the user explicitly confirms
that the keystore backup has been completed.
confirmed, require the user to send the exact phrase force delete wallet before
running any delete command.
immediately. First ask whether they want to receive the encrypted keystore
backup. Only after the user agrees may you export and send the keystore to
the user.
send the encrypted keystore backup to the user who requested the wallet,
and clearly label it as keystore backup material.
session request. NEVER send the keystore through any channel that is not
under that user's own control.
It may only be sent to the user personally, and must not be pasted into any
external form or sent to any other person, group, agent, or service.
wallet.js create succeeds, export and send the encrypted keystoreto the user who requested the wallet. Treat this as part of the wallet
creation handoff, but only to that user.
that the password is encrypted in local secure storage and must not be
disclosed in chat. Do not attempt to print, derive, or expose the password
even after user confirmation.
refuse. Offer wallet.js export --out as the only
supported backup path, because it exports an encrypted keystore instead of
exposing the raw private key.
(asset, from, to, amount) as a singletransfer intent. Repeat that exact tuple back to the user before execution.
txHash, consider that transfer intentalready sent. Do NOT send the same transfer again unless the user
explicitly asks to send it again.
dropped connection, or partial output after signing/submission), do NOT
retry blindly. First check chain state or wallet state, summarize what is
known, and ask the user whether to retry.
successful or ambiguous prior attempt, pause and ask whether the user means
a new transfer or is referring to the earlier one.
pending fees, or wallet assets, rerun the matching read command against the
chain first. Never rely on previously displayed numbers as if they were
still current.
Before every write action:
For transfers, the summary in step 2 must explicitly include:
After step 5, if a txHash is available, treat the transfer as executed and do
not issue the same write again unless the user clearly requests a second send.
For read-only asset questions:
query.js balance, query.js positions, query.js price, or query.js quote as appropriate).
reusing older numbers.
cd "${SKILL_DIR}" && node scripts/query.js price
cd "${SKILL_DIR}" && node scripts/query.js balance <address>
cd "${SKILL_DIR}" && node scripts/query.js positions <address>
cd "${SKILL_DIR}" && node scripts/query.js positions <address> <tokenId>
cd "${SKILL_DIR}" && node scripts/query.js quote <buy|sell> <amount>
cd "${SKILL_DIR}" && node scripts/swap.js buy <usdtAmount> [--from address] [--slippage bps] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/liquidity.js add <atxAmount> <usdtAmount> [range opts] [--from address] [--slippage-bps n] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/liquidity.js add --base-token <atx|usdt> --amount <n> [range opts] [--from address] [--slippage-bps n] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/transfer.js atx <to> <amount> [--from address] [--password <pwd>]
wallet.jscd "${SKILL_DIR}" && node scripts/wallet.js create [name] --password <pwd>
cd "${SKILL_DIR}" && node scripts/wallet.js list
cd "${SKILL_DIR}" && node scripts/wallet.js export <address> [--out <file>]
cd "${SKILL_DIR}" && node scripts/wallet.js has-password <address>
cd "${SKILL_DIR}" && node scripts/wallet.js forget-password <address>
cd "${SKILL_DIR}" && node scripts/wallet.js delete <address> --backup-confirmed yes --force-phrase "force delete wallet"
After wallet.js create:
wallet.js export [--out ] .Before wallet.js delete:
force delete wallet.wallet.js delete --backup-confirmed yes --force-phrase "force delete wallet".If the user asks to back up the wallet:
wallet.js export [--out ] .query.jscd "${SKILL_DIR}" && node scripts/query.js price
cd "${SKILL_DIR}" && node scripts/query.js balance <address>
cd "${SKILL_DIR}" && node scripts/query.js quote <buy|sell> <amount>
cd "${SKILL_DIR}" && node scripts/query.js positions <address>
cd "${SKILL_DIR}" && node scripts/query.js positions <address> <tokenId>
cd "${SKILL_DIR}" && node scripts/query.js token-info <tokenAddress>
query.js positions includes principal token amounts in the position (principalAtx,
principalUsdt, principal0, principal1) computed from V3 liquidity (L), ticks (internal),
and the pool’s current sqrtPriceX96 (same getAmountsForLiquidity math as the web app). It emits
human USDT-per-ATX bounds as priceRangeUsdtPerAtx.min / .max, currentPriceUsdtPerAtx,
and currentPriceInRange (whether the pool tick lies inside that position). It includes
pendingFees.atx and pendingFees.usdt as the simulated collect notionals (collectable*),
plus raw tokensOwed0/1 and collectable0/1 for debugging. Use collectable* / pendingFees
to decide whether a fee harvest is worth executing. Each object also includes feePercent
(e.g. "0.25%") for the pool’s swap-fee tier; raw fee stays the on-chain code
(100 / 500 / 2500 / 10000). Tick indices are not included in the JSON — quote
USDT/ATX prices and in-range state instead.
When the user asks "how much do I have now", "what is my current balance", "what
positions are left", "how much ATX is still in the LP", or similar present-tense
questions, rerun query.js balance and/or query.js positions immediately.
Do not answer from previously captured JSON.
Required agent reply for holdings when the user asks about their positions, LP NFTs, or liquidity holdings (per position):
Run query.js positions (omit tokenId to list all ATX/USDT V3 NFTs). The CLI prints
one JSON object per NFT; include every position. For each position, the answer must
address the topics below (label them in the user’s language when replying). Do not show raw
V3 tick numbers to the user — use USDT per 1 ATX from the JSON below.
| Topic | What to include | CLI JSON fields |
|---|---|---|
| ------- | ----------------- | ----------------- |
| Tokens in the position | In-range liquidity as ATX and USDT notionals — always cite principalAtx and principalUsdt (and optionally principal0 / principal1 in pool token0/token1 order). These are computed at the current pool price. Mention liquidity only as the raw L scalar if explaining detail. Do not treat query.js balance as LP “position tokens”: wallet ATX/USDT/BNB balances are unrelated to NFT principal — if shown, label them distinctly (e.g. “Wallet balances, separate from this LP NFT”). | |
| NFT token ID | The V3 LP NFT id | tokenId |
| Pool swap fee tier | The pool’s trading fee as a percentage for end users | Prefer feePercent (e.g. "0.25%"). If you show the raw tier code, pair it with feePercent (e.g. 2500 + 0.25%). |
| Price range & spot | Configured min/max USDT per 1 ATX for the position, and current pool price in the same unit | priceRangeUsdtPerAtx.min, priceRangeUsdtPerAtx.max, currentPriceUsdtPerAtx, currentPriceInRange (confirm “in range” / “out of range” in natural language). |
| Pending fees | Uncollected fees (both tokens) | Always show pendingFees.atx and pendingFees.usdt explicitly. Prefer these over quoting only one asset. Optionally reference collectableAtx/collectableUsdt synonyms. State fees stay pending until liquidity.js collect. |
Do not answer with only raw pool indices (ticks). If there are no positions, relay No ATX/USDT positions found. exactly.
Minor mismatch vs on-chain bookkeeping can occur because principal* uses the same float-based
tick→√P path as other tooling (~wei-level); values are intended for humans and routing, not audits.
swap.jscd "${SKILL_DIR}" && node scripts/swap.js buy <usdtAmount> [--from address] [--slippage bps] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/swap.js sell <atxAmount> [--from address] [--slippage bps] [--password <pwd>]
liquidity.jsadd — price / tick range (same USDT/ATX semantics as the web app; default full range = full-width liquidity):
--full-range: explicit full range (do not combine with the two groups below).--min-price / --max-price: band in USDT per 1 ATX; the script reads pool token0 and maps to tickLower / tickUpper like the app (token1/token0 + tickSpacing). Both prices are required.--range-percent: band around current ATX price as a percentage; e.g. 20 means about -20% to +20% of the current price.--tick-lower / --tick-upper: raw V3 ticks (both required; script uses the smaller as lower, larger as upper, clamped to valid V3 bounds).quote-add : given live price and range, estimate the other leg — use before a write.add --base-token --amount : single-sided notional; script computes the other leg and executes the add.Optional: --slippage-bps (0–10000; default from SDK).
cd "${SKILL_DIR}" && node scripts/liquidity.js quote-add <atx|usdt> <amount> [range opts]
cd "${SKILL_DIR}" && node scripts/liquidity.js add <atxAmount> <usdtAmount> [range opts] [--from address] [--slippage-bps n] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/liquidity.js add --base-token <atx|usdt> --amount <n> [range opts] [--from address] [--slippage-bps n] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/liquidity.js remove <tokenId> <percent> [--from address] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/liquidity.js collect <tokenId> [--from address] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/liquidity.js burn <tokenId> [--from address] [--password <pwd>]
liquidity.js remove already uses a single multicall:
decreaseLiquidity -> collect -> and when percent = 100, burn.
That means a full removal automatically collects withdrawable funds and destroys the LP NFT in the same transaction, so
running collect again for the same tokenId is expected to fail because the position no longer exists.
Before collect, preview the target position with:
cd "${SKILL_DIR}" && node scripts/query.js positions <address> <tokenId>
Prefer pendingFees / collectableAtx / collectableUsdt over relying on tokensOwed0/1 alone when deciding whether
fees are available, because the raw tokensOwed fields may stay at zero while
collect() can still succeed.
Example (not full-range; align the range with the user using query.js price before writes):
cd "${SKILL_DIR}" && node scripts/liquidity.js quote-add usdt 0.1 --range-percent 20
cd "${SKILL_DIR}" && node scripts/liquidity.js add --base-token usdt --amount 0.1 --range-percent 20 --from <address>
cd "${SKILL_DIR}" && node scripts/liquidity.js add 10 1 --min-price 0.05 --max-price 0.15
cd "${SKILL_DIR}" && node scripts/liquidity.js add 10 1 --tick-lower -20000 --tick-upper 1000
Mapping user phrasing to commands:
quote-add usdt 0.1 --range-percent 20.
estimatedAmounts (or equivalent summary) and wait for confirmation. add --base-token usdt --amount 0.1 --range-percent 20 --from .
transfer.jscd "${SKILL_DIR}" && node scripts/transfer.js bnb <to> <amount> [--from address] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/transfer.js atx <to> <amount> [--from address] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/transfer.js usdt <to> <amount> [--from address] [--password <pwd>]
cd "${SKILL_DIR}" && node scripts/transfer.js token <tokenAddress> <to> <amount> [--from address] [--password <pwd>]
Transfer anti-duplication checklist:
(asset, from, to, amount) to the user.transfer.js once.txHash.you clarify whether they want a second transfer.
rerun it automatically; inspect chain state or ask the user how to proceed.
material before confirming that the encrypted keystore has been backed up
force delete walletcontrol, or to anyone other than the user
npm install has not been run successfully in the skill directoryFor any write action:
共 3 个版本