Trigger Pattern MONETARY_PARAMETER flag (fee, rate, emission, cap, bps as template fields) - Inject Into Breadth agents (merged via M4 hierarchy)
Scanned 9/6/2026
Install to Claude Code
npx -y skills add PlamenTSV/plamen --skill economic-design-audit --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Economic Design Audit?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/plamentsv-economic-design-audit-plamen)More formats (shields.io, HTML) on the badges page.
---
name: "economic-design-audit"
description: "Trigger Pattern MONETARY_PARAMETER flag (fee, rate, emission, cap, bps as template fields) - Inject Into Breadth agents (merged via M4 hierarchy)"
---
# ECONOMIC_DESIGN_AUDIT Skill (DAML)
> **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.
---
## 1. Parameter Boundary Analysis
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**:
- Does MAX cause an `Int`/`Decimal` overflow in `amount * rate` BEFORE the division? An overflow ABORTS the choice → liveness brick (`[ELEVATE:ENSURE_GAP]`/boundary), not a wrap.
- Does 0 cause a division-by-zero? In DAML that ABORTS the transaction → verify a guard or `ensure` blocks zero.
- Does 10000 bps (100%) make the holder receive 0 (truncated) or, with fees-on-fees, push a successor's `ensure` to fail (`PreconditionFailed`)?
- Does a negative field value slip past a missing `ensure`? (`Int`/`Decimal` are signed; `ensure amount > 0.0` is the only guard.)
---
## 2. Economic Invariant Identification
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**:
- **Value conservation across split/merge/transfer**: total carried by all child contracts must equal the parent. Verify no rounding loss accumulates across many split operations (`Decimal` truncation).
- **No negative amounts**: only an `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.
- **Accumulator/cap honored across transactions**: see Section 3 — this is the highest-yield DAML economic class.
---
## 3. Accumulator / Cap Coherence Across Transactions (R14 — PRIMARY DAML LANE)
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)**:
- Is there a value-creating choice (mint/issue/Propose-Accept) that creates an asset contract but does NOT archive+recreate the cap/total contract to reflect it? → cap unenforced → unbounded issuance (`[ELEVATE:VALUE_CONSERVATION]`).
- Are two interacting limits (per-tx cap and global cap) settable by independent choices without a coherence check between them?
- Can a setter choice lower the cap field BELOW the already-accumulated total? What does the consuming `ensure`/guard do then (abort? lock out all holders?) — setter regression.
- Permissionless issuance: if the issuing choice's `controller` is non-privileged or argument-derived, a holder can inflate issuance past the cap (cross-reference AUTHORIZATION_MODEL).
---
## 4. Fee / Rate Formula Verification at Normal Values
### 4a. Concrete Example Computation
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**:
- Gross-up: `amount * MAX / (MAX - fee)` charges a higher effective rate than `fee/MAX`.
- Fee-on-fee: one fee's output feeds another's input across chained choices — combined rate is not the sum.
- Rounding direction: `Decimal`/`Int` division truncates toward zero — verify the intended direction and that it does not let the protocol keep dust on every operation.
- Division order: `amount * rate / MAX` vs `amount / MAX * rate` — the second loses precision for small amounts.
### 4b. Fee-Base Consistency
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.
### 4c. Fee Impact on Conservation
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.
---
## 5. Emission / Inflation Sustainability
For protocols with emission/reward distribution via choices:
- Maximum amount mintable per transaction / per ledger-time period?
- Can cumulative emissions exceed a reward-pool contract's tracked balance (CONTRACT abort on transfer, or silent over-issuance if unchecked)?
- Is there a supply-cap contract? Can a choice bypass it (Section 3)?
- What happens when a reward-pool contract is exhausted — does the distribute choice abort (PreconditionFailed / NO_SUCH_KEY)?
| Emission Param | Max per Tx | Pool Balance Required | Txns to Depletion at Max | Cap Contract Exists? |
|----------------|-----------|------------------------|--------------------------|----------------------|
---
## Finding Template
```markdown
**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).
```
---
## Step Execution Checklist (MANDATORY)
| 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).
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!