LlamaRisk

Update schemas

The Pendle PT implementation uses three case-sensitive update-type strings:

EmaImpliedRateUpdate
PendleDiscountRateUpdate
EModeCategoryUpdate

The market-state record is stored in LlamaGuardOracle. The two executable recommendation types are stored in RiskOracle.

Common recommendation shape

Executable RiskOracle recommendations contain:

FieldPurpose
referenceIdHuman-readable source and model provenance
newValueABI-encoded recommendation intended for the relevant agent or reader
updateTypeExact typed-recommendation name
marketPT address or encoded eMode ID
additionalDataABI-encoded audit context not injected as the parameter value

Single publication encodes one tuple. Bulk publication encodes five parallel arrays.

Reference IDs

The shared format is:

<updateType>:<sourceChainId>:<market>:<sourceLocator>:v<modelVersion>

For EMA and risk-parameter records, sourceLocator is the finalized source block. For a discount-rate record it is the upstream EMA update ID.

EmaImpliedRateUpdate

Market key: PT asset address

newValue = abi.encode(int256 emaLnImpliedRateWad)

additionalData is encoded in this order:

IndexABI typeMeaning
0uint256Current raw logarithmic implied rate
1uint256Previous rate EMA
2uint32EMA span
3uint256Maturity timestamp
4uint256Calculation timestamp
5uint256Finalized source block number
6uint32Model version
7uint8Flags
8uint256Current raw market proportion
9uint256Previous proportion EMA
10uint256New proportion EMA

Flags:

BitMeaning
0Rate EMA seeded from the current observation
1Proportion EMA seeded from the current observation

The report also includes a publication deadline. The workflow sets it to 86,400 seconds after calculation.

PendleDiscountRateUpdate

Market key: PT asset address

newValue = abi.encode(uint256 nextDiscountRatePerYear)

additionalData:

IndexABI typeMeaning
0uint256Current discount rate
1uint256Unbounded target discount rate
2int256Signed price deviation, WAD-scaled
3uint256EMA logarithmic implied rate
4uint256Time to maturity in years, WAD-scaled
5uint256Upstream EMA update ID
6uint64EMA observation timestamp
7uint64EMA source block
8uint32EMA span
9uint32Model version
10uint16Flags
11uint64Retired-field sentinel, always zero
12uint64Retired-field sentinel, always zero

The last two fields preserve the historical tuple width. Active delay and movement controls now live in the router, AgentHub, and RangeValidationModule; zero does not mean those controls are disabled.

Flags:

BitMeaning
0Directional rate step applied
1Adapter maximum discount rate applied
2Raw adapter price reached the methodology floor
3An upward discount-rate move was step-capped

EModeCategoryUpdate

Market key: eMode ID encoded as a 20-byte address

newValue = abi.encode(
  uint256 ltvBps,
  uint256 liquidationThresholdBps,
  uint256 liquidationBonusBps
)

additionalData:

IndexABI typeMeaning
0addressSource PT asset
1uint16eMode category ID
2uint256Current discount rate
3uint256Time to maturity in years, WAD-scaled
4uint256LB floor in bps
5uint256LT cap in bps
6uint256Computed LT bound in bps
7uint32Model version
8uint8Flags
9uint256EMA logarithmic implied rate
10uint256EMA market proportion
11uint256Upstream EMA update ID
12uint256Reference endpoint multiplier, scaled by 10,000
13uint64EMA observation timestamp
14uint64EMA source block
15uint256Reference market proportion, WAD-scaled
16int256Liquidation-bonus slope, WAD-scaled
17uint256Stressed AMM price, WAD-scaled

Flags:

BitMeaning
0Raw adapter price reached the methodology floor
1LT was bounded by the configured cap
2Reference market proportion reached the 96% ceiling
3Negative liquidation-bonus slope was floored to zero

Signed report envelope

The two router-bound recommendation workflows wrap the bare RiskOracle payload as:

abi.encode(uint64 signedAt, bytes payload)

signedAt is the CRE consensus timestamp. The router uses it to enforce the route's maximum report age and strict ordering for each workflow, market, and update type before forwarding the bare payload to RiskOracle.

Decoding guidance

Validate updateType before decoding either byte field. Treat newValue as the typed recommendation and additionalData as provenance. Indexers should retain the raw bytes and use modelVersion when interpreting historical records.

On this page