Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: minswap tokens #2

Merged
merged 30 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
049950e
add tokens yml files and fetcher
rinchan01 Nov 15, 2024
fbcb021
add tokens yml files
rinchan01 Nov 18, 2024
0e0a66f
add tokens yml files
rinchan01 Nov 18, 2024
7cdbef6
fix token yaml files and features
rinchan01 Nov 20, 2024
3025bde
sync maxSupply with decimals
rinchan01 Nov 21, 2024
55974b0
test token files and fix get marketcap logic
rinchan01 Nov 22, 2024
87ac45b
Merge branch 'main' into tlinh
rinchan01 Nov 22, 2024
e70da97
change
rinchan01 Nov 22, 2024
21ace95
fix token yml files and add internal feats
rinchan01 Nov 22, 2024
5298da3
add internal TVL check
rinchan01 Nov 22, 2024
053528d
fix and add comments
rinchan01 Nov 22, 2024
e2ec39b
fix lib config
0xj4m35 Nov 22, 2024
474db22
Merge branch 'tlinh' of github.com:minswap/minswap-tokens into tlinh
0xj4m35 Nov 22, 2024
af1e1f4
format
0xj4m35 Nov 22, 2024
14a6645
fix tvl check
rinchan01 Nov 25, 2024
3a53b65
test ci
rinchan01 Nov 25, 2024
775355a
test ci
rinchan01 Nov 25, 2024
ebe2032
test ci
rinchan01 Nov 25, 2024
d18dca4
test ci
rinchan01 Nov 25, 2024
cf908b3
test ci :(
rinchan01 Nov 25, 2024
bc9084a
test ci :(
rinchan01 Nov 25, 2024
f6dced7
test ci :(
rinchan01 Nov 25, 2024
dcbe940
test ci :( and changes, still bugged with token schema
rinchan01 Nov 26, 2024
a2c85b8
test ci :( and changes, still bugged with token schema
rinchan01 Nov 26, 2024
03147d9
refactor
rinchan01 Nov 26, 2024
0e32d92
fix ci, schema
rinchan01 Nov 26, 2024
268f009
fix edge case formatNumber
rinchan01 Nov 27, 2024
2127742
refactor
rinchan01 Nov 27, 2024
85192c8
del redundant file
rinchan01 Nov 27, 2024
34c1304
run lint and setup jest
0xj4m35 Nov 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
BLOCKFROST_PROJECT_ID=
10 changes: 10 additions & 0 deletions .github/workflows/ci.yaml
rinchan01 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
pull_request:
branches:
- "*"
push:
rinchan01 marked this conversation as resolved.
Show resolved Hide resolved
jobs:
validate-data:
runs-on: ubuntu-latest
Expand All @@ -22,5 +23,14 @@ jobs:
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
tokens:
- 'src/tokens/**'
base: 'tlinh'
rinchan01 marked this conversation as resolved.
Show resolved Hide resolved
- name: Run validate data
if: steps.changes.outputs.tokens == 'true'
working-directory: src/tokens
run: pnpm run test
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
node_modules
.idea
.vscode
.env
act
0xj4m35 marked this conversation as resolved.
Show resolved Hide resolved
build
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"files": {
"ignoreUnknown": false,
"ignore": ["node_modules/**", ".vscode/**"]
"ignore": ["node_modules/**", ".vscode/**", "build", "src/tokens"]
},
"formatter": {
"bracketSpacing": true,
Expand Down
9 changes: 9 additions & 0 deletions environment.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
BLOCKFROST_PROJECT_ID: string;
}
}
}

export {};
100 changes: 100 additions & 0 deletions internal/checkTVL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import fs from "node:fs";
import path from "node:path";
import { BlockFrostAPI } from "@blockfrost/blockfrost-js";
import * as SDK from "@minswap/sdk";
import { dump, load } from "js-yaml";

import type { TokenMetadata } from "@/types";

const MINIMUM_TVL = 1000_000000n; // 1000 ADA
const LIMIT_PAGINATION = 100;
const __dirname = import.meta.dirname;
const TOKEN_DIR = path.join(__dirname, "../src/tokens");

const STABLE_COINS = [
"8db269c3ec630e06ae29f74bc39edd1f87c819f1056206e879a1cd61.446a65644d6963726f555344", // DJED
"f66d78b4a3cb3d37afa0ec36461e51ecbde00f26c8f0a68f94b69880.69555344", // iUSD
"25c5de5f5b286073c593edfd77b48abc7a48e5a4f3d4cd9d428ff935.55534443", // USDC
"c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.5553444d", // USDM
"92776616f1f32c65a173392e4410a3d8c39dcf6ef768c73af164779c.4d79555344", // MyUSD
];

const blockfrostAPI = new BlockFrostAPI({
projectId: process.env["BLOCKFROST_PROJECT_ID"],
network: "mainnet",
});

const blockfrostAdapter = new SDK.BlockfrostAdapter({
networkId: SDK.NetworkId.MAINNET,
blockFrost: blockfrostAPI,
});

export async function verifyTVL() {
rinchan01 marked this conversation as resolved.
Show resolved Hide resolved
const [v1Pools, { pools: v2Pools }] = await Promise.all([getAllV1Pools(), blockfrostAdapter.getAllV2Pools()]);
fs.readdir(TOKEN_DIR, async function (error, files) {
if (error) {
throw error;
}
for (const file of files) {
const filePath = path.join(TOKEN_DIR, file);
const tokenData = <TokenMetadata>load(fs.readFileSync(filePath, "utf8"));
const tokenId = file.split('.')[0];
const newVerified = await checkTVL(v1Pools, v2Pools, tokenId);
if (newVerified === tokenData.verified) {
continue;
}

const tokenInfo = {
...tokenData,
verified: newVerified,
};

let yamlString = "";
for (const [key, value] of Object.entries(tokenInfo)) {
yamlString += `${dump({ [key]: value }, { lineWidth: -1 })}\n`;
}
fs.writeFileSync(filePath, yamlString, "utf8");
}
});
}

async function checkTVL(v1Pools: SDK.PoolV1.State[], v2Pools: SDK.PoolV2.State[], tokenId: string): Promise<boolean> {
if (STABLE_COINS.includes(tokenId)) {
return true;
}

let maxTVL = 0n;

const poolV1 = v1Pools.find((pool) => pool.assetA === SDK.Asset.toString(SDK.ADA) && pool.assetB === tokenId);

maxTVL = (poolV1?.reserveA ?? 0n) * 2n;

const poolV2 = v2Pools.find((pool) => pool.assetA === SDK.Asset.toString(SDK.ADA) && pool.assetB === tokenId);

const tvlV2 = (poolV2?.reserveA ?? 0n) * 2n;
if (maxTVL < tvlV2) {
maxTVL = tvlV2;
}

return maxTVL >= MINIMUM_TVL;
}

async function getAllV1Pools() {
const v1Pools: SDK.PoolV1.State[] = [];

let page = 1;
while (true) {
const paginatedPools = await blockfrostAdapter.getV1Pools({
page,
count: LIMIT_PAGINATION,
});
if (paginatedPools.length === 0) {
break;
}
v1Pools.push(...paginatedPools);
page++;
}
return v1Pools;
}

verifyTVL();
43 changes: 43 additions & 0 deletions internal/validateTokenFiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
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";

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;
}
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}`);
}

}
}

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);
}
0xj4m35 marked this conversation as resolved.
Show resolved Hide resolved

validateTokenFiles(getChangedFiles("yaml"));
199 changes: 199 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/configuration
*/

/** @type {import('jest').Config} */
const config = {
// All imported modules in your tests should be mocked automatically
// automock: false,

// Stop running tests after `n` failures
// bail: 0,

// The directory where Jest should store its cached dependency information
// cacheDirectory: "C:\\Users\\ADMIN\\AppData\\Local\\Temp\\jest",

// Automatically clear mock calls, instances, contexts and results before every test
// clearMocks: false,

// Indicates whether the coverage information should be collected while executing the test
// collectCoverage: false,

// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,

// The directory where Jest should output its coverage files
// coverageDirectory: undefined,

// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "\\\\node_modules\\\\"
// ],

// Indicates which provider should be used to instrument code for coverage
coverageProvider: "v8",

// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],

// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,

// A path to a custom dependency extractor
// dependencyExtractor: undefined,

// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,

// The default configuration for fake timers
// fakeTimers: {
// "enableGlobally": false
// },

// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],

// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,

// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,

// A set of global variables that need to be available in all test environments
globals: {
"ts-jest": {
diagnostics: false,
},
},

// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",

// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],

// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "mjs",
// "cjs",
// "jsx",
// "ts",
// "tsx",
// "json",
// "node"
// ],

// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
moduleNameMapper: {},

// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],

// Activates notifications for test results
// notify: false,

// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",

// A preset that is used as a base for Jest's configuration
// preset: undefined,

// Run tests from one or more projects
// projects: undefined,

// Use this configuration option to add custom reporters to Jest
// reporters: undefined,

// Automatically reset mock state before every test
// resetMocks: false,

// Reset the module registry before running each individual test
// resetModules: false,

// A path to a custom resolver
// resolver: undefined,

// Automatically restore mock state and implementation before every test
// restoreMocks: false,

// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,

// A list of paths to directories that Jest should use to search for files in
roots: ["<rootDir>/test"],

// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",

// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],

// A list of paths to modules that run some code to configure or set up the testing framework before each test
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],

// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,

// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],

// The test environment that will be used for testing
// testEnvironment: "jest-environment-node",

// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},

// Adds a location field to test results
// testLocationInResults: false,

// The glob patterns Jest uses to detect test files
testMatch: ["**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[tj]s?(x)"],

// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "\\\\node_modules\\\\"
// ],

// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],

// This option allows the use of a custom results processor
// testResultsProcessor: undefined,

// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",

// A map from regular expressions to paths to transformers
transform: {
"^.+\\.(ts|tsx)$": "ts-jest",
},

// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "\\\\node_modules\\\\",
// "\\.pnp\\.[^\\\\]+$"
// ],

// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,

// Indicates whether each individual test should be reported during the run
verbose: true,

// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],

// Whether to use watchman for file crawling
// watchman: true,
};

export default config;
Empty file added jest.setup.js
Empty file.
Loading
Loading