Compare commits

...

6 Commits

Author SHA1 Message Date
75de69770e Test lint CI
All checks were successful
Lint and Build / lint-and-build (18.x) (push) Successful in 39s
2025-12-29 14:36:44 +05:30
d051054aa4 Remove any type usage
All checks were successful
Lint and Build / lint-and-build (18.x) (pull_request) Successful in 36s
2025-12-29 12:33:54 +05:30
df8fade1a6 Remove unnecessary workflow 2025-12-29 10:30:56 +05:30
02235b12a9 Add lint and build gitea workflow 2025-12-23 18:17:03 +05:30
AdityaSalunkhe21
4e73b98a17 Add lint and build github workflow 2025-12-19 13:52:25 +05:30
AdityaSalunkhe21
47af6e0bcf Fix lint and type errors 2025-12-19 13:50:52 +05:30
9 changed files with 1846 additions and 63 deletions

2
.eslintignore Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

23
.eslintrc.json Normal file
View File

@ -0,0 +1,23 @@
{
"env": {
"es2021": true,
"node": true
},
"extends": [
"semistandard",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
"@typescript-eslint/explicit-module-boundary-types": "warn"
},
"ignorePatterns": ["dist", "node_modules"]
}

View File

@ -0,0 +1,42 @@
name: Lint and Build
on:
push:
# branches:
# - main
paths:
- 'src/**'
pull_request:
branches:
- main
paths:
- 'src/**'
jobs:
lint-and-build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Enable corepack and yarn
run: corepack enable
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run lint
run: yarn lint
- name: Run build
run: yarn build

View File

@ -9,7 +9,9 @@
"postbuild": "cp src/schema.graphql dist/schema.graphql", "postbuild": "cp src/schema.graphql dist/schema.graphql",
"start": "node dist/index.js", "start": "node dist/index.js",
"dev": "ts-node src/index.ts", "dev": "ts-node src/index.ts",
"generate-participants": "node dist/participant-generator.js" "generate-participants": "node dist/participant-generator.js",
"lint": "eslint --max-warnings=0 .",
"lint:fix": "eslint . --fix"
}, },
"dependencies": { "dependencies": {
"apollo-server-express": "^3.12.1", "apollo-server-express": "^3.12.1",
@ -23,6 +25,15 @@
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/node": "^20.14.10", "@types/node": "^20.14.10",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.57.0",
"eslint-config-semistandard": "^15.0.1",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^5.0.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.5.3" "typescript": "^5.5.3"
} }

View File

@ -1,5 +1,7 @@
import * as fs from 'fs'; import * as fs from 'fs';
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
interface VerifiedParticipant { interface VerifiedParticipant {
attestation: { attestation: {
payload: { payload: {
@ -19,36 +21,37 @@ interface VerifiedParticipant {
role: string; role: string;
} }
interface BlockData { export interface BlockData {
hash: string; hash: string;
number: number; number: number;
timestamp: number; timestamp: number;
} }
interface PointLockedEvent { export interface PointLockedEvent {
__typename: "PointLockedEvent"; __typename: 'PointLockedEvent';
azimuth_id: string; azimuth_id: string;
point: string; point: string;
lock_period: number; lock_period: number;
} }
interface LockdropClosedEvent { export interface LockdropClosedEvent {
__typename: "LockdropClosedEvent"; __typename: 'LockdropClosedEvent';
ok: boolean; ok: boolean;
} }
interface EventInRange { export interface EventInRange {
block: BlockData; block: BlockData;
contract: string;
event: PointLockedEvent | LockdropClosedEvent; event: PointLockedEvent | LockdropClosedEvent;
} }
interface GeneratedData { export interface GeneratedData {
data: { data: {
eventsInRange: EventInRange[]; eventsInRange: EventInRange[];
}; };
} }
function generateMockBlock(): BlockData { function generateMockBlock (): BlockData {
const sixMonthsAgo = Math.floor(Date.now() / 1000) - (6 * 30 * 24 * 60 * 60); const sixMonthsAgo = Math.floor(Date.now() / 1000) - (6 * 30 * 24 * 60 * 60);
const now = Math.floor(Date.now() / 1000); const now = Math.floor(Date.now() / 1000);
@ -58,15 +61,15 @@ function generateMockBlock(): BlockData {
return { return {
hash: `0x${Math.random().toString(16).substr(2, 64)}`, hash: `0x${Math.random().toString(16).substr(2, 64)}`,
number: randomBlockNumber, number: randomBlockNumber,
timestamp: randomTimestamp, timestamp: randomTimestamp
}; };
} }
function generateRandomLockPeriod(): number { function generateRandomLockPeriod (): number {
return Math.floor(Math.random() * 5) + 1; // 1 to 5 years return Math.floor(Math.random() * 5) + 1; // 1 to 5 years
} }
export function generateDataFromParticipants(verifiedParticipantsPath: string): GeneratedData { export function generateDataFromParticipants (verifiedParticipantsPath: string): GeneratedData {
const participantsData = JSON.parse(fs.readFileSync(verifiedParticipantsPath, 'utf8')) as VerifiedParticipant[]; const participantsData = JSON.parse(fs.readFileSync(verifiedParticipantsPath, 'utf8')) as VerifiedParticipant[];
const events: EventInRange[] = []; const events: EventInRange[] = [];
@ -114,12 +117,13 @@ export function generateDataFromParticipants(verifiedParticipantsPath: string):
const event: EventInRange = { const event: EventInRange = {
block, block,
contract: ZERO_ADDRESS,
event: { event: {
__typename: "PointLockedEvent", __typename: 'PointLockedEvent',
azimuth_id: azimuthId, azimuth_id: azimuthId,
point, point,
lock_period: lockPeriod, lock_period: lockPeriod
}, }
}; };
events.push(event); events.push(event);
} }
@ -129,20 +133,21 @@ export function generateDataFromParticipants(verifiedParticipantsPath: string):
if (latestBlock) { if (latestBlock) {
events.push({ events.push({
block: latestBlock, block: latestBlock,
contract: ZERO_ADDRESS,
event: { event: {
__typename: "LockdropClosedEvent", __typename: 'LockdropClosedEvent',
ok: true, ok: true
}, }
}); });
} }
return { return {
data: { data: {
eventsInRange: events, eventsInRange: events
}, }
}; };
} }
export function saveGeneratedData(data: GeneratedData, outputPath: string): void { export function saveGeneratedData (data: GeneratedData, outputPath: string): void {
fs.writeFileSync(outputPath, JSON.stringify(data, null, 2)); fs.writeFileSync(outputPath, JSON.stringify(data, null, 2));
} }

View File

@ -4,18 +4,19 @@ import { readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { resolvers } from './resolvers'; import { resolvers } from './resolvers';
async function startServer() { // Test lint CI
async function startServer () {
const typeDefs = readFileSync(join(__dirname, 'schema.graphql'), 'utf8'); const typeDefs = readFileSync(join(__dirname, 'schema.graphql'), 'utf8');
const server = new ApolloServer({ const server = new ApolloServer({
typeDefs, typeDefs,
resolvers, resolvers
}); });
await server.start(); await server.start();
const app = express(); const app = express();
server.applyMiddleware({ app: app as any }); server.applyMiddleware({ app });
const PORT = process.env.PORT || 6000; const PORT = process.env.PORT || 6000;

View File

@ -10,7 +10,7 @@ const MAX_GALAXIES = 256;
const MAX_STARS = 65280; const MAX_STARS = 65280;
// Generate real Cosmos address with zenith prefix using standard derivation // Generate real Cosmos address with zenith prefix using standard derivation
async function generateCosmosAddress(): Promise<{ address: string; privateKey: string }> { async function generateCosmosAddress (): Promise<{ address: string; privateKey: string }> {
const privkeyBytes = Random.getBytes(32); const privkeyBytes = Random.getBytes(32);
const keypair = await Secp256k1.makeKeypair(privkeyBytes); const keypair = await Secp256k1.makeKeypair(privkeyBytes);
const pubkey = Secp256k1.compressPubkey(keypair.pubkey); const pubkey = Secp256k1.compressPubkey(keypair.pubkey);
@ -27,7 +27,7 @@ async function generateCosmosAddress(): Promise<{ address: string; privateKey: s
} }
// Generate real Ethereum address // Generate real Ethereum address
function generateEthereumAddress(): { address: string; privateKey: string } { function generateEthereumAddress (): { address: string; privateKey: string } {
const wallet = Wallet.createRandom(); const wallet = Wallet.createRandom();
return { return {
address: wallet.address, address: wallet.address,
@ -36,7 +36,7 @@ function generateEthereumAddress(): { address: string; privateKey: string } {
} }
// Generate Urbit point names using urbit-ob // Generate Urbit point names using urbit-ob
function getUrbitPointName(id: number): string { function getUrbitPointName (id: number): string {
return patp(id.toString()); return patp(id.toString());
} }
@ -88,11 +88,11 @@ export class ParticipantGenerator {
private usedGalaxies: Set<number> = new Set(); private usedGalaxies: Set<number> = new Set();
private usedStars: Set<number> = new Set(); private usedStars: Set<number> = new Set();
constructor(config: GeneratorConfig) { constructor (config: GeneratorConfig) {
this.config = config; this.config = config;
} }
private shuffleArray<T>(array: T[]): T[] { private shuffleArray<T> (array: T[]): T[] {
const shuffled = [...array]; const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) { for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1)); const j = Math.floor(Math.random() * (i + 1));
@ -101,19 +101,19 @@ export class ParticipantGenerator {
return shuffled; return shuffled;
} }
private getAvailableGalaxies(): number[] { private getAvailableGalaxies (): number[] {
const galaxies = Array.from({ length: MAX_GALAXIES }, (_, i) => i); const galaxies = Array.from({ length: MAX_GALAXIES }, (_, i) => i);
return this.shuffleArray(galaxies).slice(0, this.config.galaxyCount); return this.shuffleArray(galaxies).slice(0, this.config.galaxyCount);
} }
private getAvailableStars(): number[] { private getAvailableStars (): number[] {
// Stars start from MAX_GALAXIES (after galaxies) // Stars start from MAX_GALAXIES (after galaxies)
const stars = Array.from({ length: MAX_STARS }, (_, i) => i + MAX_GALAXIES); const stars = Array.from({ length: MAX_STARS }, (_, i) => i + MAX_GALAXIES);
return this.shuffleArray(stars).slice(0, this.config.starCount); return this.shuffleArray(stars).slice(0, this.config.starCount);
} }
// Distribute all available galaxies among first participants (they become validators) // Distribute all available galaxies among first participants (they become validators)
private distributeGalaxies(availableGalaxies: number[]): number[] { private distributeGalaxies (availableGalaxies: number[]): number[] {
const galaxyAllocation: number[] = new Array(this.config.totalParticipants).fill(null); const galaxyAllocation: number[] = new Array(this.config.totalParticipants).fill(null);
// First galaxyCount participants get galaxies (and become validators) // First galaxyCount participants get galaxies (and become validators)
@ -125,7 +125,7 @@ export class ParticipantGenerator {
} }
// Distribute all available stars randomly among all participants (each gets at least 1) // Distribute all available stars randomly among all participants (each gets at least 1)
private distributeStars(availableStars: number[]): number[][] { private distributeStars (availableStars: number[]): number[][] {
const starAllocation: number[][] = Array.from({ length: this.config.totalParticipants }, () => []); const starAllocation: number[][] = Array.from({ length: this.config.totalParticipants }, () => []);
const shuffledStars = this.shuffleArray([...availableStars]); const shuffledStars = this.shuffleArray([...availableStars]);
@ -143,7 +143,7 @@ export class ParticipantGenerator {
return starAllocation; return starAllocation;
} }
async generate(): Promise<{ participants: VerifiedParticipant[]; accounts: GeneratedAccount[]; stats: GenerationStats }> { async generate (): Promise<{ participants: VerifiedParticipant[]; accounts: GeneratedAccount[]; stats: GenerationStats }> {
const participants: VerifiedParticipant[] = []; const participants: VerifiedParticipant[] = [];
this.accounts = []; this.accounts = [];
this.usedGalaxies.clear(); this.usedGalaxies.clear();
@ -192,10 +192,10 @@ export class ParticipantGenerator {
attestation: { attestation: {
payload: { payload: {
address: ethereumAccount.address, address: ethereumAccount.address,
msg: "Onboarding my Azimuth ID onto ZenithChain", msg: 'Onboarding my Azimuth ID onto ZenithChain',
payload: { payload: {
address: cosmosAccount.address, address: cosmosAccount.address,
msg: "Onboarding my validator onto ZenithChain", msg: 'Onboarding my validator onto ZenithChain',
owned_points: { owned_points: {
galaxy, galaxy,
stars stars
@ -207,7 +207,7 @@ export class ParticipantGenerator {
`dummy_zenith_sig_${i}_${Math.random().toString(36).substring(2, 15)}` `dummy_zenith_sig_${i}_${Math.random().toString(36).substring(2, 15)}`
] ]
}, },
role: isValidator ? "validator" : "delegator" role: isValidator ? 'validator' : 'delegator'
}; };
participants.push(participant); participants.push(participant);
@ -233,7 +233,7 @@ export class ParticipantGenerator {
return { participants, accounts: this.accounts, stats }; return { participants, accounts: this.accounts, stats };
} }
saveToFiles(outputDir: string, participants: VerifiedParticipant[], accounts: GeneratedAccount[], stats: GenerationStats): void { saveToFiles (outputDir: string, participants: VerifiedParticipant[], accounts: GeneratedAccount[], stats: GenerationStats): void {
// Ensure output directory exists // Ensure output directory exists
if (!fs.existsSync(outputDir)) { if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true }); fs.mkdirSync(outputDir, { recursive: true });
@ -257,7 +257,7 @@ export class ParticipantGenerator {
} }
// Validation function // Validation function
function validateConfig(config: GeneratorConfig): void { function validateConfig (config: GeneratorConfig): void {
const errors: string[] = []; const errors: string[] = [];
if (config.totalParticipants <= 0) { if (config.totalParticipants <= 0) {
@ -297,7 +297,7 @@ function validateConfig(config: GeneratorConfig): void {
} }
// CLI interface // CLI interface
function parseArgs(): GeneratorConfig { function parseArgs (): GeneratorConfig {
const args = process.argv.slice(2); const args = process.argv.slice(2);
const config: GeneratorConfig = { const config: GeneratorConfig = {
totalParticipants: 400, totalParticipants: 400,
@ -374,10 +374,10 @@ if (require.main === module) {
if (fs.existsSync(statsPath)) existingFiles.push('point-allocation-stats.json'); if (fs.existsSync(statsPath)) existingFiles.push('point-allocation-stats.json');
if (existingFiles.length > 0) { if (existingFiles.length > 0) {
console.warn(`\nWARNING: The following files will be overwritten:`); console.warn('\nWARNING: The following files will be overwritten:');
existingFiles.forEach(file => console.warn(` - ${path.join(config.outputDir, file)}`)); existingFiles.forEach(file => console.warn(` - ${path.join(config.outputDir, file)}`));
console.warn(` This will replace all existing generated participant data.`); console.warn(' This will replace all existing generated participant data.');
console.warn(` Press Ctrl+C to cancel or any key to continue...`); console.warn(' Press Ctrl+C to cancel or any key to continue...');
// Wait for user input // Wait for user input
process.stdin.setRawMode(true); process.stdin.setRawMode(true);
@ -398,7 +398,7 @@ if (require.main === module) {
startGeneration(); startGeneration();
} }
function startGeneration() { function startGeneration () {
console.log('\nStarting generation...\n'); console.log('\nStarting generation...\n');
const generator = new ParticipantGenerator(config); const generator = new ParticipantGenerator(config);

View File

@ -1,9 +1,14 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { generateDataFromParticipants, saveGeneratedData } from './data-generator'; import {
generateDataFromParticipants,
saveGeneratedData,
type GeneratedData,
type EventInRange
} from './data-generator';
function loadOrGenerateData() { function loadOrGenerateData (): GeneratedData {
const outputDir = process.env.GENERATED_WATCHER_EVENTS_OUTPUT_PATH || path.join(process.cwd(), 'generated'); const outputDir = process.env.GENERATED_WATCHER_EVENTS_OUTPUT_PATH || path.join(process.cwd(), 'generated');
// Ensure output directory exists // Ensure output directory exists
@ -14,7 +19,7 @@ function loadOrGenerateData() {
const dataPath = path.join(outputDir, 'watcher-events.json'); const dataPath = path.join(outputDir, 'watcher-events.json');
const verifiedParticipantsPath = process.env.VERIFIED_PARTICIPANTS_PATH; const verifiedParticipantsPath = process.env.VERIFIED_PARTICIPANTS_PATH;
// Fallback to existing data // Fallback to existing data
if (fs.existsSync(dataPath)) { if (fs.existsSync(dataPath)) {
console.log('Using existing watcher-events.json...'); console.log('Using existing watcher-events.json...');
return JSON.parse(fs.readFileSync(dataPath, 'utf8')); return JSON.parse(fs.readFileSync(dataPath, 'utf8'));
@ -39,10 +44,10 @@ const data = loadOrGenerateData();
export const resolvers = { export const resolvers = {
Query: { Query: {
eventsInRange: (_: any, args: { fromBlockNumber: number; toBlockNumber: number; name?: string }) => { eventsInRange: (_: unknown, args: { fromBlockNumber: number; toBlockNumber: number; name?: string }): EventInRange[] => {
const events = data.data.eventsInRange; const events = data.data.eventsInRange;
return events.filter((event: any) => { return events.filter((event: EventInRange) => {
const blockNumber = event.block.number; const blockNumber = event.block.number;
const inRange = blockNumber >= args.fromBlockNumber && blockNumber <= args.toBlockNumber; const inRange = blockNumber >= args.fromBlockNumber && blockNumber <= args.toBlockNumber;

1722
yarn.lock

File diff suppressed because it is too large Load Diff