Compare commits
3 Commits
main
...
as-add-lin
| Author | SHA1 | Date | |
|---|---|---|---|
| 02235b12a9 | |||
|
|
4e73b98a17 | ||
|
|
47af6e0bcf |
3
.eslintignore
Normal file
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
*.js
|
||||
29
.eslintrc.json
Normal file
29
.eslintrc.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"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/no-explicit-any": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": [
|
||||
"warn",
|
||||
{
|
||||
"allowArgumentsExplicitlyTypedAsAny": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"ignorePatterns": ["dist", "node_modules", "*.js"]
|
||||
}
|
||||
42
.gitea/workflows/lint-and-build.yml
Normal file
42
.gitea/workflows/lint-and-build.yml
Normal 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
|
||||
36
.github/workflows/lint-and-build.yml
vendored
Normal file
36
.github/workflows/lint-and-build.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Lint and Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
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 }}
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run lint
|
||||
run: yarn lint
|
||||
|
||||
- name: Run build
|
||||
run: yarn build
|
||||
13
package.json
13
package.json
@ -9,7 +9,9 @@
|
||||
"postbuild": "cp src/schema.graphql dist/schema.graphql",
|
||||
"start": "node dist/index.js",
|
||||
"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": {
|
||||
"apollo-server-express": "^3.12.1",
|
||||
@ -23,6 +25,15 @@
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.21",
|
||||
"@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",
|
||||
"typescript": "^5.5.3"
|
||||
}
|
||||
|
||||
@ -26,14 +26,14 @@ interface BlockData {
|
||||
}
|
||||
|
||||
interface PointLockedEvent {
|
||||
__typename: "PointLockedEvent";
|
||||
__typename: 'PointLockedEvent';
|
||||
azimuth_id: string;
|
||||
point: string;
|
||||
lock_period: number;
|
||||
}
|
||||
|
||||
interface LockdropClosedEvent {
|
||||
__typename: "LockdropClosedEvent";
|
||||
__typename: 'LockdropClosedEvent';
|
||||
ok: boolean;
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ interface GeneratedData {
|
||||
};
|
||||
}
|
||||
|
||||
function generateMockBlock(): BlockData {
|
||||
function generateMockBlock (): BlockData {
|
||||
const sixMonthsAgo = Math.floor(Date.now() / 1000) - (6 * 30 * 24 * 60 * 60);
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
|
||||
@ -58,15 +58,15 @@ function generateMockBlock(): BlockData {
|
||||
return {
|
||||
hash: `0x${Math.random().toString(16).substr(2, 64)}`,
|
||||
number: randomBlockNumber,
|
||||
timestamp: randomTimestamp,
|
||||
timestamp: randomTimestamp
|
||||
};
|
||||
}
|
||||
|
||||
function generateRandomLockPeriod(): number {
|
||||
function generateRandomLockPeriod (): number {
|
||||
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 events: EventInRange[] = [];
|
||||
@ -115,11 +115,11 @@ export function generateDataFromParticipants(verifiedParticipantsPath: string):
|
||||
const event: EventInRange = {
|
||||
block,
|
||||
event: {
|
||||
__typename: "PointLockedEvent",
|
||||
__typename: 'PointLockedEvent',
|
||||
azimuth_id: azimuthId,
|
||||
point,
|
||||
lock_period: lockPeriod,
|
||||
},
|
||||
lock_period: lockPeriod
|
||||
}
|
||||
};
|
||||
events.push(event);
|
||||
}
|
||||
@ -130,19 +130,19 @@ export function generateDataFromParticipants(verifiedParticipantsPath: string):
|
||||
events.push({
|
||||
block: latestBlock,
|
||||
event: {
|
||||
__typename: "LockdropClosedEvent",
|
||||
ok: true,
|
||||
},
|
||||
__typename: 'LockdropClosedEvent',
|
||||
ok: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
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));
|
||||
}
|
||||
|
||||
@ -4,12 +4,12 @@ import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { resolvers } from './resolvers';
|
||||
|
||||
async function startServer() {
|
||||
async function startServer () {
|
||||
const typeDefs = readFileSync(join(__dirname, 'schema.graphql'), 'utf8');
|
||||
|
||||
const server = new ApolloServer({
|
||||
typeDefs,
|
||||
resolvers,
|
||||
resolvers
|
||||
});
|
||||
|
||||
await server.start();
|
||||
|
||||
@ -10,7 +10,7 @@ const MAX_GALAXIES = 256;
|
||||
const MAX_STARS = 65280;
|
||||
|
||||
// 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 keypair = await Secp256k1.makeKeypair(privkeyBytes);
|
||||
const pubkey = Secp256k1.compressPubkey(keypair.pubkey);
|
||||
@ -27,7 +27,7 @@ async function generateCosmosAddress(): Promise<{ address: string; privateKey: s
|
||||
}
|
||||
|
||||
// Generate real Ethereum address
|
||||
function generateEthereumAddress(): { address: string; privateKey: string } {
|
||||
function generateEthereumAddress (): { address: string; privateKey: string } {
|
||||
const wallet = Wallet.createRandom();
|
||||
return {
|
||||
address: wallet.address,
|
||||
@ -36,7 +36,7 @@ function generateEthereumAddress(): { address: string; privateKey: string } {
|
||||
}
|
||||
|
||||
// Generate Urbit point names using urbit-ob
|
||||
function getUrbitPointName(id: number): string {
|
||||
function getUrbitPointName (id: number): string {
|
||||
return patp(id.toString());
|
||||
}
|
||||
|
||||
@ -88,11 +88,11 @@ export class ParticipantGenerator {
|
||||
private usedGalaxies: Set<number> = new Set();
|
||||
private usedStars: Set<number> = new Set();
|
||||
|
||||
constructor(config: GeneratorConfig) {
|
||||
constructor (config: GeneratorConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
private shuffleArray<T>(array: T[]): T[] {
|
||||
private shuffleArray<T> (array: T[]): T[] {
|
||||
const shuffled = [...array];
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
@ -101,19 +101,19 @@ export class ParticipantGenerator {
|
||||
return shuffled;
|
||||
}
|
||||
|
||||
private getAvailableGalaxies(): number[] {
|
||||
private getAvailableGalaxies (): number[] {
|
||||
const galaxies = Array.from({ length: MAX_GALAXIES }, (_, i) => i);
|
||||
return this.shuffleArray(galaxies).slice(0, this.config.galaxyCount);
|
||||
}
|
||||
|
||||
private getAvailableStars(): number[] {
|
||||
private getAvailableStars (): number[] {
|
||||
// Stars start from MAX_GALAXIES (after galaxies)
|
||||
const stars = Array.from({ length: MAX_STARS }, (_, i) => i + MAX_GALAXIES);
|
||||
return this.shuffleArray(stars).slice(0, this.config.starCount);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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)
|
||||
private distributeStars(availableStars: number[]): number[][] {
|
||||
private distributeStars (availableStars: number[]): number[][] {
|
||||
const starAllocation: number[][] = Array.from({ length: this.config.totalParticipants }, () => []);
|
||||
const shuffledStars = this.shuffleArray([...availableStars]);
|
||||
|
||||
@ -143,7 +143,7 @@ export class ParticipantGenerator {
|
||||
return starAllocation;
|
||||
}
|
||||
|
||||
async generate(): Promise<{ participants: VerifiedParticipant[]; accounts: GeneratedAccount[]; stats: GenerationStats }> {
|
||||
async generate (): Promise<{ participants: VerifiedParticipant[]; accounts: GeneratedAccount[]; stats: GenerationStats }> {
|
||||
const participants: VerifiedParticipant[] = [];
|
||||
this.accounts = [];
|
||||
this.usedGalaxies.clear();
|
||||
@ -192,10 +192,10 @@ export class ParticipantGenerator {
|
||||
attestation: {
|
||||
payload: {
|
||||
address: ethereumAccount.address,
|
||||
msg: "Onboarding my Azimuth ID onto ZenithChain",
|
||||
msg: 'Onboarding my Azimuth ID onto ZenithChain',
|
||||
payload: {
|
||||
address: cosmosAccount.address,
|
||||
msg: "Onboarding my validator onto ZenithChain",
|
||||
msg: 'Onboarding my validator onto ZenithChain',
|
||||
owned_points: {
|
||||
galaxy,
|
||||
stars
|
||||
@ -207,7 +207,7 @@ export class ParticipantGenerator {
|
||||
`dummy_zenith_sig_${i}_${Math.random().toString(36).substring(2, 15)}`
|
||||
]
|
||||
},
|
||||
role: isValidator ? "validator" : "delegator"
|
||||
role: isValidator ? 'validator' : 'delegator'
|
||||
};
|
||||
|
||||
participants.push(participant);
|
||||
@ -233,7 +233,7 @@ export class ParticipantGenerator {
|
||||
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
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
@ -257,7 +257,7 @@ export class ParticipantGenerator {
|
||||
}
|
||||
|
||||
// Validation function
|
||||
function validateConfig(config: GeneratorConfig): void {
|
||||
function validateConfig (config: GeneratorConfig): void {
|
||||
const errors: string[] = [];
|
||||
|
||||
if (config.totalParticipants <= 0) {
|
||||
@ -297,7 +297,7 @@ function validateConfig(config: GeneratorConfig): void {
|
||||
}
|
||||
|
||||
// CLI interface
|
||||
function parseArgs(): GeneratorConfig {
|
||||
function parseArgs (): GeneratorConfig {
|
||||
const args = process.argv.slice(2);
|
||||
const config: GeneratorConfig = {
|
||||
totalParticipants: 400,
|
||||
@ -374,10 +374,10 @@ if (require.main === module) {
|
||||
if (fs.existsSync(statsPath)) existingFiles.push('point-allocation-stats.json');
|
||||
|
||||
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)}`));
|
||||
console.warn(` This will replace all existing generated participant data.`);
|
||||
console.warn(` Press Ctrl+C to cancel or any key to continue...`);
|
||||
console.warn(' This will replace all existing generated participant data.');
|
||||
console.warn(' Press Ctrl+C to cancel or any key to continue...');
|
||||
|
||||
// Wait for user input
|
||||
process.stdin.setRawMode(true);
|
||||
@ -398,7 +398,7 @@ if (require.main === module) {
|
||||
startGeneration();
|
||||
}
|
||||
|
||||
function startGeneration() {
|
||||
function startGeneration () {
|
||||
console.log('\nStarting generation...\n');
|
||||
|
||||
const generator = new ParticipantGenerator(config);
|
||||
|
||||
@ -3,7 +3,7 @@ import * as path from 'path';
|
||||
|
||||
import { generateDataFromParticipants, saveGeneratedData } from './data-generator';
|
||||
|
||||
function loadOrGenerateData() {
|
||||
function loadOrGenerateData (): any {
|
||||
const outputDir = process.env.GENERATED_WATCHER_EVENTS_OUTPUT_PATH || path.join(process.cwd(), 'generated');
|
||||
|
||||
// Ensure output directory exists
|
||||
@ -14,7 +14,7 @@ function loadOrGenerateData() {
|
||||
const dataPath = path.join(outputDir, 'watcher-events.json');
|
||||
const verifiedParticipantsPath = process.env.VERIFIED_PARTICIPANTS_PATH;
|
||||
|
||||
// Fallback to existing data
|
||||
// Fallback to existing data
|
||||
if (fs.existsSync(dataPath)) {
|
||||
console.log('Using existing watcher-events.json...');
|
||||
return JSON.parse(fs.readFileSync(dataPath, 'utf8'));
|
||||
@ -39,7 +39,7 @@ const data = loadOrGenerateData();
|
||||
|
||||
export const resolvers = {
|
||||
Query: {
|
||||
eventsInRange: (_: any, args: { fromBlockNumber: number; toBlockNumber: number; name?: string }) => {
|
||||
eventsInRange: (_: any, args: { fromBlockNumber: number; toBlockNumber: number; name?: string }): any[] => {
|
||||
const events = data.data.eventsInRange;
|
||||
|
||||
return events.filter((event: any) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user