11import { formatBytes32String } from '@ethersproject/strings' ;
22import { getAddress , isAddress } from '@ethersproject/address' ;
33import subgraphs from '@snapshot-labs/snapshot.js/src/delegationSubgraphs.json' ;
4+ import snapshot from '@snapshot-labs/snapshot.js' ;
45import {
5- getAddressesByProtocol ,
6- getFormattedAddressesByProtocol ,
76 getProvider ,
87 getSnapshots ,
98 Multicaller ,
109 subgraphRequest
1110} from '../utils' ;
1211import _strategies from '../strategies' ;
13- import { Score , Snapshot , VotingPower } from '../types' ;
12+ import { Score , Snapshot , VotingPower , Protocol } from '../types' ;
13+ import { VALID_PROTOCOLS } from '../constants' ;
1414
1515const DELEGATION_CONTRACT = '0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446' ;
1616const EMPTY_ADDRESS = '0x0000000000000000000000000000000000000000' ;
@@ -63,8 +63,10 @@ export async function getVp(
6363 if ( addresses . length === 0 ) return { } ;
6464 }
6565
66- addresses = getAddressesByProtocol ( addresses , supportedProtocols ) ;
67- addresses = getFormattedAddressesByProtocol ( addresses , supportedProtocols ) ;
66+ addresses = getFormattedAddressesByProtocol (
67+ getAddressesByProtocol ( addresses , supportedProtocols ) ,
68+ supportedProtocols
69+ ) ;
6870
6971 if ( addresses . length === 0 ) return { } ;
7072
@@ -91,8 +93,10 @@ export async function getVp(
9193 addresses = [ ...new Set ( addresses ) ] ;
9294 }
9395
94- addresses = getAddressesByProtocol ( addresses , supportedProtocols ) ;
95- addresses = getFormattedAddressesByProtocol ( addresses , supportedProtocols ) ;
96+ addresses = getFormattedAddressesByProtocol (
97+ getAddressesByProtocol ( addresses , supportedProtocols ) ,
98+ supportedProtocols
99+ ) ;
96100 return addresses . reduce ( ( a , b ) => a + ( score [ b ] || 0 ) , 0 ) ;
97101 } ) ;
98102 const vp = vpByStrategy . reduce ( ( a , b ) => a + b , 0 ) ;
@@ -252,3 +256,88 @@ function validateStrategies(strategies: any[]): void {
252256 throw new Error ( `invalid strategies: ${ invalidStrategies . join ( ', ' ) } ` ) ;
253257 }
254258}
259+
260+ /**
261+ * Validates that protocols are non-empty and contain only valid protocol names.
262+ *
263+ * @param protocols - Array of protocol names to validate
264+ */
265+ function validateProtocols ( protocols : Protocol [ ] ) : void {
266+ if ( ! protocols . length ) {
267+ throw new Error ( 'At least one protocol must be specified' ) ;
268+ }
269+
270+ const invalidProtocols = protocols . filter (
271+ ( p ) => ! VALID_PROTOCOLS . includes ( p )
272+ ) ;
273+ if ( invalidProtocols . length > 0 ) {
274+ throw new Error ( `Invalid protocol(s): ${ invalidProtocols . join ( ', ' ) } ` ) ;
275+ }
276+ }
277+
278+ /**
279+ * Formats addresses according to the specified blockchain protocols.
280+ *
281+ * This function takes a list of addresses and formats them according to the provided
282+ * protocols.
283+ *
284+ * @param addresses - Array of blockchain addresses to format
285+ * @param protocols - Array of protocol names to validate against. Defaults to ['evm'].
286+ * Valid protocols are 'evm' and 'starknet'.
287+ *
288+ * @returns Array of formatted addresses in the same order as input
289+ */
290+ function getFormattedAddressesByProtocol (
291+ addresses : string [ ] ,
292+ protocols : Protocol [ ] = [ 'evm' ]
293+ ) : string [ ] {
294+ validateProtocols ( protocols ) ;
295+
296+ return addresses . map ( ( address ) => {
297+ if ( protocols . includes ( 'evm' ) && address . length === 42 ) {
298+ try {
299+ return snapshot . utils . getFormattedAddress ( address , 'evm' ) ;
300+ } catch ( e ) { }
301+ } else if ( protocols . includes ( 'starknet' ) && address . length === 66 ) {
302+ try {
303+ return snapshot . utils . getFormattedAddress ( address , 'starknet' ) ;
304+ } catch ( e ) { }
305+ }
306+
307+ throw new Error (
308+ `Address "${ address } " is not a valid ${ protocols . join ( ' or ' ) } address`
309+ ) ;
310+ } ) ;
311+ }
312+
313+ /**
314+ * Filters addresses by the specified protocols.
315+ *
316+ * This function takes a list of addresses and filters them based on the provided
317+ * protocols. It checks if each address matches the expected format for EVM or
318+ * Starknet protocols
319+ *
320+ * This function DOES NOT format/validate the addresses, and may return invalid addresses
321+ *
322+ * @param addresses - Array of addresses to filter
323+ * @param protocols - Array of protocol names to validate against. Defaults to ['evm'].
324+ * Valid protocols are 'evm' and 'starknet'.
325+ *
326+ * @returns Array of addresses that match the specified protocols
327+ */
328+ function getAddressesByProtocol (
329+ addresses : string [ ] ,
330+ protocols : Protocol [ ] = [ 'evm' ]
331+ ) : string [ ] {
332+ validateProtocols ( protocols ) ;
333+
334+ return addresses . filter ( ( address ) => {
335+ if ( protocols . includes ( 'evm' ) && / ^ 0 x [ a - f A - F 0 - 9 ] { 40 } $ / . test ( address ) ) {
336+ return true ;
337+ }
338+ if ( protocols . includes ( 'starknet' ) && / ^ 0 x [ a - f A - F 0 - 9 ] { 64 } $ / . test ( address ) ) {
339+ return true ;
340+ }
341+ return false ;
342+ } ) ;
343+ }
0 commit comments