Skip to main content
Glama
Emercoin swap

Emercoin swap

Official

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.

This server is not self-contained — use the hosted endpoint above. Running an order needs deployed infrastructure: an Emercoin node + adapter (the EMC payout rail, /wallet/send), a TronGrid USDT watcher, a funded EMC reserve, and a configured TRON deposit address. An image built from this repo in isolation — e.g. by a registry/sandbox like Glama — is therefore an introspection target only: tools/list (for tool-definition quality scoring) works with zero config, but execution tools like buy_emc cannot complete without that backing infra (no deposit address → "deposit address not configured"; no adapter → reserve pre-flight fails). That's correct isolation, not a defect. To actually buy EMC, call the hosted https://swap.emercoin.com/mcp. The repo never ships the adapter key or any wallet secret — those live only on the deployed host.

Related MCP server: TRON Energy/Bandwidth MCP Server

Locked decisions

Topic

Decision

Rate

static 1 USDT = 10 EMC

Amounts

fixed denominations: 5 or 10 USDT (not a free range; floor 5: below it TRON gas dominates). REST/MCP/web validate the input against this exact set

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.py applies schema.sql with CREATE TABLE IF NOT EXISTS, which does not alter an existing table. After editing schema.sql in dev, reset the database: rm swap.db (then restart — it recreates the schema — and re-run scripts/register_service since the services table is wiped too). swap.db holds 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. See docs/TESTNET.md for the runbook (scripts/testnet/).

AML is live: OFAC SDN addresses (TRON) loaded into memory + refreshed, and a per-deposit live Tether isBlackListed check; 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); see docs/TDQS.md.

Deferred: USDT sweep / TRON tx signing (services/sweep.py, kept off the hot path).

License

MIT — see LICENSE.

Available Tools

4 tools
buy_emcBuy EMC with USDT (open an order)A

Open an order to buy EMC with USDT (TRC20) and get back a shared TRON deposit_address plus the EXACT amount_usdt to send. This does NOT move funds: you then transfer that exact figure (it is your order's matching tag) to the deposit address; on confirmed payment, EMC (amount_usdt × rate) is delivered to your address automatically. Keep the returned token and poll get_order_status until 'notified'; to abandon before paying, call cancel_order. One-way — a wrong amount cannot be matched and is NOT refunded. By default each call opens a NEW order; pass a stable idempotency_key to make retries return the same order. Use get_swap_config first to pick a valid amount.

Inputs: amount_usdt (required), destination_emc_address (required), idempotency_key. Returns: token, order_id, deposit_address, amount_usdt, +3 more

cancel_orderCancel an unpaid EMC orderA
Destructive

Cancel a still-unpaid buy_emc order by its token, expiring it now and freeing its slot ahead of the TTL. Use this only before you pay; once a payment is in flight or confirmed it is too late and this errors. A payment sent after cancellation matches nothing and is NOT refunded. To only inspect an order without changing it, use get_order_status.

Inputs: token (required). Returns: order_id, status, amount_usdt, emc_amount, +4 more

get_order_statusGet EMC order statusA
Read-onlyIdempotent

Return the current status of a buy_emc order by its token: the status, the exact amount, the EMC amount and destination address, and the emc_txid once delivered. Use this to poll after buy_emc — status progresses awaiting_payment → confirmed → emc_delivered → notified (done). Read-only; to cancel an unpaid order use cancel_order instead.

Inputs: token (required). Returns: order_id, status, amount_usdt, emc_amount, +4 more

get_swap_configGet EMC swap limits and rateA
Read-onlyIdempotent

Return the current order denominations and fixed rate for buying EMC with USDT. allowed_amounts is the exact set of USDT values buy_emc accepts (fixed denominations, not a free range) — pick one of these; min_usdt/max_usdt are its bounds and emc_per_usdt is the rate (EMC you receive = amount_usdt × emc_per_usdt). Call this first to choose a valid amount for buy_emc. Read-only — it neither creates nor changes an order. support_email is the operator contact for manual cases (e.g. an order on aml_hold or a late/mismatched payment).

Inputs: no named parameters. Returns: min_usdt, max_usdt, allowed_amounts, emc_per_usdt, +1 more

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.6/5.0

    Scored across 4 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: initiating an order, canceling unpaid orders, checking status, and retrieving configuration. No functional overlap.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun snake_case pattern (buy_emc, cancel_order, get_order_status, get_swap_config), making it easy to predict functionality.

    Tool Count5/5

    With 4 tools covering the core swap workflow, the count is well-scoped and each tool earns its place without excess or deficiency.

    Completeness4/5

    The set covers order creation, cancellation, status polling, and configuration retrieval. Minor gap: no tool for listing a user's full order history, but the core lifecycle is complete.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Provides complete HTTP/JSON access to all 100+ Emercoin RPC endpoints with integrated formatting utilities. Enables blockchain operations, name system management, wallet functions, and mining operations through a comprehensive REST API interface.
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      AI-to-AI marketplace MCP server with 46 tools — swap 65+ crypto tokens on 7 chains, rent GPUs, trade 25 tokenized stocks, on-chain escrow (Solana + Base), DeFi yields, sentiment analysis, wallet monitoring, and image generation. Supports USDC payments across 14 blockchains.
      MIT