> ## Documentation Index
> Fetch the complete documentation index at: https://docs.walletwall.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Scoring Methodology

> How WalletWall computes wallet exposure — the inputs, the outputs, the shared risk tiers (Monitor, Review, Migrate, Vault Candidate), and what the score does and does not mean.

export const deriveDocsQuantumExposureScore = input => {
  const WEIGHTS = {
    signatureExposureObserved: 35,
    noOutgoingSignatureBaseline: 5,
    dormancy: {
      ancient_dormant_730d_plus: 20,
      cold_dormant_180_730d: 12,
      warm_dormant_30_180d: 5,
      active_0_30d: 0
    },
    valueAtRisk: {
      veryHigh: 25,
      high: 18,
      meaningful: 10,
      nonzero: 5
    },
    keySignatureAge: {
      ancient: 15,
      mature: 10,
      established: 5
    },
    migrationReadinessReduction: 10
  };
  const LABELS = {
    unknown: 'Unknown / insufficient data',
    low: 'Low exposure',
    moderate: 'Moderate exposure',
    elevated: 'Elevated exposure',
    migration_priority: 'Migration priority'
  };
  const BANDS = [{
    min: 75,
    key: 'migration_priority'
  }, {
    min: 50,
    key: 'elevated'
  }, {
    min: 25,
    key: 'moderate'
  }, {
    min: 0,
    key: 'low'
  }];
  const DORMANCY_ANCHORS = [[30, 0], [180, 5], [730, 12], [1825, 20]];
  const VALUE_ANCHORS = [[1, 0], [10000, 10], [100000, 18], [1000000, 25]];
  const AGE_ANCHORS = [[1, 0], [365, 5], [1095, 10], [1825, 15]];
  const LADDER = ['low', 'medium', 'high'];
  const interp = (x, anchors) => {
    const [firstX, firstY] = anchors[0];
    if (Number.isNaN(x) || typeof x !== 'number' || x <= 0 || x <= firstX) return firstY;
    const [lastX, lastY] = anchors[anchors.length - 1];
    if (x >= lastX) return lastY;
    const logX = Math.log2(x);
    for (let i = 1; i < anchors.length; i++) {
      const [x1, y1] = anchors[i];
      if (x <= x1) {
        const [x0, y0] = anchors[i - 1];
        return y0 + (y1 - y0) * ((logX - Math.log2(x0)) / (Math.log2(x1) - Math.log2(x0)));
      }
    }
    return lastY;
  };
  const scoreDormancy = d => Math.round(interp(d, DORMANCY_ANCHORS));
  const scoreValue = v => Math.round(interp(v, VALUE_ANCHORS));
  const scoreAge = a => Math.round(interp(a, AGE_ANCHORS));
  const asNumber = v => typeof v === 'number' && Number.isFinite(v) ? v : null;
  const bandFor = score => {
    for (const band of BANDS) if (score >= band.min) return band.key;
    return 'low';
  };
  const signatureSignal = (status, txSeen) => {
    if (status === 'signature_exposure_observed') {
      return {
        key: 'signature_exposure',
        basis: 'observed',
        label: 'Outgoing signature activity observed',
        weight: WEIGHTS.signatureExposureObserved,
        points: WEIGHTS.signatureExposureObserved,
        detail: 'The public key is recoverable once an account has signed an outgoing transaction.'
      };
    }
    if (status === 'no_outgoing_signature_observed') {
      return {
        key: 'signature_exposure',
        basis: txSeen ? 'observed' : 'unknown',
        label: 'No outgoing signature observed',
        weight: WEIGHTS.signatureExposureObserved,
        points: txSeen ? WEIGHTS.noOutgoingSignatureBaseline : 0,
        detail: txSeen ? 'History is visible and shows no outgoing signature so far — a small observed baseline.' : 'No transaction history was available to confirm signature exposure, so no points are added.'
      };
    }
    if (status === 'contract_wallet') {
      return {
        key: 'signature_exposure',
        basis: 'observed',
        label: 'Contract wallet signature model',
        weight: WEIGHTS.signatureExposureObserved,
        points: 0,
        detail: 'Contract wallets follow a different signature exposure model than EOAs.'
      };
    }
    return null;
  };
  const dormancySignal = days => days == null ? {
    key: 'dormancy',
    basis: 'unknown',
    label: 'Dormancy unavailable',
    weight: WEIGHTS.dormancy.ancient_dormant_730d_plus,
    points: 0,
    detail: 'Last-activity age is unknown, so no dormancy weight is applied.'
  } : {
    key: 'dormancy',
    basis: 'observed',
    label: 'Last-activity dormancy',
    weight: WEIGHTS.dormancy.ancient_dormant_730d_plus,
    points: scoreDormancy(days),
    detail: `Long-dormant wallets can delay owner attention and migration planning (${Math.round(days)} days since last activity).`
  };
  const valueSignal = usd => usd == null || usd < 0 ? {
    key: 'value_at_risk',
    basis: 'unknown',
    label: 'Value at risk unavailable',
    weight: WEIGHTS.valueAtRisk.veryHigh,
    points: 0,
    detail: 'Reported balance is unknown, so no value weight is applied.'
  } : {
    key: 'value_at_risk',
    basis: 'observed',
    label: 'Reported value at risk',
    weight: WEIGHTS.valueAtRisk.veryHigh,
    points: scoreValue(usd),
    detail: 'Higher reported value raises the consequence of delayed migration planning.'
  };
  const ageSignal = days => days == null ? {
    key: 'key_signature_age',
    basis: 'unknown',
    label: 'Key / signature age unavailable',
    weight: WEIGHTS.keySignatureAge.ancient,
    points: 0,
    detail: 'First-seen / first-signature timestamps are unknown, so no age weight is applied.'
  } : {
    key: 'key_signature_age',
    basis: 'observed',
    label: 'Key / signature age',
    weight: WEIGHTS.keySignatureAge.ancient,
    points: scoreAge(days),
    detail: `Older keys have a longer window of on-chain signature visibility (${Math.round(days)} days old).`
  };
  const exposureStatus = input?.exposureStatus ?? 'unknown';
  const txObserved = input?.txObserved === true;
  const daysDormant = asNumber(input?.daysDormant);
  const totalBalanceUsd = asNumber(input?.totalBalanceUsd);
  const keyAgeDays = asNumber(input?.keyAgeDays);
  const migrationPathPresent = input?.migrationPathPresent === true;
  if (!exposureStatus || exposureStatus === 'unknown') {
    return Object.freeze({
      score: null,
      status: 'insufficient_data',
      label: LABELS.unknown,
      bandKey: 'unknown',
      confidence: 'low',
      signals: Object.freeze([]),
      basePoints: 0,
      migrationOffset: 0,
      evidenceCount: 0,
      explanation: 'No chain identity or exposure classification is available, so no score is emitted. Unknown is a distinct outcome — it is never a synonym for a low score.'
    });
  }
  const signals = [signatureSignal(exposureStatus, txObserved), dormancySignal(daysDormant), valueSignal(totalBalanceUsd), ageSignal(keyAgeDays)].filter(Boolean);
  const basePoints = signals.reduce((sum, signal) => sum + signal.points, 0);
  const signatureDimObserved = exposureStatus === 'signature_exposure_observed' || exposureStatus === 'contract_wallet' || txObserved;
  const evidenceCount = [signatureDimObserved, daysDormant != null, totalBalanceUsd != null, keyAgeDays != null].filter(Boolean).length;
  if (evidenceCount === 0) {
    return Object.freeze({
      score: null,
      status: 'insufficient_data',
      label: LABELS.unknown,
      bandKey: 'unknown',
      confidence: 'low',
      signals: Object.freeze(signals),
      basePoints,
      migrationOffset: 0,
      evidenceCount: 0,
      explanation: 'No wallet-specific dimension is backed by observed evidence, so no score is emitted. Two unrelated wallets with no data both return Unknown rather than an identical confident baseline.'
    });
  }
  let points = basePoints;
  let migrationOffset = 0;
  if (migrationPathPresent) {
    const reduction = Math.min(WEIGHTS.migrationReadinessReduction, points);
    points = Math.max(0, points - reduction);
    migrationOffset = -reduction;
    signals.push({
      key: 'migration_readiness',
      basis: 'inferred',
      label: 'Migration-readiness offset',
      weight: WEIGHTS.migrationReadinessReduction,
      points: -reduction,
      detail: 'Observed migration-readiness signals reduce priority versus an equivalent EOA.'
    });
  }
  const score = Math.min(100, Math.max(0, points));
  const bandKey = bandFor(score);
  let confidence;
  if (exposureStatus === 'contract_wallet') {
    confidence = 'medium';
  } else if (keyAgeDays != null && daysDormant != null) {
    confidence = 'high';
  } else if (keyAgeDays != null || daysDormant != null || signatureDimObserved) {
    confidence = 'medium';
  } else {
    confidence = 'low';
  }
  if (totalBalanceUsd == null) {
    const rank = Math.max(0, LADDER.indexOf(confidence) - 1);
    confidence = LADDER[rank];
  }
  const unknownAxes = signals.filter(s => s.basis === 'unknown').map(s => s.key);
  const explanation = unknownAxes.length > 0 ? `Scored from ${evidenceCount} observed dimension(s). ${unknownAxes.length} axis/axes had no evidence and contributed 0 points — that lowers confidence and coverage; it does not mean the wallet is safer.` : `Every scored axis is backed by observed evidence, so the composite reflects full coverage at ${confidence} confidence.`;
  return Object.freeze({
    score,
    status: 'scored',
    label: LABELS[bandKey],
    bandKey,
    confidence,
    signals: Object.freeze(signals),
    basePoints,
    migrationOffset,
    evidenceCount,
    explanation
  });
};

export const QuantumExposureCalculator = ({idPrefix = 'qec'}) => {
  const STATUS_OPTIONS = [{
    value: 'signature_exposure_observed',
    label: 'Outgoing signature observed (EOA)'
  }, {
    value: 'no_outgoing_signature_observed',
    label: 'No outgoing signature observed (EOA)'
  }, {
    value: 'contract_wallet',
    label: 'Contract wallet (Safe / multisig / AA)'
  }, {
    value: 'unknown',
    label: 'Unknown — cannot classify'
  }];
  const NON_SCORING_CONTEXT = ['Stablecoin concentration', 'Behavioral / adversarial signals', 'Counterparty relationship context', 'Protocol affinity'];
  const MIGRATION_OFFSET_POINTS = 10;
  const STYLES = `
.ww-qec{--ww-qec-bg:#FAFAF0;--ww-qec-panel:#FFF7E8;--ww-qec-ink:#2B2118;--ww-qec-muted:#59646A;--ww-qec-line:#B87333;--ww-qec-line-soft:#D9C7B3;--ww-qec-accent:#B84923;--ww-qec-ok:#526246;--ww-qec-warn:#8A5A1F;--ww-qec-risk:#8F2F1D;}
@media (prefers-color-scheme:dark){.ww-qec{--ww-qec-bg:#1B1512;--ww-qec-panel:#241C17;--ww-qec-ink:#F2E9DF;--ww-qec-muted:#A7B0B5;--ww-qec-line:#8A5A1F;--ww-qec-line-soft:#4A3B30;--ww-qec-accent:#D9714B;--ww-qec-ok:#9AAB89;--ww-qec-warn:#D6A85A;--ww-qec-risk:#E0836B;}}
.light .ww-qec,:root.light .ww-qec{--ww-qec-bg:#FAFAF0;--ww-qec-panel:#FFF7E8;--ww-qec-ink:#2B2118;--ww-qec-muted:#59646A;--ww-qec-line:#B87333;--ww-qec-line-soft:#D9C7B3;--ww-qec-accent:#B84923;--ww-qec-ok:#526246;--ww-qec-warn:#8A5A1F;--ww-qec-risk:#8F2F1D;}
.dark .ww-qec,:root.dark .ww-qec{--ww-qec-bg:#1B1512;--ww-qec-panel:#241C17;--ww-qec-ink:#F2E9DF;--ww-qec-muted:#A7B0B5;--ww-qec-line:#8A5A1F;--ww-qec-line-soft:#4A3B30;--ww-qec-accent:#D9714B;--ww-qec-ok:#9AAB89;--ww-qec-warn:#D6A85A;--ww-qec-risk:#E0836B;}
.ww-qec{background:var(--ww-qec-bg);color:var(--ww-qec-ink);border:2px solid var(--ww-qec-line);border-radius:4px;padding:1rem;font-size:0.875rem;line-height:1.5;}
.ww-qec *{box-sizing:border-box;}
.ww-qec-h{font-weight:600;font-size:0.75rem;letter-spacing:0.08em;text-transform:uppercase;color:var(--ww-qec-muted);margin:0 0 0.5rem;}
.ww-qec-grid{display:grid;grid-template-columns:1fr;gap:0.75rem;}
@media (min-width:40rem){.ww-qec-grid{grid-template-columns:1fr 1fr;}}
.ww-qec-field{display:flex;flex-direction:column;gap:0.25rem;}
.ww-qec-field label{font-weight:600;}
.ww-qec-field select,.ww-qec-field input[type="number"]{width:100%;padding:0.4rem 0.5rem;border:1px solid var(--ww-qec-line-soft);border-radius:3px;background:var(--ww-qec-panel);color:var(--ww-qec-ink);font:inherit;}
.ww-qec-field input:disabled{opacity:0.5;}
.ww-qec-field select:focus-visible,.ww-qec-field input:focus-visible{outline:2px solid var(--ww-qec-accent);outline-offset:2px;}
.ww-qec-obs{display:flex;align-items:center;gap:0.4rem;font-weight:400;color:var(--ww-qec-muted);font-size:0.8125rem;}
.ww-qec-obs input{width:auto;}
.ww-qec-hint{color:var(--ww-qec-muted);font-size:0.8125rem;}
.ww-qec-out{margin-top:1rem;border:1px solid var(--ww-qec-line-soft);border-left:4px solid var(--ww-qec-accent);border-radius:3px;background:var(--ww-qec-panel);padding:0.75rem;}
.ww-qec-score{font-size:1.75rem;font-weight:700;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;}
.ww-qec-band{font-weight:600;color:var(--ww-qec-accent);}
.ww-qec-table{width:100%;border-collapse:collapse;margin-top:0.75rem;font-size:0.8125rem;}
.ww-qec-table caption{text-align:left;font-weight:600;color:var(--ww-qec-muted);padding-bottom:0.35rem;}
.ww-qec-table th,.ww-qec-table td{border-bottom:1px solid var(--ww-qec-line-soft);padding:0.35rem 0.4rem;text-align:left;vertical-align:top;}
.ww-qec-table th{color:var(--ww-qec-muted);font-weight:600;}
.ww-qec-num{text-align:right;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:nowrap;}
.ww-qec-basis{font-size:0.75rem;text-transform:uppercase;letter-spacing:0.04em;}
.ww-qec-basis[data-basis="observed"]{color:var(--ww-qec-ok);}
.ww-qec-basis[data-basis="inferred"]{color:var(--ww-qec-warn);}
.ww-qec-basis[data-basis="unknown"]{color:var(--ww-qec-risk);}
.ww-qec-scroll{overflow-x:auto;}
.ww-qec-note{margin-top:0.75rem;padding-top:0.6rem;border-top:1px dashed var(--ww-qec-line-soft);color:var(--ww-qec-muted);font-size:0.8125rem;}
.ww-qec-ctx{margin-top:0.75rem;border:1px dashed var(--ww-qec-line-soft);border-radius:3px;padding:0.6rem;color:var(--ww-qec-muted);font-size:0.8125rem;}
.ww-qec-ctx ul{margin:0.3rem 0 0;padding-left:1.1rem;}
.ww-qec-reset{margin-top:0.75rem;padding:0.35rem 0.7rem;border:1px solid var(--ww-qec-line);border-radius:3px;background:transparent;color:var(--ww-qec-ink);font:inherit;font-size:0.8125rem;cursor:pointer;}
.ww-qec-reset:focus-visible{outline:2px solid var(--ww-qec-accent);outline-offset:2px;}
`;
  const [exposureStatus, setExposureStatus] = useState('signature_exposure_observed');
  const [txObserved, setTxObserved] = useState(true);
  const [dormancyObserved, setDormancyObserved] = useState(true);
  const [dormancyDays, setDormancyDays] = useState('365');
  const [valueObserved, setValueObserved] = useState(true);
  const [valueUsd, setValueUsd] = useState('100000');
  const [ageObserved, setAgeObserved] = useState(true);
  const [ageDays, setAgeDays] = useState('1095');
  const [migrationPathPresent, setMigrationPathPresent] = useState(false);
  const toNumber = raw => {
    const parsed = Number.parseFloat(raw);
    return Number.isFinite(parsed) ? parsed : null;
  };
  const result = useMemo(() => deriveDocsQuantumExposureScore({
    exposureStatus,
    txObserved,
    daysDormant: dormancyObserved ? toNumber(dormancyDays) : null,
    totalBalanceUsd: valueObserved ? toNumber(valueUsd) : null,
    keyAgeDays: ageObserved ? toNumber(ageDays) : null,
    migrationPathPresent
  }), [exposureStatus, txObserved, dormancyObserved, dormancyDays, valueObserved, valueUsd, ageObserved, ageDays, migrationPathPresent]);
  const reset = () => {
    setExposureStatus('signature_exposure_observed');
    setTxObserved(true);
    setDormancyObserved(true);
    setDormancyDays('365');
    setValueObserved(true);
    setValueUsd('100000');
    setAgeObserved(true);
    setAgeDays('1095');
    setMigrationPathPresent(false);
  };
  const numberFields = [{
    name: 'value',
    label: 'Value at risk (USD)',
    hint: 'Anchors: $1 → 0, $10k → 10, $100k → 18, $1M → 25 points, log-interpolated between.',
    observed: valueObserved,
    onObservedChange: setValueObserved,
    value: valueUsd,
    onValueChange: setValueUsd,
    step: '1000'
  }, {
    name: 'dormancy',
    label: 'Days since last activity',
    hint: 'Anchors: 30d → 0, 180d → 5, 730d → 12, 1825d → 20 points, log-interpolated between.',
    observed: dormancyObserved,
    onObservedChange: setDormancyObserved,
    value: dormancyDays,
    onValueChange: setDormancyDays,
    step: '1'
  }, {
    name: 'age',
    label: 'Key / signature age (days)',
    hint: 'Anchors: 1d → 0, 365d → 5, 1095d → 10, 1825d → 15 points, log-interpolated between.',
    observed: ageObserved,
    onObservedChange: setAgeObserved,
    value: ageDays,
    onValueChange: setAgeDays,
    step: '1'
  }];
  return <div className="ww-qec not-prose">
      <style>{STYLES}</style>

      <p className="ww-qec-h">Quantum exposure calculator — educational, no wallet data</p>

      <div className="ww-qec-grid">
        <div className="ww-qec-field">
          <label htmlFor={`${idPrefix}-status`}>Signature exposure status</label>
          <select id={`${idPrefix}-status`} value={exposureStatus} onChange={e => setExposureStatus(e.target.value)} aria-describedby={`${idPrefix}-status-hint`}>
            {STATUS_OPTIONS.map(option => <option key={option.value} value={option.value}>
                {option.label}
              </option>)}
          </select>
          <span className="ww-qec-obs">
            <input id={`${idPrefix}-tx`} type="checkbox" checked={txObserved} onChange={e => setTxObserved(e.target.checked)} />
            <label htmlFor={`${idPrefix}-tx`}>Transaction history was observed</label>
          </span>
          <span id={`${idPrefix}-status-hint`} className="ww-qec-hint">
            Unknown emits no score at all. Without observed history, “no outgoing
            signature” adds 0, not the observed baseline of 5.
          </span>
        </div>

        {numberFields.map(field => <div className="ww-qec-field" key={field.name}>
            <label htmlFor={`${idPrefix}-${field.name}`}>{field.label}</label>
            <input id={`${idPrefix}-${field.name}`} type="number" inputMode="numeric" min="0" step={field.step} value={field.observed ? field.value : ''} disabled={!field.observed} onChange={e => field.onValueChange(e.target.value)} aria-describedby={`${idPrefix}-${field.name}-hint`} />
            <span className="ww-qec-obs">
              <input id={`${idPrefix}-${field.name}-observed`} type="checkbox" checked={field.observed} onChange={e => field.onObservedChange(e.target.checked)} />
              <label htmlFor={`${idPrefix}-${field.name}-observed`}>Observed for this wallet</label>
            </span>
            <span id={`${idPrefix}-${field.name}-hint`} className="ww-qec-hint">
              {field.hint}
            </span>
          </div>)}

        <div className="ww-qec-field">
          <span className="ww-qec-obs">
            <input id={`${idPrefix}-migration`} type="checkbox" checked={migrationPathPresent} onChange={e => setMigrationPathPresent(e.target.checked)} />
            <label htmlFor={`${idPrefix}-migration`}>
              Programmable upgrade path inferred (AA / multisig)
            </label>
          </span>
          <span className="ww-qec-hint">
            The only subtractive term: up to −{MIGRATION_OFFSET_POINTS} points,
            never below 0.
          </span>
        </div>
      </div>

      <div className="ww-qec-out" aria-live="polite">
        <p>
          <span className="ww-qec-score">{result.score === null ? 'null' : result.score}</span>{' '}
          <span className="ww-qec-band">{result.label}</span>
        </p>
        <p>
          Status <code>{result.status}</code> · confidence <code>{result.confidence}</code> ·{' '}
          {result.evidenceCount} observed evidence dimension(s)
        </p>

        <div className="ww-qec-scroll">
          <table className="ww-qec-table">
            <caption>Per-factor contribution to the numeric score</caption>
            <thead>
              <tr>
                <th scope="col">Factor</th>
                <th scope="col">Basis</th>
                <th scope="col" className="ww-qec-num">Max</th>
                <th scope="col" className="ww-qec-num">Points</th>
              </tr>
            </thead>
            <tbody>
              {result.signals.map(signal => <tr key={signal.key}>
                  <th scope="row">
                    {signal.label}
                    <br />
                    <span className="ww-qec-hint">{signal.detail}</span>
                  </th>
                  <td>
                    <span className="ww-qec-basis" data-basis={signal.basis}>
                      {signal.basis}
                    </span>
                  </td>
                  <td className="ww-qec-num">{signal.weight}</td>
                  <td className="ww-qec-num">{signal.points}</td>
                </tr>)}
              <tr>
                <th scope="row">Composite before offset</th>
                <td />
                <td className="ww-qec-num" />
                <td className="ww-qec-num">{result.basePoints}</td>
              </tr>
              <tr>
                <th scope="row">Migration-readiness offset</th>
                <td />
                <td className="ww-qec-num" />
                <td className="ww-qec-num">{result.migrationOffset}</td>
              </tr>
              <tr>
                <th scope="row">Score (clamped 0–100)</th>
                <td />
                <td className="ww-qec-num" />
                <td className="ww-qec-num">{result.score === null ? 'null' : result.score}</td>
              </tr>
            </tbody>
          </table>
        </div>

        <p className="ww-qec-note">{result.explanation}</p>
      </div>

      <div className="ww-qec-ctx">
        <strong>Observed but not included in the numeric score:</strong>
        <ul>
          {NON_SCORING_CONTEXT.map(item => <li key={item}>{item}</li>)}
        </ul>
        These are real WalletWall observations shown elsewhere in the product. They contribute
        exactly zero points here, because they contribute zero points in production.
      </div>

      <p className="ww-qec-note">
        Illustrative inputs only — no address is accepted and no data is fetched. This is a
        forward-looking heuristic for migration planning, not a statement of current risk, not a
        security assessment, and not financial advice. Quantum Exposure is a separate surface from
        Migration Readiness and from Stablecoin Vault readiness.
      </p>

      <button type="button" className="ww-qec-reset" onClick={reset}>
        Reset to the worked example
      </button>
    </div>;
};

# Scoring Methodology

WalletWall scores **wallet exposure** — how much attention a wallet warrants and how urgent its migration-readiness planning is. This page explains the factors in plain English, the inputs and outputs, the shared risk tiers, a worked example, and the limits of the method.

<Warning>
  Exposure scores are forward-looking heuristics for risk prioritization and long-term migration planning. They do **not** indicate that a wallet is currently vulnerable to theft or exploitation by any existing technology, and they are **not** investment advice.
</Warning>

## Intuition pump: the RuneScape wall

Before the formal model, a warm-up. WalletWall's methodology is easier to trust once you have a *mental model* of what it is doing — so we borrow one from an unlikely place: the trading economy of the online game **RuneScape**.

<Info>
  **What's an "intuition pump"?** It's a memorable, deliberately simplified story that helps you build a first mental model of an idea before the real, precise version arrives. It is a teaching device — **not** evidence, and **not** part of how WalletWall actually scores a wallet. The formal model in the next section replaces every piece of it.
</Info>

Why a game? Because RuneScape accidentally rehearses the exact problems a wallet analyst faces: **one persistent identity that shows up in different places, observers who only ever see part of the story, value that moves between accounts without an obvious handshake, and reputations that can be manufactured.** Those are the same problems on-chain — just with more money and no game moderators.

### One account, many worlds

A RuneScape *account* is a persistent thing. The player can hop between dozens of near-identical server **worlds**, and the account — its name, its level, its inventory — comes along. What changes is only *which world you happen to be looking at.*

```mermaid theme={null}
stateDiagram-v2
    accTitle: A persistent RuneScape account observed across different server worlds
    accDescr: The same account moves between World A, World B, and World C. Each is a separate observation context, but the underlying account and its state persist. It occupies one active world at a time.
    [*] --> WorldA
    WorldA --> WorldB: hop worlds
    WorldB --> WorldC: hop worlds
    WorldC --> WorldA: return
    note right of WorldB
      Same persistent account.
      Different observation context.
      One active session at a time.
    end note
    classDef ctx fill:#B84923,stroke:#6B2412,color:#FFF7E8,stroke-width:1.5px;
    class WorldA,WorldB,WorldC ctx
```

The useful idea here is the split between **identity** and **where you observe it**. If your friend only ever logs into World 302, they might swear an account is "inactive" — when really it has been busy on World 419 the whole time. Their conclusion isn't lying; it is just *incomplete*. **Missing observation is not proof of inactivity.**

There is also a quantum-flavored way to say it: until you actually observe the account, you can only associate it with a *set of possible* worlds and states. Observation collapses the possibilities into what you can see.

<Warning>
  This is an analogy about **identity, state, observation, and incomplete knowledge** — nothing more. It is **not** literal quantum superposition, entanglement, or teleportation, and RuneScape worlds are **not** technically equivalent to blockchain networks. A single character occupies one active world at a time; the *account* persists across worlds, and one *person* may control several accounts. Keep those three things — account, session, and controller — distinct.
</Warning>

### Many accounts, one player, and drop trading

Now the twist that makes it interesting. One *person* can run several accounts. And RuneScape has a folk mechanic called **drop trading**: one account drops an item on the ground, and — a moment later, in the same spot — another account picks it up. No trade window, no explicit handshake between the two accounts. Value moved; the *mechanism* deliberately hides the relationship.

```mermaid theme={null}
flowchart LR
    accTitle: Indirect value transfer between two accounts via drop trading
    accDescr: A controller is illustrated behind two accounts. Account A drops an item, Account B retrieves it, producing an observed relationship. The controller link is illustrative unless independently established.
    P["Player / controller<br/>(illustrative)"]:::decision --> A["Account A"]:::process
    P --> B["Account B"]:::process
    A --> D["Item dropped"]:::input
    D --> B
    B --> O["Observed relationship<br/>between A and B"]:::output
    classDef process fill:#B84923,stroke:#6B2412,color:#FFF7E8,stroke-width:1.5px;
    classDef decision fill:#D6A85A,stroke:#8A5A1F,color:#2B2118,stroke-width:1.5px;
    classDef input fill:#FAFAF0,stroke:#B87333,color:#2B2118,stroke-width:1.5px;
    classDef output fill:#9AAB89,stroke:#526246,color:#172014,stroke-width:1.5px;
```

An observer watching that spot sees a *relationship* between Account A and Account B. That relationship is **evidence worth weighing** — but on its own it does **not** prove common ownership, a real-world identity, coordination, or bad intent. Two strangers can use the same drop spot by accident; a guildmate can pick up a genuinely lost item. The relationship is a lead, not a verdict.

### Manufactured trust

RuneScape is also full of confidence tricks, and they teach the last lesson. A scammer will show up on an **old, high-level account** wearing **expensive gear**, sometimes flanked by **friends who vouch for them**, and offer to "double your gold." A **dormant** account that suddenly reactivates with unusual behavior deserves a second look. None of these signals — age, visible wealth, social proof, a sudden return — is trustworthy on its own, and a convincing-looking account can still have very thin evidence underneath.

The takeaways carry over one-for-one to wallets:

* A **single indicator rarely proves anything.** Account age alone is weak. Visible wealth doesn't guarantee legitimacy. Coordinated accounts can manufacture social proof.
* **Context changes the meaning of a signal.** Dormancy followed by unusual activity can matter — or have a perfectly boring explanation.
* **Missing evidence is not low risk.** An account you can't see clearly is *unknown*, not *safe*.
* **Evidence, confidence, and risk are different things.** You can have a scary-looking situation with weak evidence, or a calm one with strong evidence. A score presented without its evidence quality is false confidence.

### Mapping the analogy to WalletWall

<Tabs>
  <Tab title="RuneScape intuition">
    An account keeps its identity as it hops worlds; you might only ever watch one world; a drop trade links two accounts without a handshake; an old, rich, well-vouched account can still be a scam.
  </Tab>

  <Tab title="General principle">
    A persistent entity can appear across environments; observation is partial; indirect transfers create relationships; reputation signals can be manufactured and must be weighed together, not trusted individually.
  </Tab>

  <Tab title="WalletWall implementation">
    WalletWall observes a **single wallet** from public, read-only on-chain data and scheduled analytics. It scores that wallet's own exposure. It labels how complete the evidence is (confidence), and it never converts "we couldn't see it" into "it's safe." Relationship and clustering ideas stay *illustrative here* — they are **not** inputs to the exposure score.
  </Tab>
</Tabs>

| RuneScape intuition        | General concept                           | WalletWall analogy                               | Integrity guardrail                                             |
| -------------------------- | ----------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------- |
| Player account             | Persistent entity                         | Wallet or analyzed entity                        | A wallet address is not automatically a known person.           |
| Game world                 | Observation environment                   | Chain, provider, time window, or product surface | Worlds and blockchain networks are not technically equivalent.  |
| World hopping              | Context transition                        | Activity seen across analytical environments     | Cross-context identity requires evidence.                       |
| Seeing only one world      | Partial observation                       | Incomplete provider / chain / history coverage   | Missing data is not proof of inactivity.                        |
| Multiple accounts          | Identifiers under possible common control | Related / clustered wallets                      | Similar behavior does not prove shared ownership.               |
| Drop trading               | Indirect value transfer                   | Transfer paths and counterparty relationships    | A relationship does not prove identity or intent.               |
| Old account                | Historical continuity                     | Wallet age / first-seen activity                 | Old wallets can be compromised, sold, or repurposed.            |
| Valuable inventory         | Visible wealth                            | Balance / asset exposure                         | Wealth does not establish benign behavior.                      |
| Vouching friends           | Manufactured consensus                    | Clustered counterparties                         | Association should not imply guilt.                             |
| Dormant account returns    | Behavioral transition                     | Dormancy then new activity                       | Transitions can have legitimate explanations.                   |
| Player behind the accounts | Latent controller                         | Possible shared actor                            | WalletWall does not claim real-world identity without evidence. |

<AccordionGroup>
  <Accordion title="Two more RuneScape cons, if you want them">
    * **The doubling-money scam.** "Give me 1M and I'll send back 2M." The bait is a fast, irreversible action framed by a trustworthy-looking account. On-chain, the wallet equivalent is a trusted-looking counterparty requesting a one-way approval or transfer. The lesson is the same: reputation is not verification, and irreversibility deserves suspicion.
    * **Item lending and the sudden return.** A long-idle account reactivates, borrows or gathers valuable items, and behaves unlike its history. Worth attention — but a returning player is also just a returning player. It is a *signal to weigh*, not a conviction.
  </Accordion>
</AccordionGroup>

<Expandable title="Where the analogy stops (please read before the formal model)">
  The RuneScape story is a teaching device. It is explicitly **not**:

  * evidence WalletWall uses, or a validation dataset, or labeled wallet behavior;
  * part of the scoring formula — the score below weighs a **single wallet's own** signals, and does **not** cluster wallets, assert common control, or use drop-trade-style relationship inference as an input;
  * a claim that blockchain behavior equals game behavior;
  * literal quantum physics;
  * proof of ownership, common control, or malicious intent for any real wallet.

  Anything in the analogy that sounds like "linking accounts to a person" is **intuition only**. The formal model states exactly what it does and does not do.
</Expandable>

### From intuition to the formal model

That is the whole point of the warm-up: **identity can persist across changing environments, observations are incomplete, indirect interactions can connect apparently separate accounts, and manufactured signals must be weighed together.** Now WalletWall replaces the analogy with explicit, observable evidence — defined inputs, a fixed weighting, an honest confidence level, and documented limits.

```mermaid theme={null}
flowchart TD
    accTitle: From RuneScape intuition to WalletWall's formal exposure score
    accDescr: A pipeline from RuneScape intuition to a general principle to observable wallet evidence to evidence quality and freshness to the formal scoring model to a score carrying confidence and limitations.
    I["RuneScape intuition"]:::input --> P["General principle"]:::input
    P --> E["Observable wallet evidence<br/>(public, read-only on-chain data)"]:::process
    E --> Q["Evidence quality and freshness<br/>(coverage, staleness)"]:::decision
    Q --> S["Formal exposure score<br/>(fixed SCORE_WEIGHTS)"]:::process
    S --> C["Score with confidence<br/>and stated limitations"]:::output
    classDef input fill:#FAFAF0,stroke:#B87333,color:#2B2118,stroke-width:1.5px;
    classDef process fill:#B84923,stroke:#6B2412,color:#FFF7E8,stroke-width:1.5px;
    classDef decision fill:#D6A85A,stroke:#8A5A1F,color:#2B2118,stroke-width:1.5px;
    classDef output fill:#9AAB89,stroke:#526246,color:#172014,stroke-width:1.5px;
```

<Card title="Jump to the formal Quantum Exposure Score" icon="function" href="/features/quantum-intelligence#quantum-exposure-score">
  The exact signal weights, labels, and caveat layers that replace the analogy.
</Card>

## Plain-English overview

WalletWall reads public, on-chain data for a wallet and asks a few practical questions:

* Has the wallet **revealed its public key** on-chain (by sending a transaction)?
* How **much value** is at stake?
* How **dormant** is it?
* What does its **transaction history** look like?
* How **hard** would migration be (EOA vs. smart-contract / multisig)?
* How **concentrated** are its holdings, including stablecoins?
* What **behavioral patterns** does the activity show?
* How **complete** is the underlying data?

It combines these into a normalized exposure score, places the wallet in a shared **risk tier**, and recommends a **migration-readiness path**. Every result carries a **confidence level** and **source caveats**.

## Scoring factors

The **Quantum Exposure Score** itself is built from a small, fixed set of signal groups. Each contributes at most the points shown; **missing data never adds points** — an unavailable signal lowers *confidence* instead. These are the only inputs to the number.

| Scored signal group                 | Max points | What it measures                                                                                                                                                                                                                           | Why it matters                                                                                                                         |
| ----------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Signature / public-key exposure** | 35         | Whether outgoing signature activity has been observed on-chain (the ECDSA public key becomes recoverable after the first outgoing transaction). A wallet with observed history but no outgoing signature contributes a small baseline (5). | A revealed public key is the precondition for long-horizon quantum signature risk. Receive-only wallets have lower immediate exposure. |
| **Value at risk**                   | 25         | Reported balance tier: `≥ $1M` (25), `≥ $100k` (18), `≥ $10k` (10), `> $0` (5).                                                                                                                                                            | Higher value raises the "bounty" and the stakes of migration.                                                                          |
| **Dormancy**                        | 20         | Observed last-activity bucket: `≥ 730d` (20), `180–730d` (12), `30–180d` (5), active (0).                                                                                                                                                  | Long-dormant wallets may be unmonitored and harder to migrate.                                                                         |
| **Key / signature age**             | 15         | Age of the exposed key/signature: `≥ 5y` (15), `≥ 3y` (10), `≥ 1y` (5).                                                                                                                                                                    | Longer exposure widens the analysis surface over time.                                                                                 |
| **Migration-readiness offset**      | −10        | Subtracted when a programmable upgrade path (ERC-4337 AA / multisig) is inferred.                                                                                                                                                          | A programmable wallet has a rotation path; a plain EOA does not.                                                                       |

The composite is normalized to `0–100` (or `null` on insufficient evidence) and labeled **Low** (below 25), **Moderate** (≥ 25), **Elevated** (≥ 50), or **Migration priority** (≥ 75). For the exact weights and caveat layers, see [Quantum Intelligence](/features/quantum-intelligence#quantum-exposure-score).

### Related signals that inform the assessment — but not the score

These shape how a wallet is *reviewed and reported*; they are **not** components of the numeric exposure score.

| Signal                                | Role                                                                                                                                     | Note                                                                                                                                     |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **Stablecoin concentration**          | Context on how concentrated holdings are, including specific pegs/pools.                                                                 | Informed by Stable Seer; presented alongside the score, not summed into it.                                                              |
| **Holder / whale behavioral signals** | Deterministic observations (extraction-style activity, counterparty concentration, relay routing, activity ramp, asset/value ambiguity). | Separate `adversarialSignals`; each carries its own confidence. **Not findings of wrongdoing** and never summed into the exposure score. |
| **Confidence / data completeness**    | How much of the above could actually be determined.                                                                                      | Missing or stale data lowers confidence or yields "Unknown" — it never adds exposure points.                                             |

#### Try it — which inputs actually move the number

The same calculator used on [Quantum Intelligence](/features/quantum-intelligence#quantum-exposure-score),
embedded here to make the split above concrete: only the scored signal groups have
controls. The related signals are listed as context that contributes zero points, and
switching an axis to *not observed* lowers confidence rather than lowering the score.

<QuantumExposureCalculator idPrefix="scoring-method" />

## Inputs

* **Wallet transaction history** — from public providers (Etherscan, Alchemy, The Graph).
* **Chain signature metadata** — a derived lookup of each chain's default signature scheme.
* **Scheduled Dune feeds** — dormancy, signature exposure, value-at-risk, and migration-readiness facts (scheduled/cached, never live-streamed).
* **Market & concentration context** — token/stablecoin pricing and holdings (CoinGecko, Stable Seer feeds).

## Outputs

* **Quantum Exposure Score** — normalized `0–100`, or `null` when data is insufficient.
* **Exposure label** — Low / Moderate / Elevated exposure, Migration priority, or Unknown.
* **Shared risk tier** — Monitor, Review, Migrate, or Vault Candidate.
* **Migration-readiness recommendation** — a recommended path with urgency, difficulty, blockers, and a next action.
* **Confidence level** and a **caveats** array describing data completeness and staleness.
* **Source provenance** — which feeds contributed, and whether data is live or scheduled/cached.

## Shared risk tiers

WalletWall normalizes every assessment into one of four shared tiers. The tiers are the common language across modules and reports.

| Tier                | What it means                         | Typical signals                                                                                   | Suggested posture                                                                                             |
| ------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **Monitor**         | Low urgency. Nothing to act on yet.   | Low/moderate exposure, low value at risk, public key may be unexposed.                            | Keep watching; re-check on schedule.                                                                          |
| **Review**          | Worth a closer look and a plan.       | Moderate-to-high exposure with meaningful value; exposed public key.                              | Review the wallet, plan a migration approach.                                                                 |
| **Migrate**         | Prioritize action.                    | Elevated exposure or Migration priority, high value, a feasible migration path exists.            | Begin a concrete migration (e.g. multisig, treasury custody plan).                                            |
| **Vault Candidate** | Research path surfaced — conditional. | Long-horizon, high-value, quantum-exposed wallet where experimental migration paths are relevant. | Explore the WalletWall Vault Candidate testnet rehearsal research path as one option. Not production custody. |

<Note>
  Tiers are **prioritization bands, not verdicts.** A "Migrate" tier means a wallet should be near the top of a migration queue, not that it is unsafe today. The **Vault Candidate** tier always carries the research-prototype disclosure — it is conditional and research-oriented, never a custody recommendation.
</Note>

Tiers map onto the underlying migration-readiness paths as follows:

| Migration path                 | Risk tier       |
| ------------------------------ | --------------- |
| `monitor`                      | Monitor         |
| `fresh-wallet`, `split-wallet` | Review          |
| `multisig`, `treasury-custody` | Migrate         |
| `vault-prototype`              | Vault Candidate |

See [Migration Readiness](/concepts/migration-readiness) for the full path definitions and recommended actions.

## Example interpretation

> A wallet holds **\~\$2.4M**, mostly in one asset and a large stablecoin position. It has **sent transactions** (public key revealed), shows **address reuse**, and has been **dormant for \~8 months**. It is a plain **EOA** with no detected upgrade path.

WalletWall would read this as:

* **Exposure:** Elevated — significant value in a classical EOA with a revealed public key.
* **Concentration:** Elevated — single-asset plus stablecoin concentration.
* **Dormancy:** Cold (180–730 days) — raises readiness risk.
* **Migration friction:** High — EOA with no automated rotation path.
* **Recommended path:** `multisig` or `treasury-custody`.
* **Risk tier:** **Migrate.**
* **Confidence:** Moderate-to-high if all feeds are fresh; reduced with a caveat if Dune data is stale.

The report would recommend prioritizing this wallet for migration and distributing signing across a multisig with an upgrade path — while noting that the score reflects long-term planning urgency, not current exploitability.

## Limitations

* **Heuristic, not deterministic truth.** Scores are estimates derived from observable on-chain signals and weighted heuristics.
* **Data-dependent.** Missing transaction history, unknown wallet type, or stale Dune data lowers confidence or yields "Unknown."
* **Chain scope.** WalletWall scores Ethereum/EVM EOAs and contract wallets. Solana and other non-EVM chains are documented as general categories only, not scored.
* **Behavioral signals are observations.** They use language like "may indicate" and "resembles," carry confidence levels, and are never findings of wrongdoing, intent, or legal status.
* **Scheduled data is not live.** Dune-sourced facts are scheduled/cached and labeled as such; they can lag the latest on-chain state.

## What the score does not mean

* It does **not** mean a wallet is currently vulnerable, hacked, or compromised.
* It does **not** predict when a quantum computer will break ECDSA, or name a "Q-Day."
* It is **not** a claim that the wallet is "unsafe" or "quantum-vulnerable."
* It is **not** a measure of the owner's intent, identity, or legal standing.
* It is **not** investment advice or a basis for valuing assets.

## Related

* [Quantum Intelligence](/features/quantum-intelligence) — component weights, labels, and caveats.
* [Quantum Exposure Clock](/concepts/quantum-exposure-clock) — why exposure is wallet-specific.
* [Migration Readiness](/concepts/migration-readiness) — paths, tiers, and recommended actions.
