Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
rinchan01 committed Nov 27, 2024
1 parent 268f009 commit 2127742
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 165 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: CI
name: validate-tokens
on:
pull_request:
branches:
- "*"
push:

jobs:
validate-data:
runs-on: ubuntu-latest
Expand All @@ -23,14 +23,5 @@ jobs:
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
tokens:
- 'src/tokens/**'
base: 'tlinh'
- name: Run validate data
if: steps.changes.outputs.tokens == 'true'
working-directory: src/tokens
run: pnpm run test
run: pnpm run check-format
49 changes: 31 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
# Minswap tokens
The merge of deprecated verified-tokens and market cap repositories, which contains a list of tokens, exposes APIs for transparent access to circulating supply and total supply.

## Requirements
For tokens to be verified, ensure your token has a pool with at least **1000 ADA TVL** and follow the structures stated in the instructions below. Any token that has been verified does not meet the requirements in the future would still be unverified.

## How to add my token
Create a pull request adding yaml file according to the following structure in the `src/tokens`:
```yaml
# 1 token = 1 yaml file
# filename: policyId + tokenName (like cardano-token-registry)
# merge verified-tokens and market-cap into 1 new repo, then archive those 2 old repos (to avoid breaking changes with integrators)
# filename/assetId: policyId + hex-coded token name

projectName: Minswap
project: Minswap
# among DeFi, RealFi, GameFi, Meme, Bridge, Metaverse, Wallet, NFT, Oracle, AI, Launchpad, DAO, Stablecoin, Social, Media, Risk Ratings, Index Vaults, DePIN, Other
categories:
- DeFi
- DAO
- DeFi
- DAO

decimals: 0
# not required, among website, twitter, discord, telegram, coinMarketCap, coinGecko
socialLinks:
website: https://
discord: ...

unverified: true # default false, if a token violate verification policy then turn on
verified: true # default true, if a token violate verification policy then switch to false

maxSupply: 500000000
# the following fields are not required
maxSupply: 500000000 # either number or string
# or
maxSupply: https://...

treasuryWallets:
- addr...
- addr...
- https://...

burnWallets:
- addr...
- https://...

# total = max - burn
# circulating = max - burn - treasury
treasury:
- addr...
- stake...
- https://...
- assetId

burn:
- addr...
- stake...
- https://...
- assetId

circulatingOnChain:
- addr...
- stake...
- https://...
- assetId
```
3 changes: 2 additions & 1 deletion internal/checkTVL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ const blockfrostAdapter = new SDK.BlockfrostAdapter({
blockFrost: blockfrostAPI,
});

export async function verifyTVL() {
async function verifyTVL() {
const [v1Pools, { pools: v2Pools }] = await Promise.all([getAllV1Pools(), blockfrostAdapter.getAllV2Pools()]);

fs.readdir(TOKEN_DIR, async function (error, files) {
if (error) {
throw error;
Expand Down
45 changes: 18 additions & 27 deletions internal/validateTokenFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,33 @@ import Ajv from "ajv";
import path from "node:path";
import * as fs from "node:fs";
import { load } from "js-yaml";
import { execSync } from "node:child_process";

import { DEFAULT_TOKEN_DIR } from "@/const";
import type { TokenMetadata } from "@/types";
import { tokenSchema } from "@/token-schema";
import { tokenSchema } from "@/tokenSchema";

const ajv = new Ajv();
const __dirname = import.meta.dirname;
const TOKEN_DIR = path.join(__dirname, `../src/${DEFAULT_TOKEN_DIR}`);

async function validateTokenFiles(files: string[]) {
for (const file of files) {
if (!file.includes("src/tokens")) {
continue;
async function validateTokenFiles() {
fs.readdir(TOKEN_DIR, (error, files) => {
if (error) {
console.log(error);
}
const fileComponents = file.split("/");
const fileName = fileComponents[fileComponents.length - 1];
const filePath = path.join(TOKEN_DIR, `${fileName}`);
const tokenFileData = fs.readFileSync(filePath, "utf-8");
const tokenData: TokenMetadata = {
tokenId: fileName,
...(load(tokenFileData) as Omit<TokenMetadata, "tokenId">),
};
const validate = ajv.validate(tokenSchema, tokenData);
if (!validate) {
throw new Error(`Error validating token, token file: ${fileName}`);
for (const file of files) {
const filePath = path.join(TOKEN_DIR, `${file}`);
const tokenFileData = fs.readFileSync(filePath, "utf-8");
const tokenData: TokenMetadata = {
tokenId: file.split('.')[0],
...(load(tokenFileData) as Omit<TokenMetadata, "tokenId">),
};
const validate = ajv.validate(tokenSchema, tokenData);
if (!validate) {
throw new Error(`Error validating token, token file: ${file}`);
}
}

}
}

function getChangedFiles(extension = "") {
const extensionFilter = extension ? `-- '***.${extension}'` : "";
const command = `git diff --name-only @{u}...HEAD ${extensionFilter}`;
const diff = execSync(command.toString());
return diff.toString().split("\n").filter(Boolean);
});
}

validateTokenFiles(getChangedFiles("yaml"));
validateTokenFiles();
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
"dependencies": {
"@blockfrost/blockfrost-js": "^5.7.0",
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1",
"js-yaml": "^4.1.0",
"ts-jest": "^29.2.5"
}
Expand Down
15 changes: 0 additions & 15 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 3 additions & 66 deletions src/api.ts → src/apis/marketcapApi.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import fs from "node:fs";
import path from "node:path";
import { load } from "js-yaml";

import type { Adapter } from "./adapter";
import type { TokenMetadata } from "./types";
import type {
GetTokenOptions,
MarketCapInfoResponse,
} from "./types";
import { DEFAULT_TOKEN_DIR } from "./const";
import type { Adapter } from "../adapter";
import type { MarketCapInfoResponse, TokenMetadata } from "../types";
import {
formatNumber,
getAmountFromURL,
isAPIEndPoint,
isAddress,
isBigInt,
} from "./utils";
} from "../utils";

export class MarketCapAPI {
private readonly adapter: Adapter;
Expand Down Expand Up @@ -116,57 +107,3 @@ export class MarketCapAPI {
return amounts.reduce((sum, x) => sum + x, 0n);
}
}

export class TokenAPI {
/**
* Get token's metadata by its ID.
* @param tokenId The concatenation of token policy ID and hex-coded token name.
* @returns The token metadata followed the token schema.
*/
public async getToken(tokenId: string) {
try {
const __dirname = import.meta.dirname;
const filePath = path.join(
__dirname,
`${DEFAULT_TOKEN_DIR}/${tokenId}.yaml`
);
const tokenFileData = fs.readFileSync(filePath, "utf-8");
const tokenData: TokenMetadata = {
tokenId,
...(load(tokenFileData) as Omit<TokenMetadata, "tokenId">),
};
return tokenData;
} catch (e) {
console.error(e);
return null;
}
}

/**
* Get all tokens' metadata by its ID.
* @param options Only verified or only tokens with market cap.
* @returns The list of all tokens' metadata.
*/
public async getTokens(options?: GetTokenOptions) {
const __dirname = import.meta.dirname;
const directory = path.join(__dirname, `${DEFAULT_TOKEN_DIR}`);
const tokenList: TokenMetadata[] = [];
const files = fs.readdirSync(directory);
for (const file of files) {
const tokenString = file.split(".")[0];
const token = await this.getToken(tokenString);
if (!token) {
continue;
}
const matchedVerify =
!options?.verifiedOnly || (options?.verifiedOnly && token.verified);
const matchedMarketCap =
!options?.hasMarketCapOnly ||
(options?.hasMarketCapOnly && !!token.maxSupply);
if (matchedVerify && matchedMarketCap) {
tokenList.push(token);
}
}
return tokenList;
}
}
60 changes: 60 additions & 0 deletions src/apis/tokenApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { load } from "js-yaml";

import { DEFAULT_TOKEN_DIR } from "@/const";
import type { GetTokenOptions, TokenMetadata } from "@/types";
import path from "node:path";
import fs from "node:fs";

export class TokenAPI {
/**
* Get token's metadata by its ID.
* @param tokenId The concatenation of token policy ID and hex-coded token name.
* @returns The token metadata followed the token schema.
*/
public async getToken(tokenId: string) {
try {
const __dirname = import.meta.dirname;
const filePath = path.join(
__dirname,
`${DEFAULT_TOKEN_DIR}/${tokenId}.yaml`
);
const tokenFileData = fs.readFileSync(filePath, "utf-8");
const tokenData: TokenMetadata = {
tokenId,
...(load(tokenFileData) as Omit<TokenMetadata, "tokenId">),
};
return tokenData;
} catch (e) {
console.error(e);
return null;
}
}

/**
* Get all tokens' metadata by its ID.
* @param options Only verified or only tokens with market cap.
* @returns The list of all tokens' metadata.
*/
public async getTokens(options?: GetTokenOptions) {
const __dirname = import.meta.dirname;
const directory = path.join(__dirname, `${DEFAULT_TOKEN_DIR}`);
const tokenList: TokenMetadata[] = [];
const files = fs.readdirSync(directory);
for (const file of files) {
const tokenString = file.split(".")[0];
const token = await this.getToken(tokenString);
if (!token) {
continue;
}
const matchedVerify =
!options?.verifiedOnly || (options?.verifiedOnly && token.verified);
const matchedMarketCap =
!options?.hasMarketCapOnly ||
(options?.hasMarketCapOnly && !!token.maxSupply);
if (matchedVerify && matchedMarketCap) {
tokenList.push(token);
}
}
return tokenList;
}
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BlockFrostAdapter } from "./adapter";
import { MarketCapAPI, TokenAPI } from "./api";
import { MarketCapAPI, TokenAPI } from "./apis/marketcapApi";

export const MinswapTokens = {
MarketCapAPI,
Expand Down
Loading

0 comments on commit 2127742

Please sign in to comment.