@@ -3,42 +3,25 @@ pragma solidity ^0.8.20;
33
44import "./PostRegistry.sol " ;
55import "./LinkGraph.sol " ;
6- import "./StakeEngine .sol " ;
6+ import "./interfaces/IStakeEngine .sol " ;
77
88/// @title ScoreEngine
9- /// @notice Computes base and effective Veracity Scores (VS) for claims.
9+ /// @notice Computes base and effective Verity Scores (VS) for claims.
1010/// VS is represented as signed ray (1e18 = +1.0).
11- ///
12- /// RULES:
13- /// - baseVS depends only on direct stake
14- /// - effectiveVS propagates recursively over links
15- /// - a link contributes ONLY IF:
16- /// * IC is economically active (totalStake >= postingFeeThreshold)
17- /// * DC is economically active (totalStake >= postingFeeThreshold)
18- /// * link itself is economically active (totalStake >= postingFeeThreshold)
19- /// - symmetry preserved: negative VS propagates normally
20- ///
21- /// NEW (3.6+ incentive change):
22- /// - Incoming effect is NOT just icVS * linkVS.
23- /// - Instead, an IC exports its (effectiveVS(IC)) “mass” across ALL of its outgoing links
24- /// proportional to each link’s stake (conservation / no amplification):
25- ///
26- /// let S = sum_{outgoing links of IC} totalStake(link)
27- /// share(link) = totalStake(link) / S
28- ///
29- /// incomingEffect(link -> DC) = linkVS * icVS * share(link)
30- ///
31- /// (and then flipped if edge.isChallenge, which negates linkVS)
3211contract ScoreEngine {
3312 PostRegistry public immutable registry;
34- StakeEngine public immutable stake;
13+ IStakeEngine public immutable stake;
3514 LinkGraph public immutable graph;
3615
3716 int256 internal constant RAY = 1e18 ;
3817
39- constructor (address registry_ , address stake_ , address graph_ ) {
18+ constructor (
19+ address registry_ ,
20+ address stake_ ,
21+ address graph_
22+ ) {
4023 registry = PostRegistry (registry_);
41- stake = StakeEngine (stake_);
24+ stake = IStakeEngine (stake_);
4225 graph = LinkGraph (graph_);
4326 }
4427
@@ -47,14 +30,20 @@ contract ScoreEngine {
4730 // ---------------------------------------------------------------------
4831
4932 /// @notice Base VS = (2A / (A + D)) - 1 (ray-scaled)
33+ /// @dev Posting fee is injected into A *only when active*
5034 function baseVSRay (uint256 postId ) public view returns (int256 ) {
5135 (uint256 A , uint256 D ) = stake.getPostTotals (postId);
36+ uint256 postingFee = stake.postingFeeThreshold ();
37+
5238 uint256 T = A + D;
53- if (T == 0 ) return 0 ;
39+ if (T < postingFee) return 0 ;
40+
41+ // Inject posting fee as virtual support
42+ uint256 Aeff = A + postingFee;
43+ uint256 Teff = Aeff + D;
5444
55- // ray math: ((2A / T) - 1) * 1e18
56- int256 num = int256 (2 * A) * RAY;
57- int256 vs = (num / int256 (T)) - RAY;
45+ int256 num = int256 (2 * Aeff) * RAY;
46+ int256 vs = (num / int256 (Teff)) - RAY;
5847
5948 return _clampRay (vs);
6049 }
@@ -67,19 +56,17 @@ contract ScoreEngine {
6756 return _effectiveVSRay (claimPostId, 0 );
6857 }
6958
70- function _effectiveVSRay (uint256 claimPostId , uint256 depth ) internal view returns (int256 ) {
71- // recursion safety
59+ function _effectiveVSRay (uint256 claimPostId , uint256 depth )
60+ internal
61+ view
62+ returns (int256 )
63+ {
7264 if (depth > 32 ) return 0 ;
7365
74- uint256 threshold = stake.postingFeeThreshold ();
66+ uint256 postingFee = stake.postingFeeThreshold ();
67+ if (! _isActive (claimPostId, postingFee)) return 0 ;
7568
76- // DC must be economically active to have meaningful effectiveVS
77- if (! _isActive (claimPostId, threshold)) {
78- return 0 ;
79- }
80-
81- int256 baseVS = baseVSRay (claimPostId);
82- int256 acc = baseVS;
69+ int256 acc = baseVSRay (claimPostId);
8370
8471 LinkGraph.IncomingEdge[] memory inc = graph.getIncoming (claimPostId);
8572
@@ -89,39 +76,23 @@ contract ScoreEngine {
8976 uint256 ic = e.fromClaimPostId;
9077 uint256 linkPostId = e.linkPostId;
9178
92- // IC must be economically active
93- if (! _isActive (ic, threshold)) continue ;
94-
95- // Link post must be economically active
96- if (! _isActive (linkPostId, threshold)) continue ;
79+ if (! _isActive (ic, postingFee)) continue ;
80+ if (! _isActive (linkPostId, postingFee)) continue ;
9781
98- // IC effectiveVS (recursive)
9982 int256 icVS = _effectiveVSRay (ic, depth + 1 );
10083 if (icVS == 0 ) continue ;
10184
102- // Compute sum of ALL outgoing link stakes from IC (distribution denominator)
103- uint256 sumOutgoingLinkStake = _sumOutgoingLinkStake (ic, threshold);
104- if (sumOutgoingLinkStake == 0 ) continue ;
85+ uint256 sumOutgoing = _sumOutgoingLinkStake (ic, postingFee);
86+ if (sumOutgoing == 0 ) continue ;
10587
106- // This particular link stake (numerator)
10788 uint256 linkStake = _totalStake (linkPostId);
108- if (linkStake == 0 ) continue ;
89+ if (linkStake < postingFee ) continue ;
10990
110- // Link "vote" is the link's own VS (based on its own stake queues)
111- // (Links don't have incoming claim-links, so baseVS == effectiveVS for links.)
11291 int256 linkVS = baseVSRay (linkPostId);
92+ if (e.isChallenge) linkVS = - linkVS;
11393
114- // challenge edge flips semantic polarity
115- if (e.isChallenge) {
116- linkVS = - linkVS;
117- }
118-
119- // incomingEffect = linkVS * icVS * (linkStake / sumOutgoingLinkStake)
120- // Keep ray precision:
121- // (linkVS * icVS) / RAY => ray
122- // then * linkStake / sumOutgoing => ray
12394 int256 contrib = (linkVS * icVS) / RAY;
124- contrib = (contrib * int256 (linkStake)) / int256 (sumOutgoingLinkStake );
95+ contrib = (contrib * int256 (linkStake)) / int256 (sumOutgoing );
12596
12697 acc += contrib;
12798 }
@@ -138,28 +109,23 @@ contract ScoreEngine {
138109 return s + d;
139110 }
140111
141- function _isActive (uint256 postId , uint256 threshold ) internal view returns ( bool ) {
142- uint256 t = _totalStake (postId);
143- if (threshold == 0 ) {
144- return t > 0 ;
145- }
146- return t >= threshold;
112+ function _isActive (uint256 postId , uint256 threshold )
113+ internal
114+ view
115+ returns ( bool )
116+ {
117+ return _totalStake (postId) >= threshold;
147118 }
148119
149- /// @dev Sum stakes of ALL outgoing links from IC. (Optional: only count links that are economically active.)
150- function _sumOutgoingLinkStake (uint256 icClaimPostId , uint256 threshold ) internal view returns (uint256 sum ) {
151- LinkGraph.Edge[] memory outs = graph.getOutgoing (icClaimPostId);
120+ function _sumOutgoingLinkStake (uint256 ic , uint256 threshold )
121+ internal
122+ view
123+ returns (uint256 sum )
124+ {
125+ LinkGraph.Edge[] memory outs = graph.getOutgoing (ic);
152126 for (uint256 i = 0 ; i < outs.length ; i++ ) {
153- uint256 linkPostId = outs[i].linkPostId;
154- uint256 t = _totalStake (linkPostId);
155-
156- // Only include links that are active; prevents dust from diluting distribution.
157- if (threshold == 0 ) {
158- if (t == 0 ) continue ;
159- } else {
160- if (t < threshold) continue ;
161- }
162-
127+ uint256 t = _totalStake (outs[i].linkPostId);
128+ if (t < threshold) continue ;
163129 sum += t;
164130 }
165131 }
@@ -170,3 +136,4 @@ contract ScoreEngine {
170136 return x;
171137 }
172138}
139+
0 commit comments