feat: on-chain cross-asset aggregate risk engine - #16
Merged
Conversation
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 Ledger-Lenz#11
Contributor
|
please one test is failing,all test must pass |
Contributor
Author
Hello @Inkman007 it not the test failling, it your github action, it says Error: Unable to resolve action swatinium/rust-cache, repository not found. please check and fix this. |
Contributor
|
noted |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Adds a live, weighted cross-asset aggregate risk score per wallet. A wallet that is moderately suspicious across several asset pairs (e.g. 60/65/70 on three pairs) is now visible as a single portfolio-level risk signal, instead of only as independent per-pair scores.
AggregateRiskScoretype +AssetPairs(Address)/PairWeight(Symbol)/AggregateScore(Address)DataKeyvariantsstorage::register_pair_for_walletmaintains a deduplicated list of a wallet's pairs; wired intosubmit_scoreandsubmit_scores_batchget_aggregate_score(wallet)always recomputes from live per-pair scores — it never reads theAggregateScore(wallet)cache. That cache is refreshed as a side effect of everysubmit_score/submit_scores_batchcall purely as a cheap snapshot for off-chain indexers, so the public read is guaranteed consistent with the latest submission.set_pair_weight/get_pair_weight, defaulting to1(simple average). A weight of0excludes a pair from the denominator while still counting towardpair_count,max_pair_score, the flag counts, andlast_updated.ArithmeticOverflowerror (appended as code11, per the stable-ABI convention in CONTRIBUTING.md) instead of panicking on a pathological admin-set weight.MAX_WALLET_PAIRS = 20documents the practical O(N) boundget_aggregate_scoreis designed around (enforced only as adebug_assert!, a no-op in the release profile — not a hard on-chain cap, since the issue only asked for it to be documented).Design comment / overflow strategy
The weighted sum is
Σ (pair_weight[i] * pair_score[i]) / Σ pair_weight[i]. The per-pair multiplicationweight.checked_mul(score)is done inu32— matching the stored field widths — soweight = u32::MAXoverflows on the very first multiplication oncescore ≥ 2, regardless of how many pairs are involved. Both running totals (weighted_sum,weight_sum) are then accumulated inu64viachecked_add, which is generous headroom for realistic weights/pair counts. The finalaggregate_scoredowncast tou32is always safe by construction: a weighted average of values in0..=100can never itself exceed100.Worked example (weighted case)
Pairs
XLM_USDC(score 20, weight 1),XLM_BTC(score 80, weight 2),XLM_ETH(score 40, weight 1):This matches
test_aggregate_weighted.Test plan
cargo fmt --all -- --checkcargo clippy --all-targets -- -D warningscargo test— 50 passed (39 pre-existing + 11 new), covering every row in the issue's acceptance-criteria table: single pair, equal weights, weighted average, max-pair tracking, flag counts, rescoring, wallet-not-found, pair dedup, zero-weight exclusion, overflow protectioncargo build --target wasm32-unknown-unknown --release— please confirm in CI; my local environment didn't have network/target access to verify this oneREADME.mdupdated withAggregateRiskScoredocs, function reference, event list, and the worked example aboveCloses #11