Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {addCommand as addFork} from './commands/fork';
import {addCommand as addGovernance} from './commands/governance';
import {addCommand as addIpfsCommand} from './commands/ipfsUpload';
import {addCommand as addCapoCommand} from './commands/capo';
import {addCommand as addCapoSvrCommand} from './commands/capoSvr';

const program = new Command();

Expand All @@ -32,5 +33,6 @@ addDiffSnapshots(program);
addFork(program);
addIpfsCommand(program);
addCapoCommand(program);
addCapoSvrCommand(program);

program.parse();
22 changes: 22 additions & 0 deletions src/commands/capoSvr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import fs from 'node:fs';
import type {Command} from '@commander-js/extra-typings';
import {generateSvrCapoReport} from '../reports/capo-svr-comparative-report';
import {readJsonFile, readJsonString} from '../utils/json';

export function addCommand(program: Command) {
program
.command('capo-svr-report')
.description('generate a capo svr comparative report')
.argument('<source>')
.option('-o, --out <string>', 'output path')
.option('--stringMode', 'expects input to be a string, not paths')
.action(async (_source, options) => {
const source = options.stringMode ? readJsonString(_source) : readJsonFile(_source);
const content = await generateSvrCapoReport(source);
if (options.out) {
fs.writeFileSync(options.out, content);
} else {
console.log(content);
}
});
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export * from './govv3/generateProposalReport';
export * from './utils/tenderlyClient';
export * from './utils/logger';
export * from './govv3/utils/checkAddress';
export * from './reports/capo-report';
export * from './reports/capo-svr-comparative-report';
37 changes: 37 additions & 0 deletions src/reports/__snapshots__/capo-svr-report.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`capo svr report > should generate a well formatted capo svr report 1`] = `
"# Capo Comparative Report

# Capped wstETH / stETH(ETH) / USD

- Difference between adapters using SVR and regular Chainlink Feeds

| SVR Adapter | Regular Adapter | Diff | Date |
| --- | --- | --- | --- |
| 1880.1097014 | 1880.16617657 | 0.00% | 12 Apr 2025 |
| 1940.99317901 | 1934.84763392 | 0.32% | 13 Apr 2025 |
| 1951.25160577 | 1948.99310701 | 0.12% | 14 Apr 2025 |
| 1968.85656094 | 1968.56171868 | 0.01% | 15 Apr 2025 |
| 1880.44218254 | 1880.88400462 | 0.02% | 16 Apr 2025 |
| 1927.14919798 | 1921.9665194 | 0.27% | 17 Apr 2025 |
| 1901.98709042 | 1901.24372975 | 0.04% | 18 Apr 2025 |
| 1922.66605311 | 1922.94047495 | 0.01% | 19 Apr 2025 |
| 1908.33882018 | 1906.22505555 | 0.11% | 20 Apr 2025 |
| 1973.33083291 | 1970.15250316 | 0.16% | 21 Apr 2025 |
| 1948.43062491 | 1949.37422474 | 0.05% | 22 Apr 2025 |
| 2160.35296377 | 2171.82424304 | 0.53% | 23 Apr 2025 |
| 2093.83167086 | 2093.91812992 | 0.00% | 24 Apr 2025 |
| 2148.42289872 | 2146.33325394 | 0.10% | 25 Apr 2025 |
| 2146.93062115 | 2146.64704136 | 0.01% | 26 Apr 2025 |
| 2167.39047482 | 2161.98612144 | 0.25% | 27 Apr 2025 |
| 2169.22825978 | 2170.50143613 | 0.06% | 28 Apr 2025 |
| 2183.31686871 | 2183.95464045 | 0.03% | 29 Apr 2025 |
| 2106.14087107 | 2100.66019434 | 0.26% | 30 Apr 2025 |
| 2209.6315434 | 2213.95366061 | 0.20% | 01 May 2025 |
| 2215.33523206 | 2216.96923478 | 0.07% | 02 May 2025 |
| 2207.45309063 | 2207.8434084 | 0.02% | 03 May 2025 |
| 2196.18873716 | 2196.94841401 | 0.03% | 04 May 2025 |
| 2173.76096755 | 2173.72491546 | 0.00% | 05 May 2025 |
"
`;
65 changes: 65 additions & 0 deletions src/reports/capo-svr-comparative-report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {formatUnits} from 'viem';
import {CapoSvrSnapshot} from './snapshot-types';

type Comparative = {
regularAdapterPrice: string;
svrAdapterPrice: string;
diff: string;
date: string;
};

export async function generateSvrCapoReport(snapshot: CapoSvrSnapshot) {
let comparative: Comparative[] = [];

for (const key in snapshot.comparative) {
const price = snapshot.comparative[key];

const svrAdapterPrice = formatUnits(BigInt(price.svrAdapterPrice), snapshot.decimals);
const regularAdapterPrice = formatUnits(BigInt(price.regularAdapterPrice), snapshot.decimals);
const difference =
Number(svrAdapterPrice) > Number(regularAdapterPrice)
? Number(svrAdapterPrice) - Number(regularAdapterPrice)
: Number(regularAdapterPrice) - Number(svrAdapterPrice);

const diff = (
(100 * difference) /
((Number(svrAdapterPrice) + Number(regularAdapterPrice)) / 2)
).toFixed(2);

const formattedDate = formatTimestamp(price.timestamp);

comparative.push({
svrAdapterPrice,
regularAdapterPrice,
diff,
date: formattedDate,
});
}

comparative = comparative.slice(snapshot.minSnapshotDelay);

// generate md report
let content = '';
content += `# Capo Comparative Report\n\n`;
content += `# ${snapshot.sourceName} \n\n`;
content += `- Difference between adapters using SVR and regular Chainlink Feeds\n\n`;
content += `| SVR Adapter | Regular Adapter | Diff | Date |\n`;
content += `| --- | --- | --- | --- |\n`;
comparative.forEach((price) => {
content += `| ${price.svrAdapterPrice} | ${price.regularAdapterPrice} | ${price.diff}% | ${price.date} |\n`;
});
return content;
}

function formatTimestamp(timestampInSec: number) {
// Create a new Date object from the timestamp in seconds
const date = new Date(timestampInSec * 1000);

// Use the Intl.DateTimeFormat API to format the date
return new Intl.DateTimeFormat('en-GB', {
year: 'numeric',
month: 'short',
day: '2-digit',
timeZone: 'GMT',
}).format(date);
}
16 changes: 16 additions & 0 deletions src/reports/capo-svr-report.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {describe, expect, it} from 'vitest';
import {readJsonFile} from '../utils/json';
import {generateSvrCapoReport} from './capo-svr-comparative-report';

describe('capo svr report', () => {
it(
'should generate a well formatted capo svr report',
async () => {
const snapshot = readJsonFile('/src/reports/mocks/capoSvr.json');
const content = await generateSvrCapoReport(snapshot);
console.log(content);
expect(content).toMatchSnapshot();
},
{timeout: 30000},
);
});
162 changes: 162 additions & 0 deletions src/reports/mocks/capoSvr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
{
"comparative": {
"22199900": {
"regularAdapterPrice": 217666375221,
"svrAdapterPrice": 217554419401,
"timestamp": 1743822131
},
"22207200": {
"regularAdapterPrice": 216795440985,
"svrAdapterPrice": 216644202291,
"timestamp": 1743910247
},
"22214500": {
"regularAdapterPrice": 184904466888,
"svrAdapterPrice": 184331232930,
"timestamp": 1743998399
},
"22221800": {
"regularAdapterPrice": 191382628592,
"svrAdapterPrice": 190799419233,
"timestamp": 1744086611
},
"22229100": {
"regularAdapterPrice": 172703894879,
"svrAdapterPrice": 172730277631,
"timestamp": 1744174619
},
"22236400": {
"regularAdapterPrice": 194477533416,
"svrAdapterPrice": 194601135762,
"timestamp": 1744262495
},
"22243700": {
"regularAdapterPrice": 185570748959,
"svrAdapterPrice": 185112817156,
"timestamp": 1744350443
},
"22251000": {
"regularAdapterPrice": 188016617657,
"svrAdapterPrice": 188010970140,
"timestamp": 1744438283
},
"22258300": {
"regularAdapterPrice": 193484763392,
"svrAdapterPrice": 194099317901,
"timestamp": 1744526231
},
"22265600": {
"regularAdapterPrice": 194899310701,
"svrAdapterPrice": 195125160577,
"timestamp": 1744614059
},
"22272900": {
"regularAdapterPrice": 196856171868,
"svrAdapterPrice": 196885656094,
"timestamp": 1744702151
},
"22280200": {
"regularAdapterPrice": 188088400462,
"svrAdapterPrice": 188044218254,
"timestamp": 1744790159
},
"22287500": {
"regularAdapterPrice": 192196651940,
"svrAdapterPrice": 192714919798,
"timestamp": 1744878263
},
"22294800": {
"regularAdapterPrice": 190124372975,
"svrAdapterPrice": 190198709042,
"timestamp": 1744966187
},
"22302100": {
"regularAdapterPrice": 192294047495,
"svrAdapterPrice": 192266605311,
"timestamp": 1745054243
},
"22309400": {
"regularAdapterPrice": 190622505555,
"svrAdapterPrice": 190833882018,
"timestamp": 1745142263
},
"22316700": {
"regularAdapterPrice": 197015250316,
"svrAdapterPrice": 197333083291,
"timestamp": 1745230343
},
"22324000": {
"regularAdapterPrice": 194937422474,
"svrAdapterPrice": 194843062491,
"timestamp": 1745318339
},
"22331300": {
"regularAdapterPrice": 217182424304,
"svrAdapterPrice": 216035296377,
"timestamp": 1745406467
},
"22338600": {
"regularAdapterPrice": 209391812992,
"svrAdapterPrice": 209383167086,
"timestamp": 1745494463
},
"22345900": {
"regularAdapterPrice": 214633325394,
"svrAdapterPrice": 214842289872,
"timestamp": 1745582423
},
"22353200": {
"regularAdapterPrice": 214664704136,
"svrAdapterPrice": 214693062115,
"timestamp": 1745670383
},
"22360500": {
"regularAdapterPrice": 216198612144,
"svrAdapterPrice": 216739047482,
"timestamp": 1745758211
},
"22367800": {
"regularAdapterPrice": 217050143613,
"svrAdapterPrice": 216922825978,
"timestamp": 1745846207
},
"22375100": {
"regularAdapterPrice": 218395464045,
"svrAdapterPrice": 218331686871,
"timestamp": 1745934335
},
"22382400": {
"regularAdapterPrice": 210066019434,
"svrAdapterPrice": 210614087107,
"timestamp": 1746022607
},
"22389700": {
"regularAdapterPrice": 221395366061,
"svrAdapterPrice": 220963154340,
"timestamp": 1746110987
},
"22397000": {
"regularAdapterPrice": 221696923478,
"svrAdapterPrice": 221533523206,
"timestamp": 1746199583
},
"22404300": {
"regularAdapterPrice": 220784340840,
"svrAdapterPrice": 220745309063,
"timestamp": 1746287867
},
"22411600": {
"regularAdapterPrice": 219694841401,
"svrAdapterPrice": 219618873716,
"timestamp": 1746376319
},
"22418900": {
"regularAdapterPrice": 217372491546,
"svrAdapterPrice": 217376096755,
"timestamp": 1746464591
}
},
"decimals": 8,
"minSnapshotDelay": 7,
"sourceName": "Capped wstETH / stETH(ETH) / USD"
}
15 changes: 15 additions & 0 deletions src/reports/snapshot-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,18 @@ export const capoSnapshotSchema = z.object({
});

export type CapoSnapshot = z.infer<typeof capoSnapshotSchema>;

export const capoSvrPriceSchema = z.object({
regularAdapterPrice: z.number(),
svrAdapterPrice: z.number(),
timestamp: z.number(),
});

export const capoSvrSnapshotSchema = z.object({
sourceName: z.string(),
decimals: z.number(),
minSnapshotDelay: z.number(),
comparative: z.record(capoSvrPriceSchema),
});

export type CapoSvrSnapshot = z.infer<typeof capoSvrSnapshotSchema>;
Loading