You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds a live, weighted aggregate risk score per wallet across all of its
scored asset pairs, so a wallet that is moderately suspicious on several
pairs is visible as a single portfolio-level risk signal rather than only
as independent per-pair scores.
- AggregateRiskScore type + AssetPairs/PairWeight/AggregateScore DataKeys
- storage::register_pair_for_wallet deduplicates a wallet's pair list;
wired into submit_score and submit_scores_batch
- get_aggregate_score always recomputes from live per-pair scores (never
serves a stale cache); admin-configurable per-pair weights via
set_pair_weight/get_pair_weight, defaulting to 1 (simple average)
- Checked arithmetic throughout the weighted sum, returning the new
ArithmeticOverflow error instead of panicking on pathological weights
- 11 new tests covering the acceptance criteria (equal/weighted average,
max-pair tracking, flag counts, rescoring, dedup, zero-weight exclusion,
overflow protection) plus README docs and a worked example
Closes#11
Read-only function. Returns `wallet`'s cross-asset aggregate risk score — a weighted average computed live from every asset pair the wallet has a `RiskScore` for. Always recomputed from current per-pair scores, never served from a stale cache. Returns `ScoreNotFound` if the wallet has no scores.
Sets the weight used for `asset_pair` in the aggregate risk computation. Defaults to `1` (simple average) for any pair the admin hasn't configured. A weight of `0` excludes the pair from the aggregate's denominator. Admin only.
78
+
79
+
### `get_pair_weight(asset_pair: Symbol) -> u32`
80
+
Read-only lookup of the configured weight for `asset_pair`.
81
+
73
82
### `RiskScore` Structure
74
83
75
84
```rust
@@ -82,6 +91,55 @@ pub struct RiskScore {
82
91
}
83
92
```
84
93
94
+
### `AggregateRiskScore` Structure
95
+
96
+
A wallet that is moderately suspicious across several asset pairs poses a higher *portfolio-level* risk than its individual per-pair scores suggest in isolation. `AggregateRiskScore` expresses that risk on-chain:
97
+
98
+
```rust
99
+
pubstructAggregateRiskScore {
100
+
pubaggregate_score:u32, // 0-100, weighted average across all pairs
101
+
pubpair_count:u32, // number of distinct pairs the wallet has a score for
`pair_weight[i]` defaults to `1` for every pair (a plain average) unless the admin sets a different weight via `set_pair_weight`. A pair with weight `0` is excluded from the denominator — its score still counts toward `pair_count`, `max_pair_score`, the flag counts, and `last_updated`, but not toward `aggregate_score`.
A wallet scoring 60-70 on three pairs individually might not breach the per-pair `RiskThreshold` (default 75), but the aggregate view makes the *combined* exposure visible to any contract or dashboard that queries `get_aggregate_score` — without needing to fetch and average every pair manually.
140
+
141
+
`get_aggregate_score` iterates the wallet's full pair list, so its cost is O(N) in the number of distinct pairs the wallet has scores for. The contract is designed around a practical maximum of `MAX_WALLET_PAIRS` (20) pairs per wallet; this is documented as a constant but not enforced on-chain.
142
+
85
143
## Security Features
86
144
87
145
1.**Authorization Checks**: Only the authorised LedgerLens service account can submit scores
@@ -249,6 +307,7 @@ pub struct RiskScore {
249
307
250
308
-`score` — `(wallet, asset_pair) -> (score, benford_flag, ml_flag, confidence, timestamp)`, emitted on every `submit_score`
251
309
-`svc_upd` — emitted when the admin rotates the authorised service address
310
+
-`pw_upd` — `(asset_pair) -> weight`, emitted when the admin sets a pair's aggregate-risk weight via `set_pair_weight`
252
311
253
312
`api` (or a dedicated indexer in `data`) should subscribe to these for audit trails and to keep an off-chain cache in sync with on-chain state.
0 commit comments