RAAC US Prime Rate Oracle¶
Overview¶
The RAACPrimeRateOracle is a Chainlink Functions-based oracle that fetches the latest US Prime Rate from multiple off-chain data sources and updates the LendingPool. The protocol’s borrowing curve derives from the Prime Rate (baseline equals one half of the Prime Rate), so timely and controlled updates are critical.
- Built on the same
BaseChainlinkFunctionsOracle
used by the Real Estate oracle - Off-chain job runs every 4 hours; only sends an on-chain request if the value changed
- On fulfillment, calls
lendingPool.setPrimeRate(newPrimeRate)
and emitsPrimeRateUpdated
Architecture¶
flowchart TD
subgraph "Off-chain Infrastructure"
S1[US Gov / Financial Data APIs]
S2[External Sources 2+]
J[Scheduler every 4h] --> A[AWS Job]
A -->|fetch & compare| C{Prime rate changed?}
C -->|No| Z[No on-chain action]
C -->|Yes| R[sendRequest args]
end
R --> O[RAACPrimeRateOracle<br/>Chainlink Functions]
O -->|DON executes JS| D[Chainlink DON]
D -->|returns primeRate| O
O -->|setPrimeRate primeRate| L[LendingPool]
L -->|ReserveLibrary::setPrimeRate| RL[Reserve Library]
style O fill:#e1f5fe
style L fill:#f3e5f5
style RL fill:#f3e5f5
Key points:
- Scheduler runs every 4 hours. It queries 2+ independent sources and triggers on-chain only when a change is detected.
- Chainlink Functions returns an encoded
uint256
prime rate (RAY), forwarded to the LendingPool. ReserveLibrary
enforces max ±5% change per update and updates derived rates.
Purpose¶
- Keep Prime Rate aligned with reputable external sources
- Enforce guarded updates via library-level limits (±5%)
- Deterministically adjust borrowing curve parameters derived from Prime Rate
Request Model & Cadence¶
- Arguments: as required by the Chainlink Functions source (internal to the oracle)
- Cadence: every 4 hours (off-chain). Only calls
sendRequest
when value changed - Fulfillment: single scalar
uint256
prime rate (RAY), decoded on-chain
Off-chain Source (Chainlink Functions)¶
The JavaScript source used by the Chainlink Functions DON to fetch the US Prime Rate is published here: IPFS (Pinata gateway).
Fulfillment Flow¶
- Off-chain job (cron: 4h) aggregates sources and detects a change
- Job calls
RAACPrimeRateOracle.sendRequest
(owner-gated) - Chainlink DON executes the source, returns
uint256 primeRate
- Oracle decodes and calls
lendingPool.setPrimeRate(primeRate)
- LendingPool delegates to
ReserveLibrary.setPrimeRate
which: - Rejects non-positive values
- Caps change to ±5%
- Updates
primeRate
,baseRate = 25% of prime
,optimalRate = 50% of prime
- Recomputes interest and liquidity
Key Functions¶
Function | Description | Access |
---|---|---|
sendRequest(args, bytesArgs) |
Triggers Chainlink Functions request | onlyOwner |
getPrimeRate() |
Returns last stored prime rate (RAY) | view |
Internals (Hooks)¶
Hook | Purpose |
---|---|
_emitRequestEvents(requestId, args) |
Emits PrimeRateRequestSent |
_beforeFulfill(args) |
Pre-fulfillment hook (no-op) |
_processResponse(requestId, response) |
Decodes uint256 rate, writes to lendingPool , emits PrimeRateUpdated |
Events¶
PrimeRateRequestSent(bytes32 requestId)
PrimeRateUpdated(uint256 primeRate)
Integration with Lending Pool¶
On fulfillment, the oracle calls lendingPool.setPrimeRate(lastPrimeRate)
. The LendingPool then applies ReserveLibrary.setPrimeRate
with safety checks:
function setPrimeRate(
ReserveData storage reserve,
ReserveRateData storage rateData,
uint256 newPrimeRate
) internal {
if (newPrimeRate < 1) revert PrimeRateMustBePositive();
if (newPrimeRate > WadRayMath.RAY) revert PrimeRateChangeExceedsLimit();
uint256 oldPrimeRate = rateData.primeRate;
if (oldPrimeRate > 0) {
uint256 maxIncrease = oldPrimeRate + WadRayMath.RAY.percentMul(5_00);
uint256 maxDecrease = oldPrimeRate < WadRayMath.RAY.percentMul(5_00)
? 0
: oldPrimeRate - WadRayMath.RAY.percentMul(5_00);
if (newPrimeRate > maxIncrease || newPrimeRate < maxDecrease) {
revert PrimeRateChangeExceedsLimit();
}
}
updateReserveInterests(reserve, rateData);
rateData.primeRate = newPrimeRate;
rateData.baseRate = rateData.primeRate.percentMul(25_00);
rateData.optimalRate = rateData.primeRate.percentMul(50_00);
// maxRate set separately by protocol
updateInterestRatesAndLiquidity(reserve, rateData, 0, 0);
emit PrimeRateUpdated(oldPrimeRate, newPrimeRate);
}
Borrow Rate Relationship
The protocol uses one-half of the US Prime Rate as the baseline for borrowing cost. Updating the Prime Rate directly adjusts the lending pool’s interest curve parameters.
Change Limits (±5%)
For security, any single update cannot change the Prime Rate by more than 5% (up or down). Larger moves must occur over multiple intervals.
Operational Notes¶
- Scheduler: Off-chain job runs every 4 hours. It aggregates 2+ sources and only submits on-chain if the value changes
- Owner-gated:
sendRequest
is restricted to the owner/operator account - Observability: Track
PrimeRateRequestSent
andPrimeRateUpdated
for monitoring
Related Components¶
BaseChainlinkFunctionsOracle
– shared request/fulfillment frameworkLendingPool
– receives prime rate updates viasetPrimeRate
ReserveLibrary
– enforces update bounds and recalculates rates