@@ -23,8 +23,14 @@ const source = path.join(root, "src", "assets", "snapshots.json");
2323const claimModal = path . join ( root , "src" , "components" , "claim-modal.js" ) ;
2424const destination = path . join ( root , "public" , "snapshots.json" ) ;
2525
26- const CHAIN_IDS = [ "1" , "100" ] ;
27- const FILENAME_PREFIX = { 1 : "snapshot-" , 100 : "xdai-snapshot-" } ;
26+ // Every chain the reward snapshots cover, declared once. To support a new chain, add one entry
27+ // here (with its filename prefix); CHAIN_IDS and the prefix lookup derive from it, so the set of
28+ // chains and their prefixes can never drift apart.
29+ const CHAINS = {
30+ 1 : { filenamePrefix : "snapshot-" } ,
31+ 100 : { filenamePrefix : "xdai-snapshot-" } ,
32+ } ;
33+ const CHAIN_IDS = Object . keys ( CHAINS ) ;
2834const ENTRY = / ^ [ A - Z a - z 0 - 9 ] + \/ [ A - Z a - z 0 - 9 . _ - ] + \. j s o n $ / ;
2935
3036// rewards.js derives the IPFS url, the month and the chain from these strings alone, so a
@@ -35,9 +41,10 @@ function assertEntriesAreWellFormed(entries, chainId) {
3541 throw new Error ( `snapshots.json: chain ${ chainId } entry "${ entry } " is not of the form "<cid>/<filename>.json"` ) ;
3642 }
3743 const filename = entry . split ( "/" ) [ 1 ] ;
38- if ( ! filename . startsWith ( FILENAME_PREFIX [ chainId ] ) ) {
44+ const { filenamePrefix } = CHAINS [ chainId ] ;
45+ if ( ! filename . startsWith ( filenamePrefix ) ) {
3946 throw new Error (
40- `snapshots.json: chain ${ chainId } entry "${ entry } " must start with "${ FILENAME_PREFIX [ chainId ] } " ` +
47+ `snapshots.json: chain ${ chainId } entry "${ entry } " must start with "${ filenamePrefix } " ` +
4148 `— rewards.js tells the chains apart by that prefix.`
4249 ) ;
4350 }
@@ -49,14 +56,27 @@ function assertEntriesAreWellFormed(entries, chainId) {
4956function assertNewestMonthIsOnEveryChain ( snapshots ) {
5057 const newestMonth = ( chainId ) => {
5158 const entries = snapshots [ chainId ] ;
52- return ( entries [ entries . length - 1 ] . match ( / ( \d { 4 } - \d { 2 } ) / ) || [ ] ) [ 1 ] ;
59+ const newest = entries [ entries . length - 1 ] ;
60+ const month = ( newest . match ( / ( \d { 4 } - \d { 2 } ) / ) || [ ] ) [ 1 ] ;
61+ if ( ! month ) {
62+ throw new Error (
63+ `snapshots.json: chain ${ chainId } 's newest entry "${ newest } " has no YYYY-MM, ` +
64+ `so it can't be checked against the other chains.`
65+ ) ;
66+ }
67+ return month ;
5368 } ;
54- const [ mainnet , gnosis ] = CHAIN_IDS . map ( newestMonth ) ;
55- if ( mainnet !== gnosis ) {
56- throw new Error (
57- `snapshots.json: newest month differs per chain (mainnet ${ mainnet } , gnosis ${ gnosis } ). Add both, or the ` +
58- `monthly reward total will be missing a chain.`
59- ) ;
69+ const [ referenceChain , ...otherChains ] = CHAIN_IDS ;
70+ const referenceMonth = newestMonth ( referenceChain ) ;
71+ for ( const chainId of otherChains ) {
72+ const month = newestMonth ( chainId ) ;
73+ if ( month !== referenceMonth ) {
74+ throw new Error (
75+ `snapshots.json: newest month differs per chain ` +
76+ `(chain ${ referenceChain } ${ referenceMonth } , chain ${ chainId } ${ month } ). ` +
77+ `Add the missing month, or the monthly reward total will be missing a chain.`
78+ ) ;
79+ }
6080 }
6181}
6282
@@ -84,6 +104,17 @@ function assertParity(snapshots) {
84104}
85105
86106const snapshots = JSON . parse ( fs . readFileSync ( source , "utf8" ) ) ;
107+
108+ // Everything below is verified per chain in CHAIN_IDS, but the whole object is written out. Reject
109+ // any other chain so nothing reaches public/snapshots.json without being validated first.
110+ const unverifiedChains = Object . keys ( snapshots ) . filter ( ( chainId ) => ! CHAIN_IDS . includes ( chainId ) ) ;
111+ if ( unverifiedChains . length > 0 ) {
112+ throw new Error (
113+ `snapshots.json: chain(s) ${ unverifiedChains . join ( ", " ) } are not verified. Add them to CHAINS ` +
114+ `(and claim-modal.js) so they are validated before being published.`
115+ ) ;
116+ }
117+
87118for ( const chainId of CHAIN_IDS ) {
88119 if ( ! Array . isArray ( snapshots [ chainId ] ) || snapshots [ chainId ] . length === 0 ) {
89120 throw new Error ( `snapshots.json is missing snapshots for chain ${ chainId } ` ) ;
0 commit comments