Devolopers - SDKs APIs & Contracts

Build on Methexis with contracts, a lightweight SDK, and optional indexer APIs for convenience. On‑chain state is canonical; off‑chain services (IPFS/Arweave + indexers) make it fast to integrate.

Status: Testnet first. Addresses and package names marked TBA will be published in Releases.

TL;DR — 5‑minute Quickstart (testnet)

# 1) Install SDKs (JS or Python)
npm i @methexis/sdk      # JS/TS
# or
pip install methexis-sdk # Python

# 2) Configure RPC + signer (env)
export ETH_RPC=https://rpc.testnet.example.org
export WALLET=0xYOUR_ADDR

# 3) Register a dataset (hash + manifest URI)
mhx data register \
  --content-hash 0xA3F5...7C1E \
  --meta-uri ipfs://bafy.../manifest.yaml \
  --bond 80

What just happened: you pinned data to IPFS, registered it on‑chain, and posted a refundable bond. A committee will now review your dataset.


Environments

Env
Chain
RPC
Contracts

Testnet

Ethereum testnet

https://rpc.testnet.example.org

TBA (published in Releases)

Mainnet

Ethereum

https://…

TBA (after audit)

Chain ID: TBA • Block explorer: TBA


Packages

  • JavaScript/TypeScript: @methexis/sdk (Ethers v6 under the hood)

  • Python: methexis-sdk (web3.py + requests)

  • CLI: mhx (thin wrapper over contracts & IPFS helpers)

Source: https://github.com/methexisxyz (modules: token, staking, rewards, governance, data‑registry, validator)


Core Contracts & ABIs (overview)

  • Token (ERC‑20): $MTHX

  • Staking / Rewards

  • Data RegistryregisterDataset(bytes32 contentHash, string metaURI); setDatasetStatus(uint256 id, Status)

  • Training CoordinationstartRound, submitModelUpdate, finalizeRound

  • Governance (DAO)propose, vote, queue, execute

Events (minimal schema) DatasetRegistered(datasetId, contentHash, submitter) DatasetStatusChanged(datasetId, status) RoundStarted(roundId, prevModelHash) ModelProposed(roundId, modelHash, signers, metricsURI) ModelFinalized(roundId, modelHash) RewardsDistributed(roundId, total, breakdownURI) Slashed(account, amount, reason)

Full ABIs are published with releases. You can also import them from the SDK.


JavaScript / TypeScript (Ethers v6) examples

1) Setup

import { ethers } from "ethers";
import { getContracts } from "@methexis/sdk"; // helper that returns typed ethers.Contract

const provider = new ethers.JsonRpcProvider(process.env.ETH_RPC!);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);

const { DataRegistry, Training, Staking, Governance } = await getContracts({
  chain: "testnet", signer: wallet,
});

2) Register a dataset

// contentHash = sha256 of the archive; metaURI = ipfs://<manifestCID>
const tx = await DataRegistry.registerDataset(
  "0xA3F5...7C1E",
  "ipfs://bafy.../manifest.yaml"
);
const receipt = await tx.wait();
const evt = receipt.logs.find(l => l.fragment?.name === "DatasetRegistered");
console.log("datasetId:", evt?.args?.datasetId?.toString());

3) Watch validation status → drive UX

DataRegistry.on("DatasetStatusChanged", (datasetId, status) => {
  console.log("status", datasetId.toString(), status);
  // update your UI: Pending → Accepted/Rejected
});

4) Listen to training lifecycle

Training.on("RoundStarted", (roundId, prevHash) =>
  console.log("Round", roundId.toString(), "prev", prevHash)
);

Training.on("ModelProposed", (roundId, modelHash, signers, metricsURI) =>
  console.log("Proposed", { roundId: roundId.toString(), modelHash, metricsURI })
);

Training.on("ModelFinalized", (roundId, modelHash) =>
  console.log("Finalized", roundId.toString(), modelHash)
);

Training.on("RewardsDistributed", (roundId, total, breakdownURI) =>
  console.log("Rewards", roundId.toString(), total.toString(), breakdownURI)
);

5) Propose a governance change

// Example: setValidatorRewardShare(62%)
const iface = new ethers.Interface(["function setValidatorRewardShare(uint256 bps)"]);
const callData = iface.encodeFunctionData("setValidatorRewardShare", [6200]); // 62.00%

const txP = await Governance.propose(callData, "Increase validator share to 62%");
await txP.wait();
console.log("Proposal submitted");

Python (web3.py) examples

from web3 import Web3
from methexis_sdk import load_contracts

web3 = Web3(Web3.HTTPProvider(os.environ["ETH_RPC"]))
acct = web3.eth.account.from_key(os.environ["PRIVATE_KEY"])
contracts = load_contracts(web3, acct, chain="testnet")

# Register dataset
tx = contracts.DataRegistry.functions.registerDataset(
    "0xA3F5...7C1E",
    "ipfs://bafy.../manifest.yaml"
).build_transaction({"from": acct.address, "nonce": web3.eth.get_transaction_count(acct.address)})
signed = web3.eth.account.sign_transaction(tx, private_key=os.environ["PRIVATE_KEY"])
txhash = web3.eth.send_raw_transaction(signed.rawTransaction)
print("tx", web3.to_hex(txhash))

Indexer API (optional convenience)

While contracts/events are the source of truth, an indexer helps you avoid manual log scans.

REST (proposed):

GET  /v1/datasets/:id              -> { id, contentHash, status, submitter, metaURI }
GET  /v1/datasets?status=Accepted  -> [...paged results...]
GET  /v1/rounds/:roundId           -> { roundId, prevModelHash, modelHash, metricsURI, finalizedAt }
GET  /v1/rewards/:roundId          -> { total, breakdownURI, allocations[] }
GET  /v1/validators/:addr          -> { stake, uptime, roundsParticipated, slashes[] }
GET  /v1/events?from_block=...     -> stream of canonical events

Webhooks (proposed):

  • dataset.status.changed — payload: { datasetId, status }

  • round.finalized — payload: { roundId, modelHash, metricsURI }

  • rewards.distributed — payload: { roundId, total, breakdownURI }

API keys are issued per project; rate limits apply. The indexer mirrors on‑chain data and links off‑chain URIs.


Data flow helpers

Hashing (sha256) & IPFS upload (JS)

import { create } from "ipfs-http-client";
import { createHash } from "crypto";
import fs from "fs";

const ipfs = create({ url: "https://ipfs.your-gateway.example/api/v0" });

const buf = fs.readFileSync("./cleancode-docs-v1.tar.zst");
const contentHash = "0x" + createHash("sha256").update(buf).digest("hex");

const { cid } = await ipfs.add(buf, { pin: true });
const manifestCID = await ipfs.add(fs.readFileSync("./manifest.yaml"));
console.log({ contentHash, archiveCID: cid.toString(), manifestURI: `ipfs://${manifestCID.cid}` });

  • Subscribe to DatasetStatusChanged and RoundStarted/Finalized to drive UX.

  • Use idempotent handlers (event replay safe).

  • Handle reorgs: wait N confirmations (e.g., 12) before acting on payments or irreversible actions.


Contract interaction patterns

  • Always simulate (staticcall / eth_call) before sending txs that mutate state.

  • Gas & revert handling: surface revert reasons to users.

  • Timelock awareness: governance changes aren’t immediate; poll timelock or listen to Queued/Executed (ABI TBA).

  • Multisig compatibility: proposals can be composed & signed by Safe; execution still goes through DAO where required.


Versioning & Compatibility

  • Semver for SDKs and contract releases (vMAJOR.MINOR.PATCH).

  • Breaking changes → new contract addresses (posted in Releases); SDK will expose both v1 and v2 namespaces during migration.

  • Deprecations are announced at least one quarter in advance in the Roadmap page.


Security & Keys

  • Prefer hardware wallets or remote signers.

  • Never store private keys in code or CI; use vaults / KMS.

  • Rotate API keys and restrict by IP where possible (indexer).

  • Monitor for Slashed events and set alerts.


Testing & Local Dev

  • Local anvil/Hardhat/Foundry support (fork testnet).

  • Mock IPFS gateway + fixtures for dataset manifests.

  • Contract interfaces shipped with the SDK for quick tests.

Example (Foundry):

forge test -vvv
# Deploy to local dev chain
forge script script/Deploy.s.sol --broadcast --rpc-url http://localhost:8545

Error Model (SDK)

  • MhxError base class with code and context.

  • Common codes: E_NO_FUNDS, E_REVERTED, E_BAD_MANIFEST, E_POLICY_VIOLATION, E_RATE_LIMIT, E_TIMEOUT.

  • All network calls support retry with backoff and abort signals.


Frequently Used Recipes

  • “Show me all Accepted datasets since block X” → indexer GET /v1/datasets?status=Accepted&from_block=X or filter DatasetStatusChanged and query status=Accepted.

  • “Notify users when a round finalizes” → subscribe to ModelFinalized + RewardsDistributed, then send webhook.

  • “Governance dashboard” → index proposals from ProposalCreated (ABI TBA), tally votes per block, show timelock ETA.


  • Releases & Addresses: GitHub → Releases

  • Package registry: npm / PyPI

  • Status page: TBA

  • Responsible disclosure: see Audits & Security page

Last updated