### Setup and Build Subgraph Dependencies Source: https://github.com/aave/protocol-subgraphs/blob/main/README.md Installs dependencies, regenerates types, and builds the subgraph for testing. Adjust the .env file with your access token and subgraph name. ```bash # copy env and adjust its content with your personal access token and subgraph name # you can get an access token from https://thegraph.com/explorer/dashboard cp .env.test .env # install project dependencies npm i # to regenrate types if schema.graphql has changed npm run subgraph:codegen # to run a test build of your subgraph npm run subgraph:build # now you're able to deploy to thegraph hosted service with one of the deploy commands: npm run deploy:hosted:mainnet ``` -------------------------------- ### Navigate by Task: Understanding Precision Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Guides users to relevant documentation sections for understanding precision, linking utility constants, converters, and common patterns. ```markdown **I need to understand precision:** → `04-utils-constants.ts` + `02-utils-converters.ts` + `11-common-patterns.md` (Precision Handling) ``` -------------------------------- ### Conceptual Guide Documentation Template Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Template for documenting conceptual guides within the Aave Protocol Subgraphs. Includes sections for overview, key concepts, common patterns, examples, and related modules. ```markdown # Topic Name ## Overview ## Key Concepts ... ## Common Patterns ... ## Examples ... ## Related Modules ... ``` -------------------------------- ### Example Function Implementation Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Illustrates the structure of an actual implementation for a TypeScript function. This serves as a template for defining functions within the project. ```typescript // Shows actual implementation export function exampleFunction(param: Type): ReturnType ``` -------------------------------- ### Navigate by Task: Understanding Deposits Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Guides users to relevant documentation sections for understanding deposit functionality, linking mapping, helper, and utility modules. ```markdown **I want to understand how deposits work:** → `09-mapping-lending-pool.ts` > handleDeposit + `06-helpers-initializers.ts` + `02-utils-converters.ts` ``` -------------------------------- ### Navigate by Task: Working with Interest Rates Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Guides users to relevant documentation sections for working with interest rates, linking helper modules and common patterns. ```markdown **I need to work with interest rates:** → `05-helpers-math.ts` + `07-helpers-reserve-logic.ts` + `11-common-patterns.md` (Interest Accrual) ``` -------------------------------- ### WAD Precision Handling Example Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Shows how to represent WAD (10^18) values, typically used for token amounts and balances. Requires BigInt.fromString. ```typescript let wadAmount = BigInt.fromString('1000000000000000000'); // 1 WAD ``` -------------------------------- ### Get or Initialize Protocol Entity Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves the singleton Protocol entity or creates it if it doesn't exist. This is used for global protocol configuration. ```typescript import { getProtocol } from './helpers/initializers'; let protocol = getProtocol(); // Returns Protocol entity with ID "1" ``` -------------------------------- ### Deposit Event ID Generation Example Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/03-utils-id-generation.md Example of how deposit event IDs are generated within a mapping handler. Reserve and UserReserve IDs are auto-generated, while the history ID is explicitly deterministic. ```typescript export function handleDeposit(event: Deposit): void { let reserve = getOrInitReserve(event.params.reserve, event); let userReserve = getOrInitUserReserve(user, reserve, event); // Reserve ID is auto-generated via getReserveId() // UserReserve ID is auto-generated via getUserReserveId() let deposit = new DepositAction(getHistoryEntityId(event)); // History ID is explicit and deterministic } ``` -------------------------------- ### RAY Precision Handling Example Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Demonstrates how to represent and convert RAY (10^27) values, commonly used for interest rates and indices. Ensure BigInt and BigDecimal are imported. ```typescript let rayValue = BigInt.fromString('1000000000000000000000000000'); // 1 RAY let percentage = rayValue.divDecimal(BigDecimal.fromString('10000000000000000000000000000')); // 1% ``` -------------------------------- ### 8-Decimal Precision Handling Example Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Illustrates handling 8-decimal precision values, often used for Chainlink price feeds. Requires BigInt.fromString and a USD_PRECISION constant. ```typescript let chainlinkPrice = BigInt.fromString('200000000000'); // $2000/ETH let usdPrice = chainlinkPrice.divDecimal(USD_PRECISION); // BigDecimal 2000 ``` -------------------------------- ### Navigate by Task: Debugging an Entity Issue Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Guides users to relevant documentation sections for debugging entity issues, linking utility modules, helper modules, and common patterns. ```markdown **I'm debugging an entity issue:** → `03-utils-id-generation.ts` + `06-helpers-initializers.ts` + `11-common-patterns.md` (Debugging Tips) ``` -------------------------------- ### Navigate by Task: Adding a New Event Handler Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Guides users to relevant documentation sections for adding a new event handler, linking common patterns, mapping modules, and GraphQL entity documentation. ```markdown **I want to add a new event handler:** → `11-common-patterns.md` (Event Handler Pattern) + `09-mapping-lending-pool.ts` (example) + `10-graphql-entities.md` ``` -------------------------------- ### User Reserve ID Composition Example Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/03-utils-id-generation.md Shows how a User Reserve entity ID is constructed by combining the user's address, the asset's address, and the pool ID. ```plaintext [userAddress][assetAddress][poolId] Example: "0x1234...1234" + "0xdac1...ec7" + "0xpool1" └─ User └─ Token └─ Pool ``` -------------------------------- ### Full Reserve Calculation Example Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/07-helpers-reserve-logic.md This snippet demonstrates how to use helper functions to calculate the current state of a reserve, including liquidity index, debt index, and utilization rate. It is essential for any calculation requiring current balances or reserve health metrics. ```typescript import { Reserve } from '../../generated/schema'; import { getReserveNormalizedIncome, getReserveNormalizedVariableDebt, calculateUtilizationRate } from './helpers/reserve-logic'; function analyzeReserve(reserveId: string, event: ethereum.Event): void { let reserve = Reserve.load(reserveId); // Calculate current state let income = getReserveNormalizedIncome(reserve, event); let debtIndex = getReserveNormalizedVariableDebt(reserve, event); let utilization = calculateUtilizationRate(reserve); // Use calculated values console.log(`Reserve ${reserveId}:`); console.log(` Liquidity Index: ${income}`); console.log(` Debt Index: ${debtIndex}`); console.log(` Utilization: ${utilization.times(BigDecimal.fromString('100'))}%`); } ``` -------------------------------- ### Calculate Growth for aToken Balance Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/05-helpers-math.md Used for supply positions that grow with accrued interest. Ensure 'scaledBalance', 'supplyRate', 'start', and 'now' are properly scaled. ```typescript newBalance = calculateGrowth(scaledBalance, supplyRate, start, now) ``` -------------------------------- ### Entity Lookup and Creation Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/09-mapping-lending-pool.md Helper functions to get or initialize reserve, user reserve, and user entities. Used when dealing with new or existing entities in the subgraph. ```typescript let poolReserve = getOrInitReserve(event.params.reserve, event); let userReserve = getOrInitUserReserve(user, reserve, event); let user = getOrInitUser(userAddress); ``` -------------------------------- ### Reserve ID Composition Example Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/03-utils-id-generation.md Illustrates the composition of a Reserve entity ID, which is formed by concatenating the underlying asset address and the pool ID. ```plaintext [underlyingAssetAddress][poolId] Example: "0xdac17f958d2ee523a2206206994597c13d831ec70xpool1" └─ USDT address └─ pool ID ``` -------------------------------- ### Reverse References with @derivedFrom Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md This GraphQL schema example demonstrates how to define reverse references using the '@derivedFrom' directive. It automatically manages the relationship between 'Reserve' and 'Pool' entities. ```graphql type Reserve { pool: Pool! # ... } type Pool { reserves: [Reserve!]! @derivedFrom(field: "pool") } ``` -------------------------------- ### Get or Initialize User Entity Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves an existing User entity or creates a new one with default values for borrowed reserves, unclaimed rewards, and incentive tracking. Use this to ensure a user entity is always available. ```typescript import { getOrInitUser } from './helpers/initializers'; import { Bytes } from '@graphprotocol/graph-ts'; let userAddr = Bytes.fromHexString('0x1234...'); let user = getOrInitUser(userAddr); // Returns User entity, creating it if needed ``` -------------------------------- ### convertTokenAmountToDecimals Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Converts a token amount from its raw form (in the smallest unit) to its human-readable form by dividing by 10^decimals. For example, 1000000000000000000 USDC (18 decimals) becomes 1. ```APIDOC ## convertTokenAmountToDecimals ### Description Converts a token amount from its raw form (in the smallest unit) to its human-readable form by dividing by 10^decimals. For example, 1000000000000000000 USDC (18 decimals) becomes 1. ### Parameters #### Path Parameters - **amount** (BigInt) - Required - Token amount in smallest unit - **decimals** (i32) - Required - Token decimal places ### Returns `BigDecimal` - The amount scaled to the correct decimal representation. ### Example ```typescript import { convertTokenAmountToDecimals } from './utils/converters'; let rawAmount = BigInt.fromString('1000000000000000000'); // 1 ETH in wei let humanAmount = convertTokenAmountToDecimals(rawAmount, 18); // Result: BigDecimal with value 1 ``` ``` -------------------------------- ### History Entity ID Composition Example Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/03-utils-id-generation.md Details the format for history entity IDs, which includes block number, transaction index, transaction hash, log index, and transaction log index. ```plaintext [blockNumber]:[transactionIndex]:[transactionHash]:[logIndex]:[transactionLogIndex] Example: "12345:0:0xabcd...ef01:1:1" └─ Block └─ TxIdx └─ Hash └─ LogIdx ``` -------------------------------- ### Lazy Loading with Defaults Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md This TypeScript function implements the 'get or init' pattern to lazily load or initialize an entity with default values. It ensures entities are always created with a valid state upon first access. ```typescript export function getOrInitX(id: string): X { let entity = X.load(id); if (!entity) { entity = new X(id); // Initialize all fields with safe defaults entity.field1 = zeroBI(); entity.field2 = ""; entity.save(); } return entity as X; } ``` -------------------------------- ### Navigate by Source File: Initializers Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source file `src/helpers/initializers.ts` to its corresponding documentation `06-helpers-initializers.ts`. ```markdown | Source | Documentation | |--------|---------------| | `src/helpers/initializers.ts` | `06-helpers-initializers.ts` | ``` -------------------------------- ### Get Zero Address Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Returns the Ethereum zero address as a Bytes type. Used for uninitialized or null address fields. ```typescript export function zeroAddress(): Bytes { return Bytes.fromHexString('0x0000000000000000000000000000000000000000'); } ``` ```typescript import { zeroAddress } from './utils/converters'; let nullAddr = zeroAddress(); reserve.aToken = nullAddr; // Initialize to zero address ``` -------------------------------- ### Navigate by Source File: Reserve Logic Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source file `src/helpers/reserve-logic.ts` to its corresponding documentation `07-helpers-reserve-logic.ts`. ```markdown | Source | Documentation | |--------|---------------| | `src/helpers/reserve-logic.ts` | `07-helpers-reserve-logic.ts` | ``` -------------------------------- ### exponentToBigDecimal Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Converts a decimal exponent to a BigDecimal. For example, with input 18, returns 1000000000000000000 (10^18). Used to scale token amounts. ```APIDOC ## exponentToBigDecimal ### Description Converts a decimal exponent to a BigDecimal. For example, with input 18, returns 1000000000000000000 (10^18). Used to scale token amounts. ### Parameters #### Path Parameters - **decimals** (i32) - Required - Number of decimal places (exponent of 10) ### Returns `BigDecimal` - A BigDecimal value representing 10^decimals. ### Example ```typescript import { exponentToBigDecimal } from './utils/converters'; let ethMultiplier = exponentToBigDecimal(18); let priceInWei = BigInt.fromI32(100); let priceInEth = priceInWei.toBigDecimal().div(ethMultiplier); ``` ``` -------------------------------- ### Prepare and Deploy Subgraph to Mainnet Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/01-project-overview.md Prepares the subgraph for deployment by setting environment variables for version, blockchain, and network, then initiates the deployment to the mainnet. ```bash VERSION=v3 BLOCKCHAIN=v3 NETWORK=mainnet npm run prepare:subgraph npm run deploy:hosted:mainnet-v3 ``` -------------------------------- ### Navigate by Source File: GraphQL Entities Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source files `schemas/*.graphql` to their corresponding documentation `10-graphql-entities.md`. ```markdown | Source | Documentation | |--------|---------------| | `schemas/*.graphql` | `10-graphql-entities.md` | ``` -------------------------------- ### Navigate by Source File: Cross-module Patterns Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps cross-module patterns to their corresponding documentation `11-common-patterns.md`. ```markdown | Source | Documentation | |--------|---------------| | Cross-module | `11-common-patterns.md` | ``` -------------------------------- ### Get Zero BigInt Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Factory function that returns a zero BigInt for initializing integer values. Convenience wrapper around BigInt.fromI32(0). ```typescript export function zeroBI(): BigInt { return BigInt.fromI32(0); } ``` ```typescript import { zeroBI } from './utils/converters'; let zeroBalance = zeroBI(); let count = zeroBalance; // BigInt with value 0 ``` -------------------------------- ### Navigate by Source File: Math Helpers Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source file `src/helpers/math.ts` to its corresponding documentation `05-helpers-math.ts`. ```markdown | Source | Documentation | |--------|---------------| | `src/helpers/math.ts` | `05-helpers-math.ts` | ``` -------------------------------- ### Get Zero BigDecimal Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Factory function that returns a zero BigDecimal for initializing decimal values. Convenience wrapper around BigDecimal.fromString('0'). ```typescript export function zeroBD(): BigDecimal { return BigDecimal.fromString('0'); } ``` ```typescript import { zeroBD } from './utils/converters'; let zeroAmount = zeroBD(); let balance = zeroAmount; // BigDecimal with value 0 ``` -------------------------------- ### Navigate by Source File: Lending Pool Mapping Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source file `src/mapping/lending-pool/*.ts` to its corresponding documentation `09-mapping-lending-pool.ts`. ```markdown | Source | Documentation | |--------|---------------| | `src/mapping/lending-pool/*.ts` | `09-mapping-lending-pool.ts` | ``` -------------------------------- ### Convert Exponent to BigDecimal Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Converts a decimal exponent to a BigDecimal. For example, with input 18, returns 1000000000000000000 (10^18). Used to scale token amounts. ```typescript export function exponentToBigDecimal(decimals: i32): BigDecimal { return BigDecimal.fromString('10').pow(decimals as u8); } ``` ```typescript import { exponentToBigDecimal } from './utils/converters'; let ethMultiplier = exponentToBigDecimal(18); let priceInWei = BigInt.fromI32(100); let priceInEth = priceInWei.toBigDecimal().div(ethMultiplier); ``` -------------------------------- ### Navigate by Source File: Price Updates Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source file `src/helpers/price-updates.ts` to its corresponding documentation `08-helpers-price-updates.ts`. ```markdown | Source | Documentation | |--------|---------------| | `src/helpers/price-updates.ts` | `08-helpers-price-updates.ts` | ``` -------------------------------- ### Navigate by Source File: Converters Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source file `src/utils/converters.ts` to its corresponding documentation `02-utils-converters.ts`. ```markdown | Source | Documentation | |--------|---------------| | `src/utils/converters.ts` | `02-utils-converters.ts` | ``` -------------------------------- ### Navigate by Source File: Constants Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source file `src/utils/constants.ts` to its corresponding documentation `04-utils-constants.ts`. ```markdown | Source | Documentation | |--------|---------------| | `src/utils/constants.ts` | `04-utils-constants.ts` | ``` -------------------------------- ### Calculate Linear Interest for Stable Debt Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/05-helpers-math.md Used for fixed-rate borrows that accrue interest linearly. Ensure 'rate', 'start', and 'now' are properly scaled. ```typescript newBalance = principalDebt * calculateLinearInterest(rate, start, now) ``` -------------------------------- ### Initialize Reserve Entity Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/04-utils-constants.md Initializes a new Reserve entity, setting default addresses to ZERO_ADDRESS and marking if the asset is the native ETH using MOCK_ETHEREUM_ADDRESS. Requires importing ZERO_ADDRESS and MOCK_ETHEREUM_ADDRESS from './utils/constants'. ```typescript import { ZERO_ADDRESS, MOCK_ETHEREUM_ADDRESS } from './utils/constants'; import { Reserve } from '../../generated/schema'; function initReserve(assetAddress: string): Reserve { let reserve = new Reserve(assetAddress); // Initialize addresses to zero reserve.aToken = ZERO_ADDRESS; reserve.vToken = ZERO_ADDRESS; reserve.sToken = ZERO_ADDRESS; // Mark if this is ETH if (assetAddress === MOCK_ETHEREUM_ADDRESS) { reserve.isNativeAsset = true; } return reserve; } ``` -------------------------------- ### Navigate by Source File: ID Generation Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Maps the source file `src/utils/id-generation.ts` to its corresponding documentation `03-utils-id-generation.ts`. ```markdown | Source | Documentation | |--------|---------------| | `src/utils/id-generation.ts` | `03-utils-id-generation.ts` | ``` -------------------------------- ### Convert BigInt from RAY to BigDecimal Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Converts a BigInt value scaled in RAY units (10^27) to a BigDecimal. Use this to get human-readable values from Aave protocol data. ```typescript import { convertValueFromRay } from './utils/converters'; let rayValue = BigInt.fromString('10000000000000000000000000000'); // 10 RAY let decimalValue = convertValueFromRay(rayValue); // Result: BigDecimal with value 10 ``` -------------------------------- ### Calculate Compound Interest for Variable Debt Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/05-helpers-math.md Used for variable-rate borrows that accrue interest based on compound interest. Ensure 'rate', 'start', and 'now' are properly scaled. ```typescript newBalance = scaledDebt * calculateCompoundedInterest(rate, start, now) ``` -------------------------------- ### Build Subgraph: Generate Schema Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/01-project-overview.md Generates the GraphQL schema from a template. This is the first step in the subgraph build process. ```bash # 1. Generate schema from template npm run generate:schema ``` -------------------------------- ### Proposal Status Initializing Constant Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/04-utils-constants.md String constant for the initial status of governance proposals before voting begins. ```typescript export const PROPOSAL_STATUS_INITIALIZING = 'Initializing'; ``` -------------------------------- ### Initialize User and Reserve Entities in Event Handler Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md This snippet demonstrates the common pattern of using helper functions like getOrInitUser, getOrInitReserve, and getOrInitUserReserveWithIds to initialize entities before updating their state. It ensures that all necessary entities are created or retrieved before modifications are made and persisted. ```typescript export function handleUserAction(event: UserEvent): void { // Get or create entities let user = getOrInitUser(event.params.user); let reserve = getOrInitReserve(event.params.asset, event); let userReserve = getOrInitUserReserveWithIds( event.params.user, event.params.asset, getPoolByContract(event) ); // Update state userReserve.currentBalance = userReserve.currentBalance.plus(event.params.amount); userReserve.lastUpdateTimestamp = event.block.timestamp.toI32(); // Persist userReserve.save(); } ``` -------------------------------- ### Get or Initialize ENS Entity Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves or creates a ChainlinkENS entity for tracking ENS-to-address mappings. Initializes with zero address and empty string for aggregator, underlying address, and symbol. ```typescript import { getOrInitENS } from './helpers/initializers'; import { namehash } from './utils/converters'; let nodeHash = namehash(["eth", "aave"]); let ens = getOrInitENS(nodeHash); // Returns ChainlinkENS entity for aave.eth ``` -------------------------------- ### Get Pool ID by Contract Address Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Looks up the pool ID associated with a given smart contract address using the ContractToPoolMapping. This is essential for routing events to the correct pool. ```typescript import { getPoolByContract } from './helpers/initializers'; import { Deposit } from '../../generated/templates/LendingPool/LendingPool'; export function handleDeposit(event: Deposit): void { let poolId = getPoolByContract(event); // Returns something like "0x1" (Aave V2) or "1" (Aave V3) } ``` -------------------------------- ### Calculate Asset Price in USD Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/08-helpers-price-updates.md Demonstrates how to convert an asset's price from its native denomination (e.g., ETH) to USD using the current ETH/USD price. ```typescript let asset = PriceOracleAsset.load(tokenAddress); let oracle = PriceOracle.load('1'); // Asset price in ETH let priceInEth = asset.priceInEth.toBigDecimal() .div(ETH_PRECISION); // ETH price in USD (from Chainlink, 8 decimals) let ethPriceUsd = oracle.usdPriceEth.toBigDecimal() .div(USD_PRECISION); // Asset price in USD let assetPriceUsd = priceInEth.times(ethPriceUsd); ``` -------------------------------- ### Price Update Flow Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Outlines the sequence of events for updating asset prices in the Aave protocol subgraphs, starting from a price change event and ending with saving all related entities. ```text Price Change Event ↓ Identify asset (token address) ↓ Get or create PriceOracleAsset ↓ Query oracle contract (oracle.getAssetPrice(asset)) ↓ Update priceInEth field ↓ Create PriceHistoryItem (record at this block) ↓ Update dependent assets (composite assets that depend on this) ↓ Save all entities ``` -------------------------------- ### Convert Token Amount to Decimals Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Converts a token amount from its raw form (in the smallest unit) to its human-readable form by dividing by 10^decimals. For example, 1000000000000000000 USDC (18 decimals) becomes 1. ```typescript export function convertTokenAmountToDecimals(amount: BigInt, decimals: i32): BigDecimal { return amount.toBigDecimal().div(exponentToBigDecimal(decimals)); } ``` ```typescript import { convertTokenAmountToDecimals } from './utils/converters'; let rawAmount = BigInt.fromString('1000000000000000000'); // 1 ETH in wei let humanAmount = convertTokenAmountToDecimals(rawAmount, 18); // Result: BigDecimal with value 1 ``` -------------------------------- ### Calculating User's Current aToken Balance Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/00-index.md Explains how to calculate a user's current aToken balance when the field is not directly stored. It involves loading stored values and using reserve logic to compute the actual balance based on liquidity index and interest calculations. ```typescript Query: user.currentATokenBalance ↓ Field not directly stored, must calculate: ├─ Load userReserve.scaledATokenBalance (stored value) ├─ Load reserve.liquidityIndex (stored index) ├─ getReserveNormalizedIncome() → reserve-logic.ts │ ├─ calculateLinearInterest() → math.ts │ └─ rayMul() → math.ts (multiply current index) ├─ actualBalance = scaledBalance * currentIndex / 10^27 └─ Return to user ``` -------------------------------- ### Standard Event Handler Structure Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Illustrates the typical structure for processing blockchain events, including entity initialization, parameter extraction, history creation, state updates, and persistence. ```typescript import { EventName } from '../../generated/templates/ContractName/ContractName'; import { Entity } from '../../generated/schema'; import { getOrInitEntity, getPoolByContract } from '../../helpers/initializers'; import { getEntityId } from '../../utils/id-generation'; export function handleEventName(event: EventName): void { // 1. Get or create entities let entity = getOrInitEntity(id); let poolId = getPoolByContract(event); // 2. Extract event parameters let param1 = event.params.field1; let param2 = event.params.field2; // 3. Create transaction history entity let historyEntity = new HistoryEntity(getEntityId(event)); historyEntity.field1 = param1; historyEntity.field2 = param2; historyEntity.timestamp = event.block.timestamp.toI32(); historyEntity.txHash = event.transaction.hash; // 4. Update state entities entity.field1 = newValue; entity.lastUpdateTimestamp = event.block.timestamp.toI32(); // 5. Persist changes historyEntity.save(); entity.save(); } ``` -------------------------------- ### Paginated User Transactions Query (First 100) Source: https://github.com/aave/protocol-subgraphs/blob/main/README.md Fetch the first 100 user transactions using pagination parameters. This is the initial step in fetching a larger dataset. ```graphql { userTransactions(orderBy: timestamp, orderDirection: asc, first: 100, skip: 0){ timestamp } } ``` -------------------------------- ### Get or Initialize Price Oracle Asset Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves or creates a PriceOracleAsset entity for a given asset ID. The `save` parameter controls whether the entity is persisted if created. It initializes the entity with default price and source information. ```typescript export function getPriceOracleAsset(id: string, save: boolean = true): PriceOracleAsset ``` ```typescript import { getPriceOracleAsset } from './helpers/initializers'; let usdcAddr = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; let assetOracle = getPriceOracleAsset(usdcAddr); // Returns or creates USDC price oracle asset ``` -------------------------------- ### Initialize User Reserve with IDs Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves or creates a UserReserve entity for a specific user, asset, and pool. It initializes the entity with default balances and rates if it doesn't exist. ```typescript export function getOrInitUserReserveWithIds( userAddress: Bytes, underlyingAssetAddress: Bytes, pool: string ): UserReserve ``` ```typescript import { getOrInitUserReserveWithIds } from './helpers/initializers'; import { Bytes } from '@graphprotocol/graph-ts'; let userAddr = Bytes.fromHexString('0xabc...'); let usdc = Bytes.fromHexString('0xA0b86991...'); let userReserve = getOrInitUserReserveWithIds(userAddr, usdc, 'mainnet'); // Creates or retrieves user's USDC position in mainnet pool ``` -------------------------------- ### getProtocol Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves or creates the global Protocol entity. This singleton entity tracks global protocol configuration and is created with default values if it doesn't exist. ```APIDOC ## getProtocol ### Description Retrieves or creates the global Protocol entity. Since each Aave instance has exactly one protocol, this entity is a singleton that tracks global protocol configuration. The function uses load-or-create pattern: if the Protocol doesn't exist, it creates one and saves it immediately. ### Returns - `Protocol` - The singleton Protocol entity with ID "1". ### Example ```typescript import { getProtocol } from './helpers/initializers'; let protocol = getProtocol(); // Returns Protocol entity with ID "1" ``` ``` -------------------------------- ### Get Reserve Normalized Income Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/07-helpers-reserve-logic.md Calculates the current normalized income (liquidity index) for a reserve. Use this to determine the actual aToken balance by multiplying with scaled aToken balances. Returns stored value if already updated in the current block. ```typescript export function getReserveNormalizedIncome(reserve: Reserve, event: ethereum.Event): BigInt ``` ```typescript import { getReserveNormalizedIncome } from './helpers/reserve-logic'; import { Reserve } from '../../generated/schema'; let reserve = Reserve.load(reserveId); let currentIncome = getReserveNormalizedIncome(reserve, event); // Use to calculate actual aToken balance let scaledBalance = userReserve.scaledATokenBalance; let actualBalance = scaledBalance .toBigDecimal() .div(currentIncome.toBigDecimal()); ``` -------------------------------- ### Asset Price in USD Calculation Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Details the steps to calculate an asset's price in USD using its price in ETH and the ETH/USD exchange rate obtained from the oracle. ```text To get USD price of an asset: 1. Get asset's priceInEth (18 decimals) assetPriceInEth = asset.priceInEth / 10^18 2. Get ETH/USD rate from oracle ethPriceUsd = oracle.usdPriceEth / 10^8 3. Calculate asset price in USD assetPriceUsd = assetPriceInEth * ethPriceUsd ``` -------------------------------- ### Verify Data Types and Operations Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Demonstrates safe operations with BigInt, BigDecimal, and Bytes types. Ensure correct conversion methods are used for cross-type operations. ```typescript // BigInt operations let amount = BigInt.fromI32(1000); let multiplied = amount.times(BigInt.fromI32(2)); // Safe // BigDecimal operations let price = BigDecimal.fromString('1.5'); let usd = price.times(BigDecimal.fromString('2000')); // Safe // Bytes operations let addr = Bytes.fromHexString('0xabc...'); let str = addr.toHexString(); // Lowercase ``` -------------------------------- ### Generate History Entity ID Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/03-utils-id-generation.md Generates a unique ID for transaction history entities by combining block, transaction, and log indices. Ensures no two events get the same ID, even within the same transaction. Used for all user transaction types and is immutable. ```typescript export function getHistoryEntityId(event: ethereum.Event): string { // ... implementation details ... return `${event.block.number}:${event.transaction.index}:${event.transaction.hash.toHexString()}:${event.logIndex.toString()}:${event.transactionLogIndex.toString()}` } ``` ```typescript import { getHistoryEntityId } from './utils/id-generation'; import { Deposit } from '../../generated/templates/LendingPool/LendingPool'; export function handleDeposit(event: Deposit): void { let historyId = getHistoryEntityId(event); // historyId might be: "12345:0:0xabc123...:1:1" let deposit = new DepositAction(historyId); deposit.save(); } ``` -------------------------------- ### Get Protocol Update Block Number Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/02-utils-converters.md Returns the block height at which a specific protocol update (v3.0.1) was applied on a given network. This is crucial for correctly interpreting BalanceTransfer events after the update. Returns 0 for networks not explicitly listed or if the default interpretation should be used. ```typescript import { getUpdateBlock } from './utils/converters'; let polyUpdateBlock = getUpdateBlock("polygon"); // 42535602 let networkUpdateBlock = getUpdateBlock("mainnet"); // 0 (uses updated version by default) ``` -------------------------------- ### Initialize Price Oracle Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves or creates the global PriceOracle singleton entity. It initializes the entity with default configuration values if it does not exist. ```typescript export function getOrInitPriceOracle(): PriceOracle ``` ```typescript import { getOrInitPriceOracle } from './helpers/initializers'; let oracle = getOrInitPriceOracle(); // Returns global price oracle configuration ``` -------------------------------- ### Get Reserve Normalized Variable Debt Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/07-helpers-reserve-logic.md Calculates the current normalized variable debt (borrow index) for a reserve. Use this to determine the actual variable debt amount by multiplying with scaled variable debt balances. Returns stored value if already updated in the current block. ```typescript export function getReserveNormalizedVariableDebt(reserve: Reserve, event: ethereum.Event): BigInt ``` ```typescript import { getReserveNormalizedVariableDebt } from './helpers/reserve-logic'; import { Reserve } from '../../generated/schema'; let reserve = Reserve.load(reserveId); let currentDebtIndex = getReserveNormalizedVariableDebt(reserve, event); // Use to calculate actual variable debt balance let scaledDebt = userReserve.scaledVariableDebt; let actualDebt = scaledDebt .toBigDecimal() .div(currentDebtIndex.toBigDecimal()); ``` -------------------------------- ### Initialize Reserve Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves or creates a Reserve entity for a given underlying asset and event context. It initializes the reserve with default state, configuration flags, and links it to its PriceOracleAsset. ```typescript export function getOrInitReserve(underlyingAsset: Bytes, event: ethereum.Event): Reserve ``` ```typescript import { getOrInitReserve } from './helpers/initializers'; import { Bytes } from '@graphprotocol/graph-ts'; import { Deposit } from '../../generated/templates/LendingPool/LendingPool'; export function handleDeposit(event: Deposit): void { let reserve = getOrInitReserve(event.params.reserve, event); // Returns or creates the reserve for event.params.reserve } ``` -------------------------------- ### Local Subgraph Development Commands Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Commands for generating schema code, building the subgraph, and checking for TypeScript errors locally. The build process typically includes linting. ```bash # Generate schema and code npm run subgraph:codegen # Build subgraph npm run subgraph:build # Check for TypeScript errors # (no separate lint needed, build catches errors) ``` -------------------------------- ### Build Subgraph: Build Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/01-project-overview.md Builds the subgraph project, compiling the code and schema into a deployable artifact. This is the final step in the build process. ```bash # 3. Build the subgraph npm run subgraph:build ``` -------------------------------- ### Code Module Documentation Template Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/README.md Template for documenting code modules within the Aave Protocol Subgraphs. Includes sections for module description, exported functions, constants, types, and integration notes. ```markdown # Module: src/path/to/module [Brief description] ## Exported Functions ### functionName [Signature] [Parameters table] [Returns specification] [Description] [Source file reference] [Code example] ## Constants / Types ... ## Integration Notes ... ``` -------------------------------- ### Handle Borrow Event Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/09-mapping-lending-pool.md Processes borrow events to create a Borrow transaction entity and update user/reserve debt state. Tracks whether the borrow is a stable or variable rate. ```typescript export function handleBorrow(event: Borrow): void ``` -------------------------------- ### Check Entity Load/Create Logic Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Implement logic to load an existing entity by its ID or create a new one if it does not exist. Log the creation of new entities for debugging. ```typescript let entity = Entity.load(id); if (!entity) { log.info('Creating new entity: {}', [id]); entity = new Entity(id); } ``` -------------------------------- ### Mock Ethereum Address Constant Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/04-utils-constants.md Placeholder address for ETH in token lists, used for uniform handling in oracle and price feed configurations. ```typescript export const MOCK_ETHEREUM_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; ``` -------------------------------- ### Mock USD Address Constant Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/04-utils-constants.md Mock address representing USD, used as a placeholder for USD/stablecoin pairings in price oracle configurations. ```typescript export const MOCK_USD_ADDRESS = '0x10f7fc1f91ba351f9c629c5947ad69bd03c05b96'; ``` -------------------------------- ### Handle Swap Interest Rate Mode Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/09-mapping-lending-pool.md Processes interest rate mode swaps where users change between stable and variable borrowing rates. Creates transaction history and updates user reserve data. ```typescript export function handleSwap(event: Swap): void ``` -------------------------------- ### Build Subgraph: Codegen Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/01-project-overview.md Runs the GraphQL codegen tool to generate types and artifacts based on the schema. This is the second step in the build process. ```bash # 2. Run GraphQL codegen npm run subgraph:codegen ``` -------------------------------- ### Query User Position Details Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/11-common-patterns.md Retrieve a user's specific reserve positions, including balances, debt, and collateralization status. This query helps in understanding a user's active engagements with different reserves. ```graphql { userReserves(where: {user: "0x..."}) { reserve { symbol } scaledATokenBalance scaledVariableDebt principalStableDebt usageAsCollateralEnabledOnUser lastUpdateTimestamp } } ``` -------------------------------- ### getOrInitUser Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/06-helpers-initializers.md Retrieves an existing User entity or creates a new one with default initialized fields if it doesn't exist. Default initial values include borrowed reserves count, unclaimed rewards, incentives last updated, and lifetime rewards set to 0. ```APIDOC ## getOrInitUser ### Description Retrieves an existing User entity or creates a new one with default initialized fields if it doesn't exist. Initial values: - `borrowedReservesCount`: 0 - `unclaimedRewards`: 0 - `incentivesLastUpdated`: 0 - `lifetimeRewards`: 0 ### Parameters #### Path Parameters - **address** (Bytes) - Required - User's wallet address ### Returns - `User` - The User entity, created with defaults if it doesn't exist. ### Example ```typescript import { getOrInitUser } from './helpers/initializers'; import { Bytes } from '@graphprotocol/graph-ts'; let userAddr = Bytes.fromHexString('0x1234...'); let user = getOrInitUser(userAddr); // Returns User entity, creating it if needed ``` ``` -------------------------------- ### Handle Reserve Used As Collateral Enabled Source: https://github.com/aave/protocol-subgraphs/blob/main/_autodocs/09-mapping-lending-pool.md Processes events when users enable an asset as collateral. Creates transaction history and updates collateral status. ```typescript export function handleReserveUsedAsCollateralEnabled(event: ReserveUsedAsCollateralEnabled): void ```