diff --git a/README.md b/README.md
index f2058d6..1acfb21 100644
--- a/README.md
+++ b/README.md
@@ -36,10 +36,14 @@
| GET
`text/plain` | `/health` | Checks database connection |
| GET
`text/plain` | `/metrics` | [Prometheus](https://prometheus.io/) metrics |
+## GraphQL
+
+Go to `/graphql` for a GraphIQL interface.
+
## Requirements
- [ClickHouse](clickhouse.com/), databases should follow a `{chain}_tokens_{version}` naming scheme. Database tables can be setup using the [`schema.sql`](./schema.sql) definitions created by the [`create_schema.sh`](./create_schema.sh) script.
-- A [Substream sink](https://substreams.streamingfast.io/reference-and-specs/glossary#sink) for loading data into ClickHouse. We recommend [Substreams Sink ClickHouse](https://github.com/pinax-network/substreams-sink-clickhouse/) or [Substreams Sink SQL](https://github.com/pinax-network/substreams-sink-sql). You should use the generated [`protobuf` files](tsp-output/@typespec/protobuf) to build your substream. This Token API makes use of the [`substreams-antelope-tokens`](https://github.com/pinax-network/substreams-antelope-tokens/) substream.
+- A [Substream sink](https://substreams.streamingfast.io/reference-and-specs/glossary#sink) for loading data into ClickHouse. We recommend [Substreams Sink ClickHouse](https://github.com/pinax-network/substreams-sink-clickhouse/) or [Substreams Sink SQL](https://github.com/pinax-network/substreams-sink-sql). You should use the generated [`protobuf` files](static/@typespec/protobuf) to build your substream. This Token API makes use of the [`substreams-antelope-tokens`](https://github.com/pinax-network/substreams-antelope-tokens/) substream.
### API stack architecture
diff --git a/bun.lockb b/bun.lockb
index 0c19d78..005f82c 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/index.ts b/index.ts
index e7c4f4b..cf4c687 100644
--- a/index.ts
+++ b/index.ts
@@ -1,21 +1,22 @@
-import client from './src/clickhouse/client.js';
-import openapi from "./tsp-output/@typespec/openapi3/openapi.json";
-
-import { Hono } from "hono";
+import { Hono, type Context } from "hono";
+import { type RootResolver, graphqlServer } from '@hono/graphql-server';
+import { buildSchema } from 'graphql';
import { z } from 'zod';
-import { paths } from './src/types/zod.gen.js';
+
+import client from './src/clickhouse/client.js';
+import openapi from "./static/@typespec/openapi3/openapi.json";
+import * as prometheus from './src/prometheus.js';
import { APP_VERSION } from "./src/config.js";
import { logger } from './src/logger.js';
-import * as prometheus from './src/prometheus.js';
import { makeUsageQuery } from "./src/usage.js";
import { APIErrorResponse } from "./src/utils.js";
+import { usageOperationsToEndpointsMap, type EndpointReturnTypes, type UsageEndpoints, type ValidPathParams, type ValidUserParams } from "./src/types/api.js";
+import { paths } from './src/types/zod.gen.js';
-import type { Context } from "hono";
-import type { EndpointReturnTypes, UsageEndpoints, ValidPathParams, ValidUserParams } from "./src/types/api.js";
-
-function AntelopeTokenAPI() {
+async function AntelopeTokenAPI() {
const app = new Hono();
+ // Tracking all incoming requests
app.use(async (ctx: Context, next) => {
const pathname = ctx.req.path;
logger.trace(`Incoming request: [${pathname}]`);
@@ -24,6 +25,10 @@ function AntelopeTokenAPI() {
await next();
});
+ // ---------------
+ // --- Swagger ---
+ // ---------------
+
app.get(
"/",
async (_) => new Response(Bun.file("./swagger/index.html"))
@@ -34,6 +39,10 @@ function AntelopeTokenAPI() {
async (_) => new Response(Bun.file("./swagger/favicon.ico"))
);
+ // ------------
+ // --- Docs ---
+ // ------------
+
app.get(
"/openapi",
async (ctx: Context) => ctx.json<{ [key: string]: EndpointReturnTypes<"/openapi">; }, 200>(openapi)
@@ -44,6 +53,10 @@ function AntelopeTokenAPI() {
async (ctx: Context) => ctx.json, 200>(APP_VERSION)
);
+ // ------------------
+ // --- Monitoring ---
+ // ------------------
+
app.get(
"/health",
async (ctx: Context) => {
@@ -62,6 +75,10 @@ function AntelopeTokenAPI() {
async (_) => new Response(await prometheus.registry.metrics(), { headers: { "Content-Type": prometheus.registry.contentType } })
);
+ // --------------------------
+ // --- REST API endpoints ---
+ // --------------------------
+
const createUsageEndpoint = (endpoint: UsageEndpoints) => app.get(
// Hono using different syntax than OpenAPI for path parameters
// `/{path_param}` (OpenAPI) VS `/:path_param` (Hono)
@@ -88,17 +105,57 @@ function AntelopeTokenAPI() {
}
);
- createUsageEndpoint("/{chain}/balance");
- createUsageEndpoint("/chains");
- createUsageEndpoint("/{chain}/holders");
- createUsageEndpoint("/{chain}/supply");
- createUsageEndpoint("/{chain}/tokens");
- createUsageEndpoint("/{chain}/transfers");
- createUsageEndpoint("/{chain}/transfers/{trx_id}");
+ // Create all API endpoints interacting with DB
+ Object.values(usageOperationsToEndpointsMap).forEach(e => createUsageEndpoint(e));
+
+ // ------------------------
+ // --- GraphQL endpoint ---
+ // ------------------------
+
+ const schema = buildSchema(await Bun.file("./static/@openapi-to-graphql/graphql/schema.graphql").text());
+ const rootResolver: RootResolver = async (ctx?: Context) => {
+ if (ctx) {
+ const createGraphQLUsageResolver = (endpoint: UsageEndpoints) =>
+ async (args: ValidUserParams) => await (await makeUsageQuery(ctx, endpoint, { ...args })).json();
+
+ return Object.keys(usageOperationsToEndpointsMap).reduce(
+ // SQL queries endpoints
+ (resolver, op) => Object.assign(
+ resolver,
+ {
+ [op]: createGraphQLUsageResolver(usageOperationsToEndpointsMap[op] as UsageEndpoints)
+ }
+ ),
+ // Other endpoints
+ {
+ health: async () => {
+ const response = await client.ping();
+ return response.success ? "OK" : `[500] bad_database_response: ${response.error.message}`;
+ },
+ openapi: () => openapi,
+ metrics: async () => await prometheus.registry.getMetricsAsJSON(),
+ version: () => APP_VERSION
+ }
+ );
+ }
+ };
+
+ app.use(
+ '/graphql',
+ graphqlServer({
+ schema,
+ rootResolver,
+ graphiql: true, // if `true`, presents GraphiQL when the GraphQL endpoint is loaded in a browser.
+ })
+ );
+
+ // -------------
+ // --- Miscs ---
+ // -------------
app.notFound((ctx: Context) => APIErrorResponse(ctx, 404, "route_not_found", `Path not found: ${ctx.req.method} ${ctx.req.path}`));
return app;
}
-export default AntelopeTokenAPI();
\ No newline at end of file
+export default await AntelopeTokenAPI();
\ No newline at end of file
diff --git a/kubb.config.ts b/kubb.config.ts
index 676765e..27d84bc 100644
--- a/kubb.config.ts
+++ b/kubb.config.ts
@@ -5,7 +5,7 @@ export default defineConfig(() => {
return {
root: '.',
input: {
- path: './tsp-output/@typespec/openapi3/openapi.json',
+ path: './static/@typespec/openapi3/openapi.json',
},
output: {
path: './src/types'
diff --git a/package.json b/package.json
index f8eefca..6e6da75 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "antelope-token-api",
"description": "Token balances, supply and transfers from the Antelope blockchains",
- "version": "4.0.0",
+ "version": "5.0.0",
"homepage": "https://github.com/pinax-network/antelope-token-api",
"license": "MIT",
"authors": [
@@ -18,6 +18,7 @@
],
"dependencies": {
"@clickhouse/client-web": "latest",
+ "@hono/graphql-server": "^0.5.0",
"@kubb/cli": "^2.23.3",
"@kubb/core": "^2.23.3",
"@kubb/plugin-oas": "^2.23.3",
@@ -37,7 +38,7 @@
"lint": "export APP_VERSION=$(git rev-parse --short HEAD) && bun run tsc --noEmit --skipLibCheck --pretty",
"start": "export APP_VERSION=$(git rev-parse --short HEAD) && bun index.ts",
"test": "bun test --coverage",
- "types": "bun run tsp compile ./src/typespec && bun run kubb",
+ "types": "bun run tsp compile ./src/typespec --output-dir static && bun run openapi-to-graphql ./static/@typespec/openapi3/openapi.json --save static/@openapi-to-graphql/graphql/schema.graphql --simpleNames --singularNames && bun run kubb",
"types:check": "bun run tsp compile ./src/typespec --no-emit --pretty --warn-as-error",
"types:format": "bun run tsp format src/typespec/**/*.tsp",
"types:watch": "bun run tsp compile ./src/typespec --watch --pretty --warn-as-error"
@@ -45,10 +46,11 @@
"type": "module",
"devDependencies": {
"@typespec/compiler": "latest",
+ "@typespec/openapi": "latest",
"@typespec/openapi3": "latest",
"@typespec/protobuf": "latest",
- "@typespec/openapi": "latest",
"bun-types": "latest",
+ "openapi-to-graphql-cli": "^3.0.7",
"typescript": "latest"
},
"prettier": {
diff --git a/src/types/README.md b/src/types/README.md
index 91b19eb..c8695ca 100644
--- a/src/types/README.md
+++ b/src/types/README.md
@@ -1,9 +1,8 @@
### `zod.gen.ts`
-> [!WARNING]
-> **DO NOT EDIT**: Auto-generated [Zod](https://zod.dev/) schemas definitions from the [OpenAPI3](../tsp-output/@typespec/openapi3/openapi.json) specification using [`Kubb`](https://kubb.dev).
-
-Use `bun run types` to run the code generation for Zod schemas.
+> [!CAUTION]
+> Auto-generated [Zod](https://zod.dev/) schemas definitions from the [OpenAPI3](../static/@typespec/openapi3/openapi.json) specification using [`Kubb`](https://kubb.dev). **DO NOT EDIT MANUALLY**.
+> Use `bun run types` to run the code generation.
### `api.ts`
diff --git a/src/types/api.ts b/src/types/api.ts
index 45eb67b..42b36ea 100644
--- a/src/types/api.ts
+++ b/src/types/api.ts
@@ -1,6 +1,6 @@
import { z } from "zod";
-import { paths } from './zod.gen.js';
+import { operations, paths } from './zod.gen.js';
type GetEndpoints = typeof paths;
export type EndpointReturnTypes = z.infer;
@@ -21,3 +21,14 @@ export type ValidUserParams = EndpointParameters ex
export type AdditionalQueryParams = { offset?: number; min_block?: number; max_block?: number; };
// Allow any valid parameters from the endpoint to be used as SQL query parameters
export type ValidQueryParams = ValidUserParams & AdditionalQueryParams;
+
+// Map stripped operations name (e.g. `Usage_transfers` stripped to `transfers`) to endpoint paths (e.g. `/{chain}/transfers`)
+// This is used to map GraphQL operations to REST endpoints
+export const usageOperationsToEndpointsMap = Object.entries(operations).filter(([k, _]) => k.startsWith("Usage")).reduce(
+ (o, [k, v]) => Object.assign(
+ o,
+ {
+ [k.split('_')[1] as string]: Object.entries(paths).find(([k_, v_]) => v_.get === v)?.[0]
+ }
+ ), {}
+) as { [key in string]: UsageEndpoints };
\ No newline at end of file
diff --git a/src/types/zod.gen.ts b/src/types/zod.gen.ts
index 1cb1e1e..8a52176 100644
--- a/src/types/zod.gen.ts
+++ b/src/types/zod.gen.ts
@@ -5,7 +5,7 @@ export const apiErrorSchema = z.object({ "status": z.union([z.literal(500), z.li
export type ApiErrorSchema = z.infer;
-export const balanceChangeSchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.number(), "account": z.coerce.string(), "balance": z.coerce.string(), "balance_delta": z.coerce.number() });
+export const balanceChangeSchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.string(), "account": z.coerce.string(), "balance": z.coerce.string(), "balance_delta": z.coerce.number() });
export type BalanceChangeSchema = z.infer;
@@ -25,15 +25,15 @@ export const responseMetadataSchema = z.object({ "statistics": z.lazy(() => quer
export type ResponseMetadataSchema = z.infer;
-export const supplySchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.number(), "issuer": z.coerce.string(), "max_supply": z.coerce.string(), "supply": z.coerce.string(), "supply_delta": z.coerce.number() });
+export const supplySchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.string(), "issuer": z.coerce.string(), "max_supply": z.coerce.string(), "supply": z.coerce.string(), "supply_delta": z.coerce.number() });
export type SupplySchema = z.infer;
-export const supportedChainsSchema = z.enum(["eos", "wax"]);
+export const supportedChainsSchema = z.enum(["EOS", "WAX"]);
export type SupportedChainsSchema = z.infer;
-export const transferSchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.number(), "from": z.coerce.string(), "to": z.coerce.string(), "quantity": z.coerce.string(), "memo": z.coerce.string() });
+export const transferSchema = z.object({ "trx_id": z.coerce.string(), "action_index": z.coerce.number(), "contract": z.coerce.string(), "symcode": z.coerce.string(), "precision": z.coerce.number(), "amount": z.coerce.number(), "value": z.coerce.number(), "block_num": z.coerce.number(), "timestamp": z.coerce.string(), "from": z.coerce.string(), "to": z.coerce.string(), "quantity": z.coerce.string(), "memo": z.coerce.string() });
export type TransferSchema = z.infer;
@@ -78,12 +78,12 @@ export type MonitoringHealthQueryResponseSchema = z.infer;
/**
* @description Metrics as text.
*/
-export const monitoringMetricsQueryResponseSchema = z.coerce.string();
+export const monitoringMetricsQueryResponseSchema = z.object({});
export type MonitoringMetricsQueryResponseSchema = z.infer;
/**
diff --git a/src/typespec/README.md b/src/typespec/README.md
index ea01018..fa0e934 100644
--- a/src/typespec/README.md
+++ b/src/typespec/README.md
@@ -14,6 +14,6 @@ The data models used for both outputs can be found in [`models.tsp`](./models.ts
## Compiling definitions
-Use the `bun run types:watch` to auto-compile the definitions on file changes. Generated outputs can be found in the [`tsp-output`](/tsp-output/) folder.
+Use the `bun run types:watch` to auto-compile the definitions on file changes. Generated outputs can be found in the [`static`](/static/) folder.
Typescript compiler options can be found in [`tspconfig.yaml`](/tspconfig.yaml).
\ No newline at end of file
diff --git a/src/typespec/openapi3.tsp b/src/typespec/openapi3.tsp
index 58764e5..9133b53 100644
--- a/src/typespec/openapi3.tsp
+++ b/src/typespec/openapi3.tsp
@@ -12,7 +12,7 @@ using TypeSpec.OpenAPI;
name: "MIT",
url: "https://github.com/pinax-network/antelope-token-api/blob/4f4bf36341b794c0ccf5b7a14fdf810be06462d2/LICENSE"
},
- version: "4.0.0"
+ version: "5.0.0"
}) // From @typespec/openapi
namespace AntelopeTokenAPI;
@@ -38,10 +38,12 @@ model APIError {
message: string;
}
+alias TimestampType = string;
+
// Models will be present in the OpenAPI components
-model Transfer is Models.Transfer;
-model BalanceChange is Models.BalanceChange;
-model Supply is Models.Supply;
+model Transfer is Models.Transfer;
+model BalanceChange is Models.BalanceChange;
+model Supply is Models.Supply;
model Holder {
account: BalanceChange.account;
balance: BalanceChange.value;
@@ -71,8 +73,8 @@ model UsageResponse {
}
enum SupportedChains {
- EOS: "eos",
- WAX: "wax"
+ EOS,
+ WAX
}
// Alias will *not* be present in the OpenAPI components.
@@ -84,7 +86,7 @@ alias PaginationQueryParams = {
};
// Helper aliases for accessing underlying properties
-alias BlockInfo = Models.BlockInfo;
+alias BlockInfo = Models.BlockInfo;
alias TokenIdentifier = Models.Scope;
@tag("Usage")
@@ -240,5 +242,5 @@ interface Monitoring {
@summary("Prometheus metrics")
@route("/metrics")
@get
- metrics(): string;
+ metrics(): Record;
}
diff --git a/src/usage.ts b/src/usage.ts
index e60f022..c5ca36d 100644
--- a/src/usage.ts
+++ b/src/usage.ts
@@ -37,8 +37,7 @@ export async function makeUsageQuery(ctx: Context, endpoint: UsageEndpoints, use
if (endpoint !== "/chains") {
const q = query_params as ValidUserParams;
- // TODO: Document required database setup
- database = `${q.chain}_tokens_v1`;
+ database = `${q.chain.toLowerCase()}_tokens_v1`;
}
if (endpoint == "/{chain}/balance" || endpoint == "/{chain}/supply") {
@@ -104,7 +103,7 @@ export async function makeUsageQuery(ctx: Context, endpoint: UsageEndpoints, use
for (const chain of supportedChainsSchema._def.values)
query +=
`SELECT '${chain}' as chain, MAX(block_num) as block_num`
- + ` FROM ${chain}_tokens_v1.cursors GROUP BY id`
+ + ` FROM ${chain.toLowerCase()}_tokens_v1.cursors GROUP BY id`
+ ` UNION ALL `;
query = query.substring(0, query.lastIndexOf(' UNION')); // Remove last item ` UNION`
} else if (endpoint == "/{chain}/transfers/{trx_id}") {
diff --git a/static/@openapi-to-graphql/graphql/schema.graphql b/static/@openapi-to-graphql/graphql/schema.graphql
new file mode 100644
index 0000000..d544624
--- /dev/null
+++ b/static/@openapi-to-graphql/graphql/schema.graphql
@@ -0,0 +1,209 @@
+type Query {
+ """
+ Balances of an account.
+
+ Equivalent to GET /{chain}/balance
+ """
+ balance(account: String!, block_num: Int, chain: Chain!, contract: String, limit: Int, page: Int, symcode: String): Balance
+
+ """
+ List of available Antelope chains and corresponding latest block for which data is available.
+
+ Equivalent to GET /chains
+ """
+ chains(limit: Int, page: Int): Chains
+
+ """
+ Checks database connection.
+
+ Equivalent to GET /health
+ """
+ health: String
+
+ """
+ List of holders of a token.
+
+ Equivalent to GET /{chain}/holders
+ """
+ holders(chain: Chain!, contract: String!, limit: Int, page: Int, symcode: String!): Holders
+
+ """
+ Prometheus metrics.
+
+ Equivalent to GET /metrics
+ """
+ metrics: JSON
+
+ """
+ Reflection endpoint to return OpenAPI JSON spec. Also used by Swagger to generate the frontpage.
+
+ Equivalent to GET /openapi
+ """
+ openapi: JSON
+
+ """
+ Total supply for a token.
+
+ Equivalent to GET /{chain}/supply
+ """
+ supply(block_num: Int, chain: Chain!, contract: String!, issuer: String, limit: Int, page: Int, symcode: String!): Supply
+
+ """
+ List of available tokens.
+
+ Equivalent to GET /{chain}/tokens
+ """
+ tokens(chain: Chain!, limit: Int, page: Int): Tokens
+
+ """
+ Specific transfer related to a token.
+
+ Equivalent to GET /{chain}/transfers/{trx_id}
+ """
+ transfer(chain: Chain!, limit: Int, page: Int, trx_id: String!): Transfer2
+
+ """
+ All transfers related to a token.
+
+ Equivalent to GET /{chain}/transfers
+ """
+ transfers(block_range: [Int], chain: Chain!, contract: String, from: String, limit: Int, page: Int, symcode: String, to: String): Transfers
+
+ """
+ API version and Git short commit hash.
+
+ Equivalent to GET /version
+ """
+ version: Version
+}
+
+type Balance {
+ data: [BalanceChange]!
+ meta: ResponseMetadata!
+}
+
+type BalanceChange {
+ account: String!
+ action_index: Int!
+ amount: BigInt!
+ balance: String!
+ balance_delta: BigInt!
+ block_num: Int!
+ contract: String!
+ precision: Int!
+ symcode: String!
+ timestamp: String!
+ trx_id: String!
+ value: Float!
+}
+
+"""
+The `BigInt` scalar type represents non-fractional signed whole numeric values.
+"""
+scalar BigInt
+
+type ResponseMetadata {
+ next_page: BigInt!
+ previous_page: BigInt!
+ statistics: Statistics!
+ total_pages: BigInt!
+ total_results: BigInt!
+}
+
+type Statistics {
+ bytes_read: BigInt!
+ elapsed: Float!
+ rows_read: BigInt!
+}
+
+enum Chain {
+ EOS
+ WAX
+}
+
+type Chains {
+ data: [DataListItem]!
+ meta: ResponseMetadata!
+}
+
+type DataListItem {
+ block_num: Int!
+ chain: SupportedChains!
+}
+
+enum SupportedChains {
+ EOS
+ WAX
+}
+
+type Holders {
+ data: [Holder]!
+ meta: ResponseMetadata!
+}
+
+type Holder {
+ account: String!
+ balance: Float!
+}
+
+"""
+The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
+"""
+scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
+
+type Supply {
+ data: [Supply2]!
+ meta: ResponseMetadata!
+}
+
+type Supply2 {
+ action_index: Int!
+ amount: BigInt!
+ block_num: Int!
+ contract: String!
+ issuer: String!
+ max_supply: String!
+ precision: Int!
+ supply: String!
+ supply_delta: BigInt!
+ symcode: String!
+ timestamp: String!
+ trx_id: String!
+ value: Float!
+}
+
+type Tokens {
+ data: [Supply2]!
+ meta: ResponseMetadata!
+}
+
+type Transfer2 {
+ data: [Transfer]!
+ meta: ResponseMetadata!
+}
+
+type Transfer {
+ action_index: Int!
+ amount: BigInt!
+ block_num: Int!
+ contract: String!
+ from: String!
+ memo: String!
+ precision: Int!
+ quantity: String!
+ symcode: String!
+ timestamp: String!
+ to: String!
+ trx_id: String!
+ value: Float!
+}
+
+type Transfers {
+ data: [Transfer]!
+ meta: ResponseMetadata!
+}
+
+type Version {
+ commit: String!
+ version: String!
+}
\ No newline at end of file
diff --git a/static/@typespec/openapi3/openapi.json b/static/@typespec/openapi3/openapi.json
new file mode 100644
index 0000000..93d72ab
--- /dev/null
+++ b/static/@typespec/openapi3/openapi.json
@@ -0,0 +1,1188 @@
+{
+ "openapi": "3.0.0",
+ "info": {
+ "title": "Antelope Token API",
+ "summary": "Tokens information from the Antelope blockchains, powered by Substreams",
+ "license": {
+ "name": "MIT",
+ "url": "https://github.com/pinax-network/antelope-token-api/blob/4f4bf36341b794c0ccf5b7a14fdf810be06462d2/LICENSE"
+ },
+ "version": "5.0.0"
+ },
+ "tags": [
+ {
+ "name": "Usage"
+ },
+ {
+ "name": "Docs"
+ },
+ {
+ "name": "Monitoring"
+ }
+ ],
+ "paths": {
+ "/chains": {
+ "get": {
+ "tags": [
+ "Usage"
+ ],
+ "operationId": "Usage_chains",
+ "summary": "Chains and latest block available",
+ "description": "List of available Antelope chains and corresponding latest block for which data is available.",
+ "parameters": [
+ {
+ "name": "limit",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 10
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 1
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Array of block information.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "data",
+ "meta"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "chain": {
+ "$ref": "#/components/schemas/SupportedChains"
+ },
+ "block_num": {
+ "type": "integer",
+ "format": "uint64"
+ }
+ },
+ "required": [
+ "chain",
+ "block_num"
+ ]
+ }
+ },
+ "meta": {
+ "$ref": "#/components/schemas/ResponseMetadata"
+ }
+ }
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/health": {
+ "get": {
+ "tags": [
+ "Monitoring"
+ ],
+ "operationId": "Monitoring_health",
+ "summary": "Health check",
+ "description": "Checks database connection.",
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "OK or APIError.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/metrics": {
+ "get": {
+ "tags": [
+ "Monitoring"
+ ],
+ "operationId": "Monitoring_metrics",
+ "summary": "Prometheus metrics",
+ "description": "Prometheus metrics.",
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "Metrics as text.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/openapi": {
+ "get": {
+ "tags": [
+ "Docs"
+ ],
+ "operationId": "Docs_openapi",
+ "summary": "OpenAPI JSON spec",
+ "description": "Reflection endpoint to return OpenAPI JSON spec. Also used by Swagger to generate the frontpage.",
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "The OpenAPI JSON spec",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": {}
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/version": {
+ "get": {
+ "tags": [
+ "Docs"
+ ],
+ "operationId": "Docs_version",
+ "summary": "API version",
+ "description": "API version and Git short commit hash.",
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "The API version and commit hash.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Version"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/{chain}/balance": {
+ "get": {
+ "tags": [
+ "Usage"
+ ],
+ "operationId": "Usage_balance",
+ "summary": "Token balance",
+ "description": "Balances of an account.",
+ "parameters": [
+ {
+ "name": "chain",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/SupportedChains"
+ }
+ },
+ {
+ "name": "block_num",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64"
+ }
+ },
+ {
+ "name": "contract",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "symcode",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "account",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 10
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 1
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Array of balances.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "data",
+ "meta"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/BalanceChange"
+ }
+ },
+ "meta": {
+ "$ref": "#/components/schemas/ResponseMetadata"
+ }
+ }
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/{chain}/holders": {
+ "get": {
+ "tags": [
+ "Usage"
+ ],
+ "operationId": "Usage_holders",
+ "summary": "Token holders",
+ "description": "List of holders of a token.",
+ "parameters": [
+ {
+ "name": "chain",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/SupportedChains"
+ }
+ },
+ {
+ "name": "contract",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "symcode",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 10
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 1
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Array of accounts.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "data",
+ "meta"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Holder"
+ }
+ },
+ "meta": {
+ "$ref": "#/components/schemas/ResponseMetadata"
+ }
+ }
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/{chain}/supply": {
+ "get": {
+ "tags": [
+ "Usage"
+ ],
+ "operationId": "Usage_supply",
+ "summary": "Token supply",
+ "description": "Total supply for a token.",
+ "parameters": [
+ {
+ "name": "chain",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/SupportedChains"
+ }
+ },
+ {
+ "name": "block_num",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64"
+ }
+ },
+ {
+ "name": "issuer",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "contract",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "symcode",
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 10
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 1
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Array of supplies.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "data",
+ "meta"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Supply"
+ }
+ },
+ "meta": {
+ "$ref": "#/components/schemas/ResponseMetadata"
+ }
+ }
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/{chain}/tokens": {
+ "get": {
+ "tags": [
+ "Usage"
+ ],
+ "operationId": "Usage_tokens",
+ "summary": "Tokens",
+ "description": "List of available tokens.",
+ "parameters": [
+ {
+ "name": "chain",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/SupportedChains"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 10
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 1
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Array of supplies.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "data",
+ "meta"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Supply"
+ }
+ },
+ "meta": {
+ "$ref": "#/components/schemas/ResponseMetadata"
+ }
+ }
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/{chain}/transfers": {
+ "get": {
+ "tags": [
+ "Usage"
+ ],
+ "operationId": "Usage_transfers",
+ "summary": "Token transfers",
+ "description": "All transfers related to a token.",
+ "parameters": [
+ {
+ "name": "chain",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/SupportedChains"
+ }
+ },
+ {
+ "name": "block_range",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "integer",
+ "format": "uint64"
+ }
+ },
+ "style": "form",
+ "explode": false
+ },
+ {
+ "name": "from",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "to",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "contract",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "symcode",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 10
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 1
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Array of transfers.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "data",
+ "meta"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Transfer"
+ }
+ },
+ "meta": {
+ "$ref": "#/components/schemas/ResponseMetadata"
+ }
+ }
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/{chain}/transfers/{trx_id}": {
+ "get": {
+ "tags": [
+ "Usage"
+ ],
+ "operationId": "Usage_transfer",
+ "summary": "Token transfer",
+ "description": "Specific transfer related to a token.",
+ "parameters": [
+ {
+ "name": "chain",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "$ref": "#/components/schemas/SupportedChains"
+ }
+ },
+ {
+ "name": "trx_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 10
+ }
+ },
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "uint64",
+ "default": 1
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Array of transfers.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "data",
+ "meta"
+ ],
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Transfer"
+ }
+ },
+ "meta": {
+ "$ref": "#/components/schemas/ResponseMetadata"
+ }
+ }
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/APIError"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "APIError": {
+ "type": "object",
+ "required": [
+ "status",
+ "code",
+ "message"
+ ],
+ "properties": {
+ "status": {
+ "type": "number",
+ "enum": [
+ 500,
+ 504,
+ 400,
+ 401,
+ 403,
+ 404,
+ 405
+ ]
+ },
+ "code": {
+ "type": "string",
+ "enum": [
+ "bad_database_response",
+ "bad_header",
+ "missing_required_header",
+ "bad_query_input",
+ "database_timeout",
+ "forbidden",
+ "internal_server_error",
+ "method_not_allowed",
+ "route_not_found",
+ "unauthorized"
+ ]
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ },
+ "BalanceChange": {
+ "type": "object",
+ "required": [
+ "trx_id",
+ "action_index",
+ "contract",
+ "symcode",
+ "precision",
+ "amount",
+ "value",
+ "block_num",
+ "timestamp",
+ "account",
+ "balance",
+ "balance_delta"
+ ],
+ "properties": {
+ "trx_id": {
+ "type": "string"
+ },
+ "action_index": {
+ "type": "integer",
+ "format": "uint32"
+ },
+ "contract": {
+ "type": "string"
+ },
+ "symcode": {
+ "type": "string"
+ },
+ "precision": {
+ "type": "integer",
+ "format": "uint32"
+ },
+ "amount": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "value": {
+ "type": "number",
+ "format": "double"
+ },
+ "block_num": {
+ "type": "integer",
+ "format": "uint64"
+ },
+ "timestamp": {
+ "type": "string"
+ },
+ "account": {
+ "type": "string"
+ },
+ "balance": {
+ "type": "string"
+ },
+ "balance_delta": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ },
+ "Holder": {
+ "type": "object",
+ "required": [
+ "account",
+ "balance"
+ ],
+ "properties": {
+ "account": {
+ "type": "string"
+ },
+ "balance": {
+ "type": "number",
+ "format": "double"
+ }
+ }
+ },
+ "Pagination": {
+ "type": "object",
+ "required": [
+ "next_page",
+ "previous_page",
+ "total_pages",
+ "total_results"
+ ],
+ "properties": {
+ "next_page": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "previous_page": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "total_pages": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "total_results": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ },
+ "QueryStatistics": {
+ "type": "object",
+ "required": [
+ "elapsed",
+ "rows_read",
+ "bytes_read"
+ ],
+ "properties": {
+ "elapsed": {
+ "type": "number"
+ },
+ "rows_read": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "bytes_read": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ },
+ "ResponseMetadata": {
+ "type": "object",
+ "required": [
+ "statistics",
+ "next_page",
+ "previous_page",
+ "total_pages",
+ "total_results"
+ ],
+ "properties": {
+ "statistics": {
+ "type": "object",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/QueryStatistics"
+ }
+ ],
+ "nullable": true
+ },
+ "next_page": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "previous_page": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "total_pages": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "total_results": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ },
+ "Supply": {
+ "type": "object",
+ "required": [
+ "trx_id",
+ "action_index",
+ "contract",
+ "symcode",
+ "precision",
+ "amount",
+ "value",
+ "block_num",
+ "timestamp",
+ "issuer",
+ "max_supply",
+ "supply",
+ "supply_delta"
+ ],
+ "properties": {
+ "trx_id": {
+ "type": "string"
+ },
+ "action_index": {
+ "type": "integer",
+ "format": "uint32"
+ },
+ "contract": {
+ "type": "string"
+ },
+ "symcode": {
+ "type": "string"
+ },
+ "precision": {
+ "type": "integer",
+ "format": "uint32"
+ },
+ "amount": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "value": {
+ "type": "number",
+ "format": "double"
+ },
+ "block_num": {
+ "type": "integer",
+ "format": "uint64"
+ },
+ "timestamp": {
+ "type": "string"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "max_supply": {
+ "type": "string"
+ },
+ "supply": {
+ "type": "string"
+ },
+ "supply_delta": {
+ "type": "integer",
+ "format": "int64"
+ }
+ }
+ },
+ "SupportedChains": {
+ "type": "string",
+ "enum": [
+ "EOS",
+ "WAX"
+ ]
+ },
+ "Transfer": {
+ "type": "object",
+ "required": [
+ "trx_id",
+ "action_index",
+ "contract",
+ "symcode",
+ "precision",
+ "amount",
+ "value",
+ "block_num",
+ "timestamp",
+ "from",
+ "to",
+ "quantity",
+ "memo"
+ ],
+ "properties": {
+ "trx_id": {
+ "type": "string"
+ },
+ "action_index": {
+ "type": "integer",
+ "format": "uint32"
+ },
+ "contract": {
+ "type": "string"
+ },
+ "symcode": {
+ "type": "string"
+ },
+ "precision": {
+ "type": "integer",
+ "format": "uint32"
+ },
+ "amount": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "value": {
+ "type": "number",
+ "format": "double"
+ },
+ "block_num": {
+ "type": "integer",
+ "format": "uint64"
+ },
+ "timestamp": {
+ "type": "string"
+ },
+ "from": {
+ "type": "string"
+ },
+ "to": {
+ "type": "string"
+ },
+ "quantity": {
+ "type": "string"
+ },
+ "memo": {
+ "type": "string"
+ }
+ }
+ },
+ "Version": {
+ "type": "object",
+ "required": [
+ "version",
+ "commit"
+ ],
+ "properties": {
+ "version": {
+ "type": "string",
+ "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
+ },
+ "commit": {
+ "type": "string",
+ "pattern": "^[0-9a-f]{7}$"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/static/@typespec/protobuf/antelope/eosio/token/v1.proto b/static/@typespec/protobuf/antelope/eosio/token/v1.proto
new file mode 100644
index 0000000..76f028a
--- /dev/null
+++ b/static/@typespec/protobuf/antelope/eosio/token/v1.proto
@@ -0,0 +1,38 @@
+// Generated by Microsoft TypeSpec
+
+syntax = "proto3";
+
+package antelope.eosio.token.v1;
+
+import "google/protobuf/timestamp.proto";
+
+message Transfer {
+ string trx_id = 1;
+ uint32 action_index = 2;
+ string contract = 3;
+ string symcode = 4;
+ uint32 precision = 9;
+ int64 amount = 10;
+ double value = 11;
+ uint64 block_num = 12;
+ google.protobuf.Timestamp timestamp = 13;
+ string from = 5;
+ string to = 6;
+ string quantity = 7;
+ string memo = 8;
+}
+
+message BalanceChange {
+ string trx_id = 1;
+ uint32 action_index = 2;
+ string contract = 3;
+ string symcode = 4;
+ uint32 precision = 8;
+ int64 amount = 9;
+ double value = 10;
+ uint64 block_num = 11;
+ google.protobuf.Timestamp timestamp = 12;
+ string account = 5;
+ string balance = 6;
+ int64 balance_delta = 7;
+}
diff --git a/static/README.md b/static/README.md
new file mode 100644
index 0000000..5a651bc
--- /dev/null
+++ b/static/README.md
@@ -0,0 +1,12 @@
+> [!CAUTION]
+>
+> Static files generated at build time. **DO NOT EDIT MANUALLY**.
+> Use `bun run types` to run the static file generation.
+
+### `@openapi-to-graphql`
+
+GraphQL schema generated with [`openapi-to-graphql-cli`](https://www.npmjs.com/package/openapi-to-graphql-cli) from the [`openapi.json`](@typespec/openapi3/openapi.json) generated by Typespec.
+
+### `@typespec`
+
+Protobuf definitions and OpenAPI schemas generated with Typespec.
\ No newline at end of file
diff --git a/tsp-output/@typespec/openapi3/openapi.json b/tsp-output/@typespec/openapi3/openapi.json
index 794f3ee..93d72ab 100644
--- a/tsp-output/@typespec/openapi3/openapi.json
+++ b/tsp-output/@typespec/openapi3/openapi.json
@@ -7,7 +7,7 @@
"name": "MIT",
"url": "https://github.com/pinax-network/antelope-token-api/blob/4f4bf36341b794c0ccf5b7a14fdf810be06462d2/LICENSE"
},
- "version": "4.0.0"
+ "version": "5.0.0"
},
"tags": [
{
@@ -151,7 +151,8 @@
"content": {
"application/json": {
"schema": {
- "type": "string"
+ "type": "object",
+ "additionalProperties": {}
}
}
}
@@ -914,8 +915,7 @@
"format": "uint64"
},
"timestamp": {
- "type": "integer",
- "format": "int32"
+ "type": "string"
},
"account": {
"type": "string"
@@ -1078,8 +1078,7 @@
"format": "uint64"
},
"timestamp": {
- "type": "integer",
- "format": "int32"
+ "type": "string"
},
"issuer": {
"type": "string"
@@ -1099,8 +1098,8 @@
"SupportedChains": {
"type": "string",
"enum": [
- "eos",
- "wax"
+ "EOS",
+ "WAX"
]
},
"Transfer": {
@@ -1151,8 +1150,7 @@
"format": "uint64"
},
"timestamp": {
- "type": "integer",
- "format": "int32"
+ "type": "string"
},
"from": {
"type": "string"