@@ -170,6 +170,30 @@ async function etherscanReferred(pool: Address, referrer: Address, key: string):
170170 return [ ] ;
171171}
172172
173+ // The MOR claim receiver a staker set for a pool (0x0 if never set). The /stake
174+ // flow wires this to the rider's 3-way split, so a NON-zero receiver marks an
175+ // "official" sponsorship stake (its MOR routes to Gnars + the athlete). A zero
176+ // receiver is a raw Morpheus deposit that pays 100% back to the staker — not a
177+ // sponsorship, so the orbit must not count it. Read via Etherscan proxy eth_call
178+ // (datacenter-safe, same key as the log scan).
179+ const CLAIM_RECEIVER_SIG = keccak256 ( toHex ( "claimReceiver(uint256,address)" ) ) . slice ( 0 , 10 ) ;
180+ async function etherscanClaimReceiver ( pool : Address , user : Address , key : string ) : Promise < Address | null > {
181+ const data = `${ CLAIM_RECEIVER_SIG } ${ "0" . repeat ( 64 ) } ${ pad32 ( user ) . slice ( 2 ) } ` ;
182+ const url =
183+ `https://api.etherscan.io/v2/api?chainid=1&module=proxy&action=eth_call` +
184+ `&to=${ pool } &data=${ data } &tag=latest&apikey=${ key } ` ;
185+ for ( let i = 0 ; i < 4 ; i ++ ) {
186+ try {
187+ const res = await fetch ( url , { cache : "no-store" } ) ;
188+ const j = ( await res . json ( ) ) as { result ?: unknown ; message ?: string } ;
189+ if ( typeof j . result === "string" && j . result . length >= 66 ) return getAddress ( `0x${ j . result . slice ( - 40 ) } ` ) ;
190+ if ( / r a t e l i m i t / i. test ( String ( j . result ) ) || / r a t e l i m i t / i. test ( String ( j . message ) ) ) { await sleep ( 600 ) ; continue ; }
191+ return null ;
192+ } catch { await sleep ( 300 ) ; }
193+ }
194+ return null ;
195+ }
196+
173197async function morBackersByRider ( ethUsd : number ) : Promise < Record < string , OrbitBacker [ ] > > {
174198 const walletToId = new Map < string , RiderId > ( ) ;
175199 for ( const r of RIDER_LIST ) if ( r . wallet ) walletToId . set ( r . wallet . toLowerCase ( ) , r . id ) ;
@@ -201,9 +225,16 @@ async function morBackersByRider(ethUsd: number): Promise<Record<string, OrbitBa
201225 for ( const l of logs ) byUser . set ( l . user . toLowerCase ( ) , ( byUser . get ( l . user . toLowerCase ( ) ) ?? BigInt ( 0 ) ) + l . amount ) ;
202226 const out : Array < { id : RiderId ; backer : OrbitBacker } > = [ ] ;
203227 for ( const [ userLc , amt ] of byUser ) {
228+ const user = getAddress ( userLc ) ;
229+ // Only OFFICIAL /stake deposits belong in the sponsorship orbit: the
230+ // site wires the MOR claim receiver to the rider's 3-way split. A zero
231+ // receiver is a raw Morpheus stake whose MOR pays 100% to the staker
232+ // (no Gnars/athlete cut) — exclude it from the orbit AND the total.
233+ const receiver = await etherscanClaimReceiver ( pool , user , ETHERSCAN_KEY as string ) ;
234+ if ( ! receiver || receiver . toLowerCase ( ) === ZERO ) continue ;
204235 const tokens = Number ( formatUnits ( amt , decimals ) ) ;
205236 const usd = asset === "steth" ? tokens * ethUsd : tokens ;
206- if ( usd > 0 ) out . push ( { id, backer : { address : getAddress ( userLc ) , amount : usd , kind : "mor" , asset } } ) ;
237+ if ( usd > 0 ) out . push ( { id, backer : { address : user , amount : usd , kind : "mor" , asset } } ) ;
207238 }
208239 return out ;
209240 } ) ,
0 commit comments