okx-growth-competition
此技能专为OKX Agentic Wallet用户设计,提供独家交易竞赛的全生命周期管理。用户可以轻松发现、查看规则、加入竞赛、进行交易、查询排名并领取奖励。它简化了Web3交易竞赛的参与流程,确保用户不错过任何赢取奖励的机会,提升交易体验和效率。
npx skills add https://github.com/okx/onchainos-skills --skill okx-growth-competitionBefore / After 效果对比
1 组在没有智能体辅助的情况下,用户需要手动浏览多个页面,核对竞赛规则、交易资格、实时排名,并手动执行奖励领取操作,整个过程耗时且容易遗漏重要信息,平均每次竞赛需花费约60分钟。
通过智能体,用户只需简单指令即可完成竞赛发现、规则查看、参与、排名查询及奖励领取。智能体自动跟踪进度并提供提醒,将每次竞赛的管理时间大幅缩短至约5分钟,显著提升参与效率和体验。
OKX Growth Competition — Trading Competition
Agentic Wallet exclusive trading competitions. Full lifecycle: list → detail → join → trade → rank → claim.
CLI reference: references/cli-reference.md
Facts about every Agentic Wallet competition (always true unless backend confirms otherwise)
chainId— single id. A trading chain AND the claim/reward chain (rewards are paid on this chain; its contract address is here).participateChainIds— array of ids returned by bothlistanddetailendpoints (may be empty on activities created before the field was added). Additional trading chains (no claim role).
The full trading-chain set for an activity is the UNION: {chainId} ∪ participateChainIds. Trades on any chain in that union count toward the same competition standing. The claim chain is chainId only.
- The trading-chain set is
{chainId} ∪ participateChainIds(dedup). Render each id as a human-readable name via the canonicalChain id → display nametable. Currently supported competition chains:1 → Ethereum,196 → X Layer,501 → Solana. - Trades on any chain in the union count toward the same competition standing. Trades on chains NOT in the union do not count. Never tell a user "your chain doesn't count" without first checking the union.
myRankInfo.userTotal = 0means the user has not yet hit the qualifying threshold or the backend metric pipeline has not picked up their trades yet — it does NOT mean the user's chain is unsupported.competition_ranktakes a single optionalwallet. Omit it for self-rank — the tool auto-resolves the chain-appropriate address from the active account based oncompetition_detail.chainId(the primary chain used for reward claim and rank indexing). Pass an explicit address ONLY when querying someone else's rank; the address chain (EVM0x...else Solana) must match the activity's primary chain or the tool rejects the call (no silent wrong-chain queries). The chain you query on is just a lens — trades on every other chain in the union still count toward the same ranking.- Claim path uses only
chainId(that's where the reward contract / activity address lives). Everything else — trading eligibility, "which chains count", chain-list display in templates — uses the union of both fields.
When the user asks "Does my chain count for this competition?" or "Which chains can I trade on?", answer from the union of chainId and participateChainIds. When rendering the "Chain" column / line in a template, render that same union (deduplicated) — see the {supportedChains} computation rule in each Step's field-mapping section.
Identity resolution invariant (deterministic — always answerable)
Algorithm (always runs internally; AI cannot bypass):
| Tool / call shape | Identity sent | Why |
|---|---|---|
competition_user_status (always) | accountId (self) | self-only tool; covers every chain in participateChainIds in one call |
competition_rank with no wallet | accountId (self) | default self-rank, no chain picking needed |
competition_rank with wallet=<addr> | walletAddress (cross-user) | the tool validates that addr's chain family (EVM 0x... else Solana) matches the activity's primary chainId; mismatch → call is rejected (no silent wrong-chain query) |
competition_claim (pre-check) | accountId (self) | claim is always self-action; uses accountId for the eligibility check |
How to answer "which identity did you use?":
| Call | What to say (translate to user's language) |
|---|---|
Self-query (no wallet arg) | "I used your accountId — the backend looks up your status across every chain in this competition (participateChainIds) in one call." |
Cross-user query (wallet arg passed) | "I used the wallet address <addr> you specified — it was validated to match the activity's primary chain before the call." |
Forbidden answers (paraphrase patterns observed and are wrong):
- ❌ "The tool sends both
accountIdandwalletAddress" — Wrong. Exactly one, never both. - ❌ "The tool picks EVM or SOL based on chain" — Wrong (post-refactor). That was the old wallet-only model. Self-queries now send
accountId, no chain pick. - ❌ "I'm not sure which one the tool ended up sending" — Wrong. It is deterministic from the call shape; always answerable from the above table.
For multi-activity queries (e.g. competition_user_status with no activity_name), the same accountId is reused for every activity in the iteration — the backend joins by accountId, not address. The answer is uniformly "I used your accountId for all activities".
⚠️ Mandatory reading order
The template structure is fixed; the language follows the user — see the ## Output Language rule above. When the user writes Chinese, translate the template strings to natural Chinese. When the user writes English, use English as written. Placeholders (including chain display names from {supportedChains}) stay as-is.
Quick router (user intent → template section):
- "list competitions / show available competitions" → Step 1 (table, optionally split by Active / Ended)
- "show details / show rules / show prize pool" → Step 2 (Basic info block + 4 reward sections, with
{supportedChains}chain line and required participation / Skill copy) - "register / join" → Step 3 (registration success fixed template + disclaimer)
- "trade for me" → Step 4 (delegate to okx-dex-swap)
- "leaderboard / ranking" → Step 5
- "claim reward" → Step 6 (use
competition_claimMCP, atomic) - "show registered wallet" → Additional Flows / Query Registered Wallet
- "export wallet" → Additional Flows / Wallet Export Guard
If the user's intent does not clearly map to one of the above, ask which they meant before responding — do not invent a freeform format.
Pre-flight
Read
../okx-agentic-wallet/_shared/preflight.md. If missing, read_shared/preflight.md.
Command Index
| # | Command | Auth | Description |
|---|---|---|---|
| 1 | onchainos competition list [--status 0|1|2] [--page-size N] [--page-num N] | None | List Agentic Wallet exclusive competitions (default status=0, active only) |
| 2 | onchainos competition detail --activity-id <id> | None | Get rules, prize pool, chain, timeline |
| 3 | onchainos competition rank --activity-id <id> [--wallet <addr>] --sort-type <type> [--limit N] | None | Leaderboard + user rank. Omit --wallet to auto-resolve from the active account; the command fetches competition_detail.chainId and picks the chain-appropriate address. Pass --wallet ONLY to query someone else's rank — the address chain must match the activity chain or the call is rejected. MCP tool competition_rank mirrors this (single optional wallet). Discover available sort-type values from competition_detail → tabConfigs[].rankFieldConfig[].sortValueMap.descend (do not hardcode). |
| 4 | onchainos competition user-status [--activity-id <id>] | Wallet login | Check participation & reward status using the active user's accountId (omit --activity-id to check all activities). MCP tool competition_user_status takes no wallet args — accountId is loaded from the local wallet store. |
| 5 | onchainos competition join --activity-id <id> --evm-wallet <addr> --sol-wallet <addr> --chain-index <chain_id> | Wallet login | Register for the competition. MCP tool competition_join makes both wallet args optional. |
| 6 | onchainos competition claim --activity-id <id> --evm-wallet <addr> --sol-wallet <addr> | Wallet login | CLI returns unsigned calldata. MCP tool competition_claim is atomic — wallets are optional, signing + broadcast happens inside the tool, returns txHash array. Surfaces needContact: true for top-tier winners (see Step 6 contact-collection sub-flow). |
| 7 | onchainos competition submit-contact --activity-id <id> --contact-type <Telegram|WeChat|Email|Twitter> --contact-value <text> | Wallet login | Record a contact method for top-tier winners (called only after a claim that returned needContact: true). MCP tool competition_submit_contact looks up accountId + joinedAddress internally. |
--status (request filter): 0=active, 1=ended, 2=all
activityStatus (response field): 3=active, 4=ended — these are DIFFERENT values from the request filter
sort-type: dynamic — read from competition_detail → tabConfigs[].rankFieldConfig[].sortValueMap.descend. Currently observed values: 1=PnL% (realized ROI), 7=PnL (realized profit). Future activities may add more — always trust tabConfigs over hardcoding.
Output Rules
Internal-only IDs vs user-facing display. Internal numeric IDs (
activityId,chainIndex,accountId) are returned in tool responses on purpose — they are needed to chain calls between tools (e.g. aftercompetition_join, you may need to callcompetition_detailwith the activity id to fill the success template). Keep them in the data layer; never render them in user-visible messages.
Forbidden user-visible patterns (do NOT produce output like this):
- ❌
Agentic Trading Contest (#107) - ❌
#106 (agenticwallettest1) - ❌ A column titled
ID,Activity ID,#, or any equivalent in the user's language - ❌ A row labeled
Activity ID,ID,#, or any equivalent in the user's language (e.g. a 2-column key/value table where a row maps the id label to the numeric value) — this is the same violation as a column, just rotated - ❌ Any reference like
competition 107,id 107,the activity id is 107, or the same wording in another language - ❌ Numeric id rendered anywhere a user can see it, regardless of label, shape, or language
Correct user-visible pattern:
- ✅
Agentic Trading Contest - ✅ When disambiguating two activities with the same name, append
chainName(e.g.Agentic Trading Contest (Solana)), never the ID.
Behind the scenes (allowed and expected):
- ✅ Reading
activityIdfrom acompetition_user_status/competition_joinresponse and passing it tocompetition_detailto fetch the data needed by a fixed template. - ✅ Any tool-to-tool chaining via numeric ids — as long as the final user-facing message omits them.
When the user asks to act on a specific activity (e.g. "claim Agentic Trading Contest"), the MCP tools competition_claim / competition_join accept activity_name and resolve the id server-side, so you can also use names directly without doing your own lookup.
Time Formatting (MANDATORY)
Preferred — use backend-formatted strings when available:
For the competition_detail response, the backend now returns pre-formatted UTC+8 strings — use them verbatim, do NOT recompute from the raw epoch:
| Field | Format | Example |
|---|---|---|
startTimeFormatted | yyyy-MM-dd HH:mm:ss (UTC+8, no suffix) | "2026-05-07 18:00:00" |
endTimeFormatted | yyyy-MM-dd HH:mm:ss (UTC+8, no suffix) | "2026-05-21 18:00:00" |
When rendering, take the string as-is and append (UTC+8) for the timezone marker (e.g. 2026-05-07 18:00:00 (UTC+8)). This is the only correct path for detail view times — the backend has already done the math; computing from startTime / endTime epoch invites off-by-an-hour errors and AI hallucination.
Raw fields — only use when no *Formatted counterpart is present:
| Field | Format | Example raw | Notes |
|---|---|---|---|
startTime, endTime (list response — no formatted variant returned) | 10-digit Unix seconds | 1778148000 | Multiply by 1000 only if the runtime expects ms |
joinTime, claimTime (user-status response) | 10-digit Unix seconds | 1778148000 | Same |
rankUpdateTime (rank response) | 13-digit Unix milliseconds | 1774359000638 | Divide by 1000 to convert to seconds first |
If you see a 13-digit value where a 10-digit is documented (or vice versa), do NOT silently coerce — flag it as a backend anomaly.
Display format — exact, no improvisation:
- Detail view (with
*Formattedavailable):YYYY-MM-DD HH:mm:ss (UTC+8)— example:2026-05-07 18:00:00 (UTC+8)(use the formatted string + suffix) - List view compact range:
YYYY-MM-DD ~ YYYY-MM-DD(UTC+8 day boundary) — example:2026-05-07 ~ 2026-05-21(compute from rawstartTime/endTime, take the date portion only) joinTime/claimTimein user-facing context:YYYY-MM-DD HH:mm (UTC+8)(compute from raw epoch)rankUpdateTime(last refresh marker):YYYY-MM-DD HH:mm:ss (UTC+8)(compute from raw ms epoch)
Timezone rule: ALL competition times displayed to the user are in UTC+8 (China Standard Time). The competition product is operated in UTC+8; never display raw UTC, never use the user's local timezone.
When you DO need to convert from raw epoch (no formatted field available):
- Identify the field's documented unit (seconds or milliseconds — see table above).
- Convert to a Date object using the correct unit.
- Format as a UTC+8 wall-clock string per the display format above.
- Always append the
(UTC+8)suffix.
...
用户评价 (0)
发表评价
暂无评价
统计数据
用户评分
为此 Skill 评分