Install
openclaw skills install element-nft-traderUse when the user wants to sell or buy an NFT on Element, create or accept a bid or offer, query public collection orders or account orders, cancel an Element order, get the configured trading wallet address, or use a supported custom payment token on a supported Element EVM network. Supported custom payment tokens are BSC USDT/USD1, Base USDC, and Polygon ETH. Other chains should use native or wrapped native token flow.
openclaw skills install element-nft-traderUse this skill for Element Market order operations: creating sell orders, buying listed NFTs, creating offers, querying orders, canceling orders, and deriving the configured wallet address.
This skill is for trading actions and order management. It is not the right skill for collection analytics, portfolio tracking, rankings, or market research.
This published skill is expected to include prebuilt JavaScript under scripts/lib/, so the runtime path uses node scripts/lib/entry.js instead of compiling on the user's machine.
Key folders and files in this skill:
scripts/lib/: prebuilt JavaScript runtime files shipped with the skill; use scripts/lib/entry.js as the execution entryscripts/entry.ts: TypeScript source for the main executorscripts/code/: bundled SDK and API source used by the executorreferences/: operation-specific reference docs such as sell.md, buy.md, and payment-tokens.mdThis skill reads the following runtime configuration from environment variables:
ELEMENT_API_KEYELEMENT_WALLET_PRIVATE_KEYExample env setup:
export ELEMENT_API_KEY="your_openapi_key_here"
export ELEMENT_WALLET_PRIVATE_KEY="your_wallet_private_key_here"
This skill signs real blockchain transactions locally. Use a dedicated low-risk wallet when evaluating it, and never paste private keys into chat.
Use this skill when the user wants to:
Switch to element-nft-tracker when the user asks about:
The private key stays local and must never be requested in chat.
For any state-changing operation, the agent must:
The runtime executor also requires confirmed: true for every state-changing operation.
State-changing operations:
erc721sellerc1155sellbuyofferacceptOffercancelRead-only operations:
queryqueryAccountOrdersgetAddressBefore executing any operation, including read-only query operations, ask for all required parameters first.
network or chain0x... value, do not immediately assert that it is an order hash; first confirm the network and whether it is the NFT collection contract address in the current trading flow0x... value is typically an EVM address, not a transaction hash. A transaction hash is typically 66 characters0x... value as the likely NFT contract address unless surrounding context clearly indicates otherwiseBefore interpreting a 0x... value, classify it first:
0x... values are typically EVM addresses0x... values are typically transaction hashescancel, a transaction hash alone is not executable input; you still need the full order object or enough context to retrieve it0x... value, check its length before replying. Do not state a type that you have not verifiedUse this routing before doing anything else:
SellQuery Orders, then BuyOfferQuery Orders with side=0, then Accept OfferQuery OrdersQuery Account OrdersQuery Account Orders, then Query Orders filtered by maker if needed, then Cancelelement-nft-tracker0x... in a trading context -> first ask for the network, then confirm whether that value is the NFT collection contract address for the intended query or order flowAsk for the required parameters first for every operation.
Sell: network, collection address, token ID, priceBuy: network, collection address, then let the user choose from queried ordersOffer: network, collection address, offer price, asset schemaAccept Offer: network, order object, and token ID for collection-wide offersQuery: network, collection addressQuery Account Orders: network, optional wallet_addressCancel: network, order ID or enough context to find the user's orderGetAddress: networkAdditional guidance:
ERC721 or ERC1155; do not guess the schemaexpirationTime unless the user explicitly asked for a custom expiry; omit it and let the SDK default to 7 daysnetwork or chain before executing; never scan all chains by defaultBefore any state-changing action, confirm:
network is explicitly confirmed0x... contract input used as an NFT contract address is a 42-character EVM address, not a transaction hashtokenId for listings, assetId for collection-wide offer acceptance, quantity for ERC1155 when neededoffer, assetSchema is explicitly confirmed as ERC721 or ERC1155paymentToken has been resolved correctly for the selected chain, or omitted intentionallyerc721sell, custom paymentToken is placed inside sellOrderserc1155sell, custom paymentToken is placed inside erc1155sellOrderbuy, acceptOffer, or cancel; do not hand-reconstruct order fieldsPrimary executor:
scripts/entry.ts handles erc721sell, erc1155sell, buy, offer, acceptOffer, query, queryAccountOrders, cancel, and getAddressInvocation pattern:
node scripts/lib/entry.js "$INPUT"
The script accepts JSON either as the first CLI argument or from stdin.
Assistant workflow:
jqscripts/lib/entry.jsUser: Cancel order ID 789
Assistant: [Shows order details] Confirm?
User: CONFIRM CANCEL ORDER
Assistant: Order canceled
User: Show my current NFT listings on Element
Assistant: Which chain do you want to query? For example `base`, `eth`, `bsc`, `polygon`, `linea`, or `arbitrum`
User: base
Assistant: [Queries the current listings on that chain]
User: Query orders for collection 0x123...
Assistant: Which network should I query? For example `base`, `eth`, `bsc`, `polygon`, `linea`, or `arbitrum`
User: base
Assistant: [Queries the orders for that collection on Base]
User: Query order 0xCA3605ca7cffAA27a8D9a9B7E41bcb3c51e590D9
Assistant: Which network should I query? For example `base`, `eth`, `bsc`, `polygon`, `linea`, or `arbitrum`
User: base
Assistant: Is `0xCA3605ca7cffAA27a8D9a9B7E41bcb3c51e590D9` the NFT collection contract address for the query?
amountInWei = amountInToken * (10 ^ decimals)
| Token | Decimals | 1 unit |
|---|---|---|
| ETH, USDT (BSC) | 18 | 1000000000000000000 |
| USDC (Base) | 6 | 1000000 |
Examples:
0.5 ETH = 0.5 * 10^18 = 500000000000000000
100 USDC = 100 * 10^6 = 100000000
For supported custom payment tokens, read payment-tokens.md. The current rule is:
bsc: supports USDT and USD1base: supports USDCpolygon: supports ETHIf the table provides token decimals and the operation is buy, pass them as paymentTokenDecimals instead of relying on runtime detection.
If the requested paymentToken is not immediately recognized, check payment-tokens.md first. Do not guess token addresses or token symbols. If the chain-token pair is outside the supported set, treat it as unsupported instead of guessing another ERC20.
Supported networks come from the SDK and entry script. Commonly used networks include:
eth, bsc, polygon, arbitrum, base, ...
The current implementation supports 27 chains in total.
Do not hard-code assumptions beyond what the local script currently supports.
Element Market collection page format:
https://element.market/collections/[slug]
Do not construct this URL from the contract address directly.
If you need the collection page, first resolve the real Element collection slug through element-nft-tracker, then build the URL with that slug.
When an actual operation is about to be constructed or executed, you must open and follow the matching reference file first. Do not rely on the main skill alone for payload construction.
Each operation now has its own reference file. Use the main skill for routing and global rules, then open only the operation reference you need:
Sell: open sell.md when creating a new listing, including ERC721, ERC1155, or custom payment token listingsQuery Orders: open query-orders.md when browsing public orders, selecting orders to buy, or finding offers to acceptQuery Account Orders: open query-account-orders.md when the user wants the current listings or orders for a specific wallet on a specific chainOffer: open offer.md when creating a collection offer or token-specific bidAccept Offer: open accept-offer.md when filling a buy-side order, especially collection-wide offers that require assetIdBuy: open buy.md when filling sell-side orders returned by queryCancel: open cancel.md when canceling an order using the exact returned order objectGet Wallet Address: open get-address.md when the user wants the configured wallet address for a supported networkExecution rule:
If an operation cannot proceed cleanly, use these fallbacks:
paymentToken is unfamiliar, check payment-tokens.md; do not guesschain + address match from the payment token reference; otherwise show the address instead of guessingassetId, ask for assetId before executionside=0 and saleKind=7, treat the order as a collection-wide offer; do not describe tokenId=0 as a real NFT #0quantity, ask for quantity before executionquery and reuse the exact returned order object0.3 ETH ~= 0.3 USDCBefore executing any state-changing order operation, show a preview like this:
Network: [NETWORK] | Wallet: [WALLET_ADDRESS]
| Field | Value |
|---|---|
| Collection | [COLLECTION_ADDRESS] |
| Element Page | Show only if a real [SLUG] has been resolved through element-nft-tracker |
| Token ID | [TOKEN_ID] if applicable |
| Price | [PRICE] [TOKEN_SYMBOL] |
| Expiration | [EXPIRATION_TIME] |
Notes for the user:
Confirmation format:
CONFIRM [OPERATION] ORDER
Example:
CONFIRM SELL ORDER
Display results based on the returned JSON operation field.
entry.ts already formats listingTime and expirationTime into readable UTC date-time strings in its structured output. Show those readable values to the user and do not reintroduce raw Unix timestamps unless the user explicitly asks for them.
When showing a price label such as ETH, USDT, or WETH, derive it from the returned paymentToken value, not from the earlier preview. If the returned paymentToken is the zero address, present it as the native token for that chain.
erc721sellStatus: success
Succeeded: [N] | Failed: [M]
Succeed list:
| Order ID | Collection | Token | Price | Expires At |
|---|---|---|---|---|
[ORDER_ID] | [CONTRACT] | [TOKEN_ID] | [PRICE] [TOKEN] | [READABLE_EXPIRATION_TIME] |
Failed list:
| Asset | Error |
|---|---|
[CONTRACT]/[TOKEN_ID] | [ERROR] |
erc1155sell| Field | Value |
|---|---|
| Status | success |
| Operation | erc1155sell |
| Order ID | [ORDER_ID] |
| Collection | [CONTRACT] |
| Token ID | [TOKEN_ID] |
| Price | [PRICE] [TOKEN] |
| Payment Token | [PAYMENT_TOKEN] |
| Listed At | [READABLE_LISTING_TIME] |
| Expires At | [READABLE_EXPIRATION_TIME] |
offer| Field | Value |
|---|---|
| Status | success |
| Operation | offer |
| Order ID | [ORDER_ID] |
| Collection | [CONTRACT] |
| Price | [PRICE] [TOKEN] |
| Payment Token | [PAYMENT_TOKEN] |
| Listed At | [READABLE_LISTING_TIME] |
| Expires At | [READABLE_EXPIRATION_TIME] |
acceptOffer| Field | Value |
|---|---|
| Status | `[success |
| Order ID | [ORDER_ID] |
| Maker | [ADDRESS] |
| Collection | [CONTRACT] |
| Token ID | [TOKEN_ID] |
| Schema | [SCHEMA] |
| Quantity | [QUANTITY] |
| Payment Token | [PAYMENT_TOKEN] |
| Proceeds | [PRICE] [TOKEN] |
| Tx Hash | [TX_HASH] |
| Gas Used | [GAS_USED] wei |
| Explorer | View on Explorer |
buy| Field | Value |
|---|---|
| Status | `[success |
| Tx Hash | [TX_HASH] |
| Gas Used | [GAS_USED] wei |
| Explorer | View on Explorer |
Purchased Orders:
| Order ID | Collection | Token ID | Schema | Quantity | Cost |
|---|---|---|---|---|---|
[ORDER_ID] | [CONTRACT] | [TOKEN_ID] | [SCHEMA] | [REQUESTED_QUANTITY] | [COST] [TOKEN] |
cancel| Field | Value |
|---|---|
| Status | success |
| Cancelled | [N] order(s) |
Transactions:
| Hash | Status | Block | Gas | Explorer |
|---|---|---|---|---|
[TX_HASH] | `[success | failed]` | [BLOCK] | [GAS_USED] |
query| Field | Value |
|---|---|
| Status | success |
| Found | [N] order(s) |
Order #1:
| Field | Value |
|---|---|
| Side | `[buy |
| Order ID | [ORDER_ID] |
| Maker | [ADDRESS] |
| Collection | [CONTRACT] |
| Token ID | [TOKEN_ID] |
| Schema | [SCHEMA] |
| Available Quantity | [QUANTITY] |
| Price | [PRICE] [TOKEN] |
| Payment Token | [PAYMENT_TOKEN] |
| Listed At | [READABLE_LISTING_TIME] |
| Expires At | [READABLE_EXPIRATION_TIME] |
queryAccountOrders| Field | Value |
|---|---|
| Status | success |
| Chain | [CHAIN] |
| Using Default Account | `[true |
| Wallet Address | [WALLET_ADDRESS_OR_NULL] |
| Found | [N] order(s) |
Order #1:
| Field | Value |
|---|---|
| Name | [NAME] |
| Collection | [COLLECTION_NAME] |
| Collection Address | [CONTRACT] |
| Token ID | [TOKEN_ID] |
| Side | `[buy |
| Price | [PRICE] |
| Price USD | [PRICE_USD] |
| Standard | [STANDARD] |
| Expires At | [READABLE_EXPIRATION_TIME] |
Display rules:
count > 1, do not present the result as if there were only one ordercountgetAddress| Field | Value |
|---|---|
| Wallet | [ADDRESS] |