Emercoin swap
Keyless MCP exchanger for AI agents — pay an exact amount to one deposit address, EMC delivered to any address. USDT(Tron) > EMC. Live at https://swap.emercoin.com/mcp
README
swap — EMC cashier (USDT → EMC)
A minimal cashier exposing one primitive. All business logic stays in the calling services; swap knows nothing about NVS/DNS/subscriptions.
buy_emc(amount_usdt, destination_emc_address, callback_url, ref)
→ collect USDT on a unique deposit address
→ on confirmation, deliver EMC (fixed rate ×10) to destination
→ notify the caller with a SIGNED callback
destination is opaque to swap: it can be a service's address (the service
then renders its own product on that EMC — the user only ever pays USDT and
never touches a wallet) or the user's own address (raw on-ramp).
Use via MCP
An AI agent with USDT can buy EMC directly — no account, no API key, no callback. swap exposes a keyless MCP exchanger over Streamable HTTP at:
https://swap.emercoin.com/mcp
Add it to a client:
# Claude Code
claude mcp add --transport http swap https://swap.emercoin.com/mcp
- Claude Desktop — Settings → Connectors → Add custom connector → the URL above.
- MCP Inspector —
npx @modelcontextprotocol/inspector→ Streamable HTTP → the URL.
Tools:
| Tool | What it does |
|---|---|
get_swap_config |
min/max USDT per order + the fixed EMC-per-USDT rate |
buy_emc |
open an order → returns a deposit address + the exact USDT amount to send (+ optional idempotency_key) |
get_order_status |
poll an order by its token until delivered |
cancel_order |
drop an unpaid order early |
Flow: get_swap_config → buy_emc(amount, your_emc_address) → send the exact
returned amount (TRC20) to the deposit address → poll get_order_status by token
until notified. One-way, exact-amount, no refunds. The same primitive is also
available as keyed REST (for services, with a signed callback) and a keyless
web page at swap.emercoin.com.
Locked decisions
| Topic | Decision |
|---|---|
| Rate | static 1 USDT = 10 EMC |
| Cap / floor | 5–10 USDT (floor 5: below it TRON gas dominates) |
| USDT rail | TRC20 (TRON) |
| Payment match | one shared deposit address + unique per-order amount tag |
| EMC delivery | via emercoin adapter POST /wallet/send (X-Internal-Key) |
| Callback signature | HMAC-SHA256 over canonical body, per-service secret |
| KYC | none (amounts far below threshold) |
| AML | minimal but mandatory — OFAC SDN + Tether freeze blacklist |
| Terms | exact amount, single transfer, one-way (no refunds) — state in the offer |
Layout
swap/
config.py env-driven settings (pydantic-settings)
models.py OrderStatus enum + request/response schemas
states.py order state machine (allowed transitions)
schema.sql DDL: services/orders/deposits/aml_checks/sweeps/callbacks
db.py SQLite connection + init
repository.py DB access layer
auth.py caller auth by API key
orders.py buy_emc business logic (shared by REST + MCP)
main.py FastAPI app (REST: POST /buy_emc, GET /order/{id})
mcp_app.py keyless MCP exchanger at /mcp (agent tools, mirrors /web)
web.py public keyless /web/* channel (raw on-ramp for humans)
site/ static exchanger page + offer (index.html, oferta.html)
clients/
adapter.py EMC delivery + balance via emercoin adapter
trongrid.py TRC20 deposit watcher source (TronGrid)
tron/
hd.py HD derivation of deposit addresses (BIP44, coin 195)
services/
aml.py OFAC + Tether blacklist screening
delivery.py deliver EMC from reserve (idempotent)
callback.py signed callback notifier + retries
watcher.py background loop: deposits → confirm → AML → deliver → notify
sweep.py USDT consolidation from deposit addresses
State machine
created → awaiting_payment → confirmed → emc_delivered → notified (done)
↘ underpaid (top-up or partial refund)
↘ overpaid (refund excess)
↘ aml_hold (sender blacklisted → manual)
↘ deliver_failed (retry; else refund USDT)
expired — no payment before TTL
Dev
uv sync --extra dev
cp .env.example .env # fill secrets
uv run uvicorn swap.main:app --reload --port 8002
EMC delivery and the TRON watcher need the emercoin adapter and TronGrid creds;
for local end-to-end you can bring up the node+adapter from emercoin_docker
(docker compose --profile dev up). TRON parts are verified in a test
environment before they are wired into the watcher.
Schema changes have no migrations.
db.pyappliesschema.sqlwithCREATE TABLE IF NOT EXISTS, which does not alter an existing table. After editingschema.sqlin dev, reset the database:rm swap.db(then restart — it recreates the schema — and re-runscripts/register_servicesince theservicestable is wiped too).swap.dbholds only local/test data.
Status: full happy path verified live end-to-end (+ 41 unit tests). On 2026-06-14 a real run took a TRC20 USDT deposit on TRON Nile testnet →
confirmed→ delivered real EMC on Emercoin mainnet (via the adapter/wallet/send) → signed callback verified by the receiver against the service's HMAC secret:awaiting_payment → confirmed → emc_delivered → notified. Seedocs/TESTNET.mdfor the runbook (scripts/testnet/).AML is live: OFAC SDN addresses (TRON) loaded into memory + refreshed, and a per-deposit live Tether
isBlackListedcheck; a hit →aml_hold(no delivery).Payment matching: pivoted from a unique HD address per order to one shared deposit address + a unique per-order amount tag (matched by exact amount). This removes per-order sweeping and the fresh-address gas penalty; the trade-off is exact-amount, single-transfer payments (no auto under/overpaid). Collected USDT is moved to treasury / off-ramp manually at low volume. MCP exchanger: the keyless web on-ramp is also exposed as MCP tools (
buy_emc,get_order_status,cancel_order,get_swap_config) over Streamable HTTP at/mcp, so an AI agent buys EMC with USDT directly — no key, no callback, same anti-spam as the web channel. No auth by design: it's a public "pay for a service" on-ramp, not an account. Tool definitions pass a pre-publication TDQS review (all tier A); seedocs/TDQS.md.Deferred: USDT sweep / TRON tx signing (
services/sweep.py, kept off the hot path).
License
MIT — see LICENSE.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。