107 lines
3.3 KiB
JavaScript
107 lines
3.3 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Sync TAX_RATE options from the on-chain Stake contract to kraiken-lib.
|
||
|
|
*
|
||
|
|
* The Stake.sol contract defines the canonical TAX_RATES array in basis points (yearly percentage * 100).
|
||
|
|
* This script parses that array and regenerates kraiken-lib/src/taxRates.ts so that all front-end consumers
|
||
|
|
* share a single source of truth that mirrors the deployed contract.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { readFileSync, writeFileSync } from 'node:fs';
|
||
|
|
import { fileURLToPath } from 'node:url';
|
||
|
|
import path from 'node:path';
|
||
|
|
|
||
|
|
const __filename = fileURLToPath(import.meta.url);
|
||
|
|
const __dirname = path.dirname(__filename);
|
||
|
|
|
||
|
|
const stakeSourcePath = path.resolve(__dirname, '../onchain/src/Stake.sol');
|
||
|
|
const taxRatesDestPath = path.resolve(__dirname, '../kraiken-lib/src/taxRates.ts');
|
||
|
|
|
||
|
|
const source = readFileSync(stakeSourcePath, 'utf8');
|
||
|
|
|
||
|
|
const match = source.match(/uint256\[]\s+public\s+TAX_RATES\s*=\s*\[([^\]]+)\]/m);
|
||
|
|
if (!match) {
|
||
|
|
throw new Error(`Unable to locate TAX_RATES array in ${stakeSourcePath}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
const rawValues = match[1]
|
||
|
|
.split(',')
|
||
|
|
.map(value => value.trim())
|
||
|
|
.filter(Boolean);
|
||
|
|
|
||
|
|
if (rawValues.length === 0) {
|
||
|
|
throw new Error('TAX_RATES array is empty or failed to parse');
|
||
|
|
}
|
||
|
|
|
||
|
|
const taxRateOptions = rawValues.map((value, index) => {
|
||
|
|
const basisPoints = Number(value.replace(/_/g, ''));
|
||
|
|
if (!Number.isFinite(basisPoints)) {
|
||
|
|
throw new Error(`Invalid TAX_RATES entry "${value}" at index ${index}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
const yearlyPercent = basisPoints;
|
||
|
|
const decimalRate = yearlyPercent / 100;
|
||
|
|
const dailyPercent = yearlyPercent / 365;
|
||
|
|
|
||
|
|
return {
|
||
|
|
index,
|
||
|
|
year: yearlyPercent,
|
||
|
|
daily: Number(dailyPercent.toFixed(5)),
|
||
|
|
decimal: Number(decimalRate.toFixed(2)),
|
||
|
|
};
|
||
|
|
});
|
||
|
|
|
||
|
|
// Generate checksum for runtime validation
|
||
|
|
import { createHash } from 'node:crypto';
|
||
|
|
const taxRatesString = rawValues.join(',');
|
||
|
|
const checksum = createHash('sha256').update(taxRatesString).digest('hex').slice(0, 16);
|
||
|
|
|
||
|
|
const fileHeader = `/**
|
||
|
|
* AUTO-GENERATED FILE — DO NOT EDIT
|
||
|
|
*
|
||
|
|
* Generated by scripts/sync-tax-rates.mjs from onchain/src/Stake.sol.
|
||
|
|
* Run \`node scripts/sync-tax-rates.mjs\` after modifying the contract TAX_RATES array.
|
||
|
|
*/
|
||
|
|
`;
|
||
|
|
|
||
|
|
const interfaceDef = `export interface TaxRateOption {
|
||
|
|
index: number;
|
||
|
|
year: number;
|
||
|
|
daily: number;
|
||
|
|
decimal: number;
|
||
|
|
}
|
||
|
|
`;
|
||
|
|
|
||
|
|
const optionLines = taxRateOptions
|
||
|
|
.map(option => ` { index: ${option.index}, year: ${option.year}, daily: ${option.daily}, decimal: ${option.decimal} }`)
|
||
|
|
.join(',\n');
|
||
|
|
|
||
|
|
const content = `${fileHeader}
|
||
|
|
${interfaceDef}
|
||
|
|
export const TAX_RATE_OPTIONS: TaxRateOption[] = [
|
||
|
|
${optionLines}
|
||
|
|
];
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Checksum of the contract TAX_RATES array (first 16 chars of SHA-256).
|
||
|
|
* Used for runtime validation to ensure kraiken-lib is in sync with deployed contracts.
|
||
|
|
*
|
||
|
|
* To validate at runtime:
|
||
|
|
* 1. Read TAX_RATES array from the Stake contract
|
||
|
|
* 2. Compute checksum: sha256(values.join(',')).slice(0, 16)
|
||
|
|
* 3. Compare with TAX_RATES_CHECKSUM
|
||
|
|
*
|
||
|
|
* If mismatch: Run \`node scripts/sync-tax-rates.mjs\` and rebuild kraiken-lib.
|
||
|
|
*/
|
||
|
|
export const TAX_RATES_CHECKSUM = '${checksum}';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Array of raw year values (matches contract uint256[] TAX_RATES exactly).
|
||
|
|
* Used for runtime validation without needing to parse options.
|
||
|
|
*/
|
||
|
|
export const TAX_RATES_RAW = [${rawValues.join(', ')}];
|
||
|
|
`;
|
||
|
|
|
||
|
|
writeFileSync(taxRatesDestPath, content.trimStart() + '\n');
|