agents/skills/daml/economic-design-audit/SKILL.md
Trigger Pattern MONETARY_PARAMETER flag (fee, rate, emission, cap, bps as template fields) - Inject Into Breadth agents (merged via M4 hierarchy)
npx skillsauth add plamentsv/plamen economic-design-auditInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Trigger Pattern: MONETARY_PARAMETER flag (required) Inject Into: Breadth agents (merged via M4 hierarchy) Finding prefix:
[DML-EDA-N]Rules referenced: R2, R10, R13, R14
rate|fee|reward_rate|emission|inflation|cap|limit|max_amount|basis_points|bps|fee_bps|spread|price|amount
DAML arithmetic context: monetary values are template fields typed Int or Decimal (Decimal = fixed-point, 10 fractional digits). There is no floating-point. A "setter" is a choice that archives a config/parameter contract and creates a successor with a changed field; a "consumer" is any choice/ensure that reads that field and branches. Critical DAML difference: Int/Decimal THROW on overflow — they do not wrap. So an economic boundary that overflows is a liveness/brick bug (the choice aborts, the path becomes un-exercisable), never a silent-value bug. Division truncates toward zero.
For every monetary parameter (a config/parameter template field set by a choice — rate, fee, reward rate, emission, cap, floor, BPS):
| Parameter (Template.field) | Setting Choice | Min Value | Max Value | ensure-Enforced? | Impact at Min | Impact at Max |
|----------------------------|----------------|-----------|-----------|--------------------|---------------|---------------|
For each: substitute min and max into ALL consuming choices.
Tag: [BOUNDARY:param=val -> outcome]
DAML-specific boundary checks:
Int/Decimal overflow in amount * rate BEFORE the division? An overflow ABORTS the choice → liveness brick ([ELEVATE:ENSURE_GAP]/boundary), not a wrap.ensure blocks zero.ensure to fail (PreconditionFailed)?ensure? (Int/Decimal are signed; ensure amount > 0.0 is the only guard.)List all economic invariants the protocol must maintain, and whether a setter choice can break them:
| Invariant | Parameters Involved | Can a Setter Choice Break It? | Choices That Assume It | |-----------|---------------------|-------------------------------|------------------------|
For each setter: can creating a successor with a changed field break an invariant a consuming choice depends on? If yes → finding.
DAML-specific invariants:
Decimal truncation).ensure amount >= 0.0 prevents a negative-amount contract entering the ACS; without it the create succeeds and every downstream choice trusts a broken invariant.DAML has no global mutable counter; a cap/total is itself a contract whose field is updated by a choice. The recurring bug: a value-creating choice does NOT update the accumulator contract, so the cap is never enforced across transactions.
| Cap/Total (Template.field) | Updated By (choices) | Read/Enforced By (choices) | Every Value-Creating Path Updates It? | Finding? | |----------------------------|----------------------|----------------------------|---------------------------------------|----------|
Check (R14 cross-variable + constraint coherence + setter regression):
[ELEVATE:VALUE_CONSERVATION]).ensure/guard do then (abort? lock out all holders?) — setter regression.controller is non-privileged or argument-derived, a holder can inflate issuance past the cap (cross-reference AUTHORIZATION_MODEL).Pick 3 representative rate values and trace through the actual choice-body formula:
| Fee Param | Value | Formula | Input Amount | Expected Output | Actual Output | Match? | |-----------|-------|---------|--------------|-----------------|---------------|--------|
Tag: [BOUNDARY:fee_bps={val} -> effective_rate={computed}]
Note: Decimal is fixed-point (10 fractional digits); verify the formula's scale matches the field's declared type.
Red flags:
amount * MAX / (MAX - fee) charges a higher effective rate than fee/MAX.Decimal/Int division truncates toward zero — verify the intended direction and that it does not let the protocol keep dust on every operation.amount * rate / MAX vs amount / MAX * rate — the second loses precision for small amounts.For every fee computation, trace the base amount through ALL subsequent choice consequences:
| Fee Site (Template.Choice) | Base Field | Reduced After Fee? | How | Fee Recomputed? | Overcharge? | |----------------------------|-----------|--------------------|-----|-----------------|-------------|
Methodology: identify the fee base field → trace FORWARD through the successor create → if the base is reduced (capped, adjusted) AFTER the fee is computed → fee charged on a larger base than processed.
If a fee is taken during split/transfer: does child1.amount + child2.amount + fee == parent.amount? With Decimal truncation, does deposit-vs-withdraw rounding consistently favor one party? Cross-reference SHARE_ALLOCATION_FAIRNESS.
For protocols with emission/reward distribution via choices:
| Emission Param | Max per Tx | Pool Balance Required | Txns to Depletion at Max | Cap Contract Exists? | |----------------|-----------|------------------------|--------------------------|----------------------|
**ID**: [DML-EDA-N]
**Verdict**: CONFIRMED / PARTIAL / REFUTED / CONTESTED
**Step Execution**: ✓1,2,3,4,5 | ✗(reasons) | ?(uncertain)
**Rules Applied**: [R2:___, R10:___, R13:___, R14:___]
**Severity**: Critical/High/Medium/Low/Info (Int/Decimal overflow is a LIVENESS finding, NOT auto-downgraded as silent-wrap)
**Location**: {Module}.daml:LineN (template X, choice Y)
**Title**: {parameter boundary / invariant break / cap-not-tracked / fee miscalculation}
**Description**: {specific issue with code reference and a numerical Decimal/Int example}
**Impact**: {quantified at worst-state operational parameters — Rule 10}
**PoC steer**: boundary-value Scripts (set field to 0 / max / negative and trace the consuming choice), or a multi-transaction Script that issues past a cap because the accumulator contract was not updated; assert conservation/cap violated, or the consuming choice aborts (liveness).
| Section | Required | Completed? | Notes | |---------|----------|------------|-------| | 1. Parameter Boundary Analysis | YES | | | | 2. Economic Invariant Identification | YES | | | | 3. Accumulator / Cap Coherence Across Transactions | YES | | R14 — primary DAML lane, never skip | | 4. Fee / Rate Formula Verification | IF fee/rate parameters detected | | | | 5. Emission / Inflation Sustainability | IF emission/reward detected | | |
If any step skipped, document a valid reason (N/A, single parameter, no fees, no emissions, no cap).
data-ai
Trigger Pattern Always (run during recon TASK 0, not breadth) - Inject Into Recon agent only (meta_buffer.md enrichment)
data-ai
Trigger Pattern Always (run during recon TASK 0, not breadth) - Inject Into Recon agent only (meta_buffer.md enrichment)
data-ai
Trigger Pattern Always (run during recon TASK 0, not breadth) - Inject Into Recon agent only (meta_buffer.md enrichment)
data-ai
Trigger STABLESWAP_FORK flag (fork-ancestry detects Curve/StableSwap parent via get_d/get_y/ramp_a/StableSwap patterns) - Agent Type general-purpose (standalone niche agent, 1 budget slot)