Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions submissions/mcp-hackathon/visioneer-gaspulse/RIGHTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Submission rights declaration

Project: `GasPulse`
Submission slug: `visioneer-gaspulse`
Submitter: `Visioneer (muhammad-wei, https://github.com/muhammad-wei)`
Date: `2026-09-03`

The submitter confirms that they own, or have sufficient authorization for, the source code, dependencies, service, data, branding, and other materials submitted in this pull request.

Subject to the official program terms, the submitter authorizes X-Agent to retain, reproduce, audit, test, archive, and publish the submitted program artifact for judging, fraud prevention, dispute handling, ecosystem submission, and post-award accountability. Closing the pull request, deleting a fork, or deleting an external repository does not revoke the official archive rights attached to an accepted and rewarded entry.

Third-party components and their licenses: `fastify@5.12.1 (MIT), zod@3.25.76 (MIT), dotenv@16.6.1 (BSD-2-Clause), typescript@5.9.3 (Apache-2.0), tsx@4.23.13 (MIT), vitest@2.1.9 (MIT). Runtime data source: Etherscan API (api.etherscan.io), used under Etherscan's public API terms — no Etherscan code or data is redistributed, only queried live per request.`

Exceptions or restrictions: `none`

This template is an operational declaration, not a substitute for event terms reviewed by qualified counsel.
96 changes: 96 additions & 0 deletions submissions/mcp-hackathon/visioneer-gaspulse/SUBMISSION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# GasPulse

> Replace every angle-bracket placeholder before opening the pull request.

## Capability

- **One-line description:** Given an Ethereum mainnet address, returns a recent gas-consumption
trend and a deterministic 0–100 activity/liveliness score, so a trading agent can quickly gauge
how active an address currently is.
- **Who it helps:** AI trading agents (and their operators) that need a fast, structured signal
on address activity before acting — e.g. deciding whether a counterparty or watched address is
currently live.
- **Capability boundary:** Read-only Ethereum mainnet data sourced from Etherscan. Computes gas
trend and an activity score from an address's most recent transactions (bounded — see Known
risks below). It does **not** perform fraud, risk, compliance, or security analysis of any
kind: `activityScore` reflects only the recency, frequency, and consistency of transactions,
never trustworthiness or danger.

## Live API

- **API base URL:** https://api.gaspulse.win/v1
- **Health-check URL:** https://api.gaspulse.win/health
- **Authentication:** none
- **Rate limits / known limits:** bounded by the Etherscan free tier (~5 req/s upstream);
GasPulse caches the raw per-address transaction list for 60 seconds in memory to absorb
repeated agent calls. Upstream requests time out after 8s server-side, surfaced to the caller
as `429`/`502` (see error taxonomy below and in `source/README.md`).
- **API contract:** `GET /v1/address/{address}/activity?windowDays=30` — full request/response
shapes, field meanings, and the activity-score methodology are documented in
`source/README.md` (reproduced with a live example in `verification/README.md`). A second,
free endpoint, `GET /v1/gas/current`, returns the current network-wide gas price (no address,
no parameters) — also documented in `source/README.md`.

## Source and reproducibility

- **Source repository:** https://github.com/muhammad-wei/gaspulse
- **Review commit:** `f1edc68641d5bee0f6c8a72f11abc75bfa837c75`
- **Source submitted in this PR:** `source/`
- **Run tests:** `npm ci && npm test`
- **Run locally:** `npm ci && cp .env.example .env` (fill in `ETHERSCAN_API_KEY`) `&& npm run dev`
- **Deploy:** `npm run build && node dist/server.js` with `GIT_COMMIT` and `ETHERSCAN_API_KEY` set
in the environment; a Docker alternative (`docker build --build-arg GIT_COMMIT=$(git rev-parse HEAD) ...`)
is documented in `source/README.md`.
- **Version binding:** `GIT_COMMIT` is injected into the process environment at deploy time
(Docker: `--build-arg GIT_COMMIT` baked to `ENV`; this live deployment: a systemd service
`Environment=` line set to the exact commit above) and read by `/health` and
`/.well-known/xagent-verification.json` at request time — never read from `.git` or hardcoded.

The API must expose:

```json
// GET https://api.gaspulse.win/health
{"status":"ok","commit":"f1edc68641d5bee0f6c8a72f11abc75bfa837c75"}
```

```json
// GET /.well-known/xagent-verification.json on the same API origin
{"schemaVersion":1,"slug":"visioneer-gaspulse","commit":"f1edc68641d5bee0f6c8a72f11abc75bfa837c75"}
```

## Verification

The reproducible call instructions and redacted example responses are in `verification/README.md`.

- **Health-check result:** `GET https://api.gaspulse.win/health` →
`{"status":"ok","commit":"f1edc68641d5bee0f6c8a72f11abc75bfa837c75"}`
- **Capability call:** `GET https://api.gaspulse.win/v1/address/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/activity?windowDays=30`
→ `200` with gas trend and activity score for that address.
- **Expected error behavior:** malformed address → `400 invalid_address`; out-of-range
`windowDays` → `400 invalid_window`; Etherscan rate-limited → `429 upstream_rate_limited`;
Etherscan unreachable/erroring → `502 upstream_unavailable`. An address with no transactions
returns `200` with every field zeroed, never `404` — deterministic either way.

## Security and data handling

- **Data collected:** none stored persistently. The Ethereum address in the request path is
forwarded to Etherscan's public API to look up that address's public on-chain transaction
history; results are cached in-process for 60 seconds, then discarded.
- **Purpose and retention:** the fetched transaction data is used only to compute the response
for that single request; nothing is logged or persisted beyond the 60-second in-memory cache.
- **Third parties / outbound network calls:** Etherscan API (`api.etherscan.io`) — the only
outbound call GasPulse makes.
- **Secrets:** No secrets are committed. `ETHERSCAN_API_KEY` is supplied via environment variable
only (`.env.example` ships an empty placeholder). This API requires no auth, so no review
credential needs to be shared.
- **Known risks / restrictions:** Ethereum mainnet only. Gas trend and `firstSeen`/`lastSeen` are
computed from the most recent 1,000 transactions Etherscan returns for the address —
extremely long-lived, high-volume addresses may have earlier history not reflected.
`activityScore` is deliberately not a risk/fraud/security signal (see Capability boundary).

## Support

- **Team / builder:** Visioneer
- **Contact:** https://github.com/muhammad-wei
- **License / rights:** MIT (`source/LICENSE`). Submitter confirms ownership/authorization to
submit and license this code for review and deployment — see `RIGHTS.md`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
dist
.git
.env
test
*.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Free API key from https://etherscan.io/apis — required to query transaction history.
ETHERSCAN_API_KEY=

# Optional overrides
PORT=8080
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
.env
*.log
22 changes: 22 additions & 0 deletions submissions/mcp-hackathon/visioneer-gaspulse/source/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM node:20-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src ./src
RUN npm run build

FROM node:20-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist

# Baked at build time — never read from a mutable file or set at runtime.
ARG GIT_COMMIT
ENV GIT_COMMIT=${GIT_COMMIT}
ENV PORT=8080

EXPOSE 8080
CMD ["node", "dist/server.js"]
21 changes: 21 additions & 0 deletions submissions/mcp-hackathon/visioneer-gaspulse/source/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Visioneer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
147 changes: 147 additions & 0 deletions submissions/mcp-hackathon/visioneer-gaspulse/source/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# GasPulse

Ethereum address gas-consumption trend and activity-score API, built for AI trading agents
that need a fast, deterministic read on how active an address currently is.

## Capability boundary

- **Does**: given an Ethereum mainnet address, returns recent gas-usage trend and a 0–100
activity/liveliness score derived from public on-chain transaction history (via Etherscan).
- **Does not**: perform fraud, risk, compliance, or security analysis of any kind. `activityScore`
reflects only the recency, frequency, and consistency of transactions — never trustworthiness,
danger, or a security signal. If you need risk/compliance screening, this is not that tool.

## API

### `GET /health`

```json
{"status":"ok","commit":"<40-char-sha>"}
```

### `GET /.well-known/xagent-verification.json`

```json
{"schemaVersion":1,"slug":"visioneer-gaspulse","commit":"<40-char-sha>"}
```

### `GET /v1/address/{address}/activity?windowDays=30`

- `address` (path, required) — a `0x`-prefixed 40-hex-character Ethereum address.
- `windowDays` (query, optional) — integer, `1`–`180`, default `30`.

Success (`200`) — an address with no activity still returns `200` with zeroed fields, never
`404`, so agents get a deterministic shape either way:

```json
{
"address": "0x0000000000000000000000000000000000dead",
"network": "ethereum-mainnet",
"windowDays": 30,
"asOf": "2026-09-02T00:00:00.000Z",
"txCount": 12,
"firstSeen": "2024-01-05T10:20:00.000Z",
"lastSeen": "2026-09-01T08:00:00.000Z",
"gasTrend": {
"totalGasUsed": "252000",
"avgGasPriceGwei": 14.2,
"direction": "increasing",
"buckets": [
{ "periodStart": "...", "periodEnd": "...", "txCount": 3, "gasUsed": "63000", "avgGasPriceGwei": 11.1 }
]
},
"activityScore": { "value": 78, "recency": 90, "frequency": 70, "consistency": 65 },
"dataSource": "etherscan"
}
```

**Errors** — stable `{"error":{"code":..., "message":...}}` shape:

| HTTP | code | meaning |
| --- | --- | --- |
| 400 | `invalid_address` | address is not a well-formed `0x` + 40 hex chars string |
| 400 | `invalid_window` | `windowDays` is missing bounds or not an integer 1–180 |
| 429 | `upstream_rate_limited` | Etherscan rate limit hit — retry after a short delay |
| 502 | `upstream_unavailable` | Etherscan request failed or timed out |

**Rate limits / caching**: bounded by the Etherscan free tier (~5 req/s). GasPulse caches the
raw transaction list per address for 60 seconds in memory to absorb repeated agent calls.

**Known limitations**: gas trend and `firstSeen`/`lastSeen` are computed from the most recent
1,000 transactions Etherscan returns for the address; extremely long-lived, high-volume
addresses may have earlier history that isn't reflected. Ethereum mainnet only.

### `GET /v1/gas/current` — free

Current Ethereum mainnet gas price, no parameters, no authentication. Distinct from the
per-address activity endpoint above: this is a network-wide snapshot, not tied to any address.

```json
{
"network": "ethereum-mainnet",
"asOf": "2026-09-04T03:58:43.479Z",
"safeGwei": 12.1,
"standardGwei": 14.3,
"fastGwei": 18.7,
"dataSource": "etherscan"
}
```

**Errors**: `429 upstream_rate_limited`, `502 upstream_unavailable` — same taxonomy as above.

**Caching**: the current gas price is cached in memory for 15 seconds (shorter than the
per-address cache, since the value is meant to be "current" and changes roughly every block).

## Setup

Requirements: Node.js `>=18.17`, a free Etherscan API key (https://etherscan.io/apis).

```bash
npm ci
cp .env.example .env # fill in ETHERSCAN_API_KEY
npm run dev
```

## Test

```bash
npm test
```

## Build and run

```bash
npm run build
npm start
```

## Docker

The deployed commit is baked into the image at build time (never read from a mutable file or
hardcoded) via `--build-arg GIT_COMMIT`:

```bash
docker build --build-arg GIT_COMMIT=$(git rev-parse HEAD) -t gaspulse .
docker run --rm -p 8080:8080 --env-file .env gaspulse
```

## Deploy

Any always-on container host works (the image is stock Node 20 + Fastify, no host-specific
code): build the image above, push it to the host's registry, deploy with `PORT=8080` exposed
and `/health` as the health-check path, and point DNS/TLS termination at port 443. Avoid
free tiers that sleep on idle — the hard uptime requirement rules those out.

## Activity score methodology

`activityScore.value` is `0.4 * recency + 0.4 * frequency + 0.2 * consistency`, each on a 0–100
scale, computed only from transactions inside `windowDays`:

- **recency** — decays linearly from 100 (last transaction was just now) to 0 (last transaction
was `windowDays` ago or there was none).
- **frequency** — `100 * txCount / (windowDays / 3)`, clamped to 100. One transaction every 3
days earns full credit.
- **consistency** — `100 * (1 - min(1, coefficient of variation of the gaps between consecutive
transactions))`; requires at least 3 in-window transactions, otherwise `0`.

See `src/lib/activityScore.ts` and `src/lib/gasTrend.ts` for the exact implementation.
Loading