{"id":18705038,"url":"https://github.com/aave/aave-utilities","last_synced_at":"2025-04-04T19:13:03.156Z","repository":{"id":36963760,"uuid":"397270611","full_name":"aave/aave-utilities","owner":"aave","description":null,"archived":false,"fork":false,"pushed_at":"2024-05-22T14:24:28.000Z","size":2251,"stargazers_count":96,"open_issues_count":46,"forks_count":71,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-05-22T15:44:06.595Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aave.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-17T13:37:08.000Z","updated_at":"2024-05-29T13:31:31.291Z","dependencies_parsed_at":"2024-01-02T19:36:51.842Z","dependency_job_id":"4959b34b-3ad5-4a2c-9ce3-48966a7cdf6a","html_url":"https://github.com/aave/aave-utilities","commit_stats":{"total_commits":342,"total_committers":20,"mean_commits":17.1,"dds":0.6023391812865497,"last_synced_commit":"f97fc4fa55639d3310c8f2d34351b29859372fb7"},"previous_names":[],"tags_count":347,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aave%2Faave-utilities","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aave%2Faave-utilities/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aave%2Faave-utilities/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aave%2Faave-utilities/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aave","download_url":"https://codeload.github.com/aave/aave-utilities/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247234923,"owners_count":20905854,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T12:09:31.760Z","updated_at":"2025-04-04T19:13:03.133Z","avatar_url":"https://github.com/aave.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e \u003ca href=\"https://aave.com/\" rel=\"noopener\" target=\"_blank\"\u003e\u003cimg width=\"300\" src=\"https://aave.com/governanceGhosts.svg\" alt=\"Aave logo\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eAave Utilities\u003c/h1\u003e\n\nThe Aave Protocol is a decentralized non-custodial liquidity protocol where\nusers can participate as suppliers or borrowers.\n\nAave Utilities is a JavaScript SDK extending\n[ethers.js](https://docs.ethers.org/v5/) for interacting with V2 and V3 of the\nAave Protocol, an upgrade to the existing\n[aave-js](https://github.com/aave/aave-js) library.\n\n\u003cbr /\u003e\n\n## Installation\n\nAave utilities are available as npm packages:\n\nThe [`@aave/math-utils`](https://www.npmjs.com/package/@aave/math-utils) package\ncontains methods for formatting raw contract data for usage on a frontend\n\nThe\n[`@aave/contract-helpers`](https://www.npmjs.com/package/@aave/contract-helpers)\npackage contains methods for generating transactions based on method and\nparameter inputs. Can be used to read and write data on the protocol contracts.\n\n```sh\n// with npm\nnpm install @aave/contract-helpers @aave/math-utils\n\n// with yarn\nyarn add @aave/contract-helpers @aave/math-utils\n```\n\n\u003cbr /\u003e\n\n### Compatibility\n\nThis library has a peer dependency of [ethers v5](https://docs.ethers.org/v5/),\nand will not work with v6.\n\nTo install the correct version, run:\n\n```sh\nnpm install ethers@5\n```\n\n\u003cbr /\u003e\n\n## Features\n\n1.  [Data Methods](#data-methods)\n    - a. [Setup](#data-methods-setup)\n    - b. [Markets Data](#markets-data)\n    - b. [User Data](#user-data)\n2.  [Transaction Methods](#transaction-methods)\n    - a. [Setup](#transactions-setup)\n    - b. [Submitting Transactions](#submitting-transactions)\n    - c. [Pool V3](#pool-v3)\n      - [supplyBundle](#supplyBundle)\n      - [supply](#supply)\n      - [signERC20Approval](#signERC20Approval)\n      - [supplyWithPermit](#supply-with-permit)\n      - [borrow](\u003c#borrow-(v3)\u003e)\n      - [repay](\u003c#repay-(v3)\u003e)\n      - [repayWithPermit](#repayWithPermit)\n      - [repayWithATokens](#repayWithATokens)\n      - [withdraw](\u003c#withdraw-(v3)\u003e)\n      - [swapBorrowRateMode](\u003c#swapBorrowRateMode-(v3)\u003e)\n      - [setUsageAsCollateral](\u003c#setUsageAsCollateral-(v3)\u003e)\n      - [liquidationCall](\u003c#liquidationCall-(v3)\u003e)\n      - [swapCollateral](\u003c#swapCollateral-(v3)\u003e)\n      - [repayWithCollateral](\u003c#repayWithCollateral-(v3)\u003e)\n      - [setUserEMode](#setUserEMode)\n    - d. [Lending Pool V2](#lending-pool-v2)\n      - [depositBundle](#depositBundle)\n      - [deposit](#deposit)\n      - [borrow](#borrow)\n      - [repay](#repay)\n      - [withdraw](#withdraw)\n      - [swapBorrowRateMode](#swapBorrowRateMode)\n      - [setUsageAsCollateral](#setUsageAsCollateral)\n      - [liquidationCall](#liquidationCall)\n      - [swapCollateral](#swapCollateral)\n      - [repayWithCollateral](#repayWithCollateral)\n    - e. [Staking](#staking)\n      - [stake](#stake)\n      - [redeem](#redeem)\n      - [cooldown](#cooldown)\n      - [claimRewards](#claimRewards)\n    - f. [Governance](#governance)\n      - [create](#create)\n      - [cancel](#cancel)\n      - [queue](#queue)\n      - [execute](#execute)\n      - [submitVote](#submitVote)\n      - [delegate](#delegate)\n      - [delegateByType](#delegateByType)\n    - g. [Credit Delegation](#credit-delegation)\n      - [approveDelegation](#approveDelegation)\n    - h. [New Transaction Methods (experimental)](#new-transaction-methods)\n      - [supplyTxBuilder](#supplyTxBuilder)\n      - [depositTxBuilder](#depositTxBuilder)\n    - i. [Disclaimer]\n\n\u003cbr /\u003e\n\n# Data Methods\n\nThe `@aave/contract-helpers` and `@aave/math-utils` packages are utilities to\nfetch and format smart contract data respectively. This section will guide you\nto setup and use these packages to query Aave Protocol data.\n\n\u003cbr /\u003e\n\n## Data Methods Setup\n\nAfter installing the aave-utilities packages, it's also recommended to add the\n[Aave Address Book](https://github.com/bgd-labs/aave-address-book#usage-with-node)\npackage which will be used in the examples to import contract addresses\ndirectly.\n\nTo initialize an instance of an `@aave/contract-helpers` service, an `ethers`\nprovider is required to pass into the constructor.\n[ethers.js](https://docs.ethers.io/v5/) is a library for interacting with\nEthereum and other EVM compatible blockchains, our `ethers` provider instance\nwill serve as an RPC connection to read data from the blockchain.\n\nThe two services which will be used for all data fetching methods are:\n\n- `UiPoolDataProvider`: Used for querying reserve and user data\n- `UiIncentiveDataProvider`: Used for querying reward emissions and user\n  claimable rewards\n\nThe sample code below shows a complete example of initializing and using these\nservices to query Aave protocol data.\n\n\u003cdetails\u003e\n\t\u003csummary\u003eSample Code\u003c/summary\u003e\n\n```js\nimport { ethers } from 'ethers';\nimport {\n  UiPoolDataProvider,\n  UiIncentiveDataProvider,\n  ChainId,\n} from '@aave/contract-helpers';\nimport * as markets from '@bgd-labs/aave-address-book';\n\n// ES5 Alternative imports\n//  const {\n//    ChainId,\n//    UiIncentiveDataProvider,\n//    UiPoolDataProvider,\n//  } = require('@aave/contract-helpers');\n//  const markets = require('@bgd-labs/aave-address-book');\n//  const ethers = require('ethers');\n\n// Sample RPC address for querying ETH mainnet\nconst provider = new ethers.providers.JsonRpcProvider(\n  'https://eth-mainnet.public.blastapi.io',\n);\n\n// User address to fetch data for, insert address here\nconst currentAccount = '0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c';\n\n// View contract used to fetch all reserves data (including market base currency data), and user reserves\n// Using Aave V3 Eth Mainnet address for demo\nconst poolDataProviderContract = new UiPoolDataProvider({\n  uiPoolDataProviderAddress: markets.AaveV3Ethereum.UI_POOL_DATA_PROVIDER,\n  provider,\n  chainId: ChainId.mainnet,\n});\n\n// View contract used to fetch all reserve incentives (APRs), and user incentives\n// Using Aave V3 Eth Mainnet address for demo\nconst incentiveDataProviderContract = new UiIncentiveDataProvider({\n  uiIncentiveDataProviderAddress:\n    markets.AaveV3Ethereum.UI_INCENTIVE_DATA_PROVIDER,\n  provider,\n  chainId: ChainId.mainnet,\n});\n\nasync function fetchContractData() {\n  // Object containing array of pool reserves and market base currency data\n  // { reservesArray, baseCurrencyData }\n  const reserves = await poolDataProviderContract.getReservesHumanized({\n    lendingPoolAddressProvider: markets.AaveV3Ethereum.POOL_ADDRESSES_PROVIDER,\n  });\n\n  // Object containing array or users aave positions and active eMode category\n  // { userReserves, userEmodeCategoryId }\n  const userReserves = await poolDataProviderContract.getUserReservesHumanized({\n    lendingPoolAddressProvider: markets.AaveV3Ethereum.POOL_ADDRESSES_PROVIDER,\n    user: currentAccount,\n  });\n\n  // Array of incentive tokens with price feed and emission APR\n  const reserveIncentives =\n    await incentiveDataProviderContract.getReservesIncentivesDataHumanized({\n      lendingPoolAddressProvider:\n        markets.AaveV3Ethereum.POOL_ADDRESSES_PROVIDER,\n    });\n\n  // Dictionary of claimable user incentives\n  const userIncentives =\n    await incentiveDataProviderContract.getUserReservesIncentivesDataHumanized({\n      lendingPoolAddressProvider:\n        markets.AaveV3Ethereum.POOL_ADDRESSES_PROVIDER,\n      user: currentAccount,\n    });\n\n  console.log({ reserves, userReserves, reserveIncentives, userIncentives });\n}\n\nfetchContractData();\n```\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n## Markets Data\n\nOnce you have successfully completed the Setup instructions and are querying\non-chain data, the next step is to format this data into human readable format\nand compute helpful values. This is done using the formatter functions in the\n`@aave/math-utils` package. There are two formatters for market data, one with\nincentives data, and one without. Examples for both methods are shown below.\n\nThe output of these methods is an array of formatted reserve data for each\nreserve in an Aave market.\n\n\u003cbr /\u003e\n\n### formatReserves\n\nformatReserves returns an array of formatted configuration and live usage data\nfor each reserve in an Aave market\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```js\nimport { formatReserves } from '@aave/math-utils';\nimport dayjs from 'dayjs';\n\n// `reserves` variable here is input from Setup section\n\nconst reservesArray = reserves.reservesData;\nconst baseCurrencyData = reserves.baseCurrencyData;\n\nconst currentTimestamp = dayjs().unix();\n\n/*\n- @param `reserves` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.reservesArray`\n- @param `currentTimestamp` Current UNIX timestamp in seconds\n- @param `marketReferencePriceInUsd` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.baseCurrencyData.marketReferencePriceInUsd`\n- @param `marketReferenceCurrencyDecimals` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.baseCurrencyData.marketReferenceCurrencyDecimals`\n*/\nconst formattedPoolReserves = formatReserves({\n  reserves: reservesArray,\n  currentTimestamp,\n  marketReferenceCurrencyDecimals:\n    baseCurrencyData.marketReferenceCurrencyDecimals,\n  marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,\n});\n```\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### formatReservesAndIncentives\n\nformatReservesAndIncentives returns an array of formatted configuration and live\nusage data plus an object with supply, variable borrow, and stable borrow\nincentives for each reserve in an Aave market\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { formatReservesAndIncentives } from '@aave/math-utils';\nimport dayjs from 'dayjs';\n\n// 'reserves' and 'reserveIncentives' inputs from Fetching Protocol Data section\n\nconst reservesArray = reserves.reservesData;\nconst baseCurrencyData = reserves.baseCurrencyData;\n\nconst currentTimestamp = dayjs().unix();\n\n/*\n- @param `reserves` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.reservesArray`\n- @param `currentTimestamp` Current UNIX timestamp in seconds, Math.floor(Date.now() / 1000)\n- @param `marketReferencePriceInUsd` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.baseCurrencyData.marketReferencePriceInUsd`\n- @param `marketReferenceCurrencyDecimals` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.baseCurrencyData.marketReferenceCurrencyDecimals`\n- @param `reserveIncentives` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserveIncentives`\n*/\nconst formattedPoolReserves = formatReservesAndIncentives({\n  reserves: reservesArray,\n  currentTimestamp,\n  marketReferenceCurrencyDecimals:\n    baseCurrencyData.marketReferenceCurrencyDecimals,\n  marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,\n  reserveIncentives,\n});\n```\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n## User Data\n\nOnce you have successfully completed the Setup instructions and are querying\non-chain data, the next step is to format this data into human readable format\nand compute cumulative user metrics. This is done using the formatter functions\nin the `@aave/math-utils` package. There are two formatters for user data, one\nwith incentives data, and one without. Examples for both methods are shown\nbelow.\n\nThe output of these methods is an object containing cumulative metrics\n(healthFactor, totalLiquidity, totalBorrows, etc.) and an array of formatted\nreserve data plus user holdings (aTokens, debtTokens) for each reserve in an\nAave market.\n\n### formatUserSummary\n\nReturns formatted summary of Aave user portfolio including: array of holdings,\ntotal liquidity, total collateral, total borrows, liquidation threshold, health\nfactor, and available borrowing power\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { formatUserSummary } from '@aave/math-utils';\nimport dayjs from 'dayjs';\n\n// 'reserves' and 'userReserves' inputs from Setup section\n\nconst reservesArray = reserves.reservesData;\nconst baseCurrencyData = reserves.baseCurrencyData;\nconst userReservesArray = userReserves.userReserves;\n\nconst currentTimestamp = dayjs().unix();\n\nconst formattedReserves = formatReserves({\n  reserves: reservesArray,\n  currentTimestamp,\n  marketReferenceCurrencyDecimals:\n    baseCurrencyData.marketReferenceCurrencyDecimals,\n  marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,\n});\n\n/*\n- @param `currentTimestamp` Current UNIX timestamp in seconds, Math.floor(Date.now() / 1000)\n- @param `marketReferencePriceInUsd` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.baseCurrencyData.marketReferencePriceInUsd`\n- @param `marketReferenceCurrencyDecimals` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.baseCurrencyData.marketReferenceCurrencyDecimals`\n- @param `userReserves` Input from [Fetching Protocol Data](#fetching-protocol-data), combination of `userReserves.userReserves` and `reserves.reservesArray`\n- @param `userEmodeCategoryId` Input from [Fetching Protocol Data](#fetching-protocol-data), `userReserves.userEmodeCategoryId`\n*/\nconst userSummary = formatUserSummary({\n  currentTimestamp,\n  marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,\n  marketReferenceCurrencyDecimals:\n    baseCurrencyData.marketReferenceCurrencyDecimals,\n  userReserves: userReservesArray,\n  formattedReserves,\n  userEmodeCategoryId: userReserves.userEmodeCategoryId,\n});\n```\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### formatUserSummaryAndIncentives\n\nReturns formatted summary of Aave user portfolio including: array of holdings,\ntotal liquidity, total collateral, total borrows, liquidation threshold, health\nfactor, available borrowing power, and dictionary of claimable incentives\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { formatUserSummaryAndIncentives } from '@aave/math-utils';\nimport dayjs from 'dayjs';\n\n// 'reserves', 'userReserves', 'reserveIncentives', and 'userIncentives' inputs from Setup section\n\nconst reservesArray = reserves.reservesData;\nconst baseCurrencyData = reserves.baseCurrencyData;\nconst userReservesArray = userReserves.userReserves;\n\nconst currentTimestamp = dayjs().unix();\n\nconst formattedReserves = formatReserves({\n  reserves: reservesArray,\n  currentTimestamp,\n  marketReferenceCurrencyDecimals:\n    baseCurrencyData.marketReferenceCurrencyDecimals,\n  marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,\n});\n\n/*\n- @param `currentTimestamp` Current UNIX timestamp in seconds, Math.floor(Date.now() / 1000)\n- @param `marketReferencePriceInUsd` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.baseCurrencyData.marketReferencePriceInUsd`\n- @param `marketReferenceCurrencyDecimals` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserves.baseCurrencyData.marketReferenceCurrencyDecimals`\n- @param `userReserves` Input from [Fetching Protocol Data](#fetching-protocol-data), combination of `userReserves.userReserves` and `reserves.reservesArray`\n- @param `userEmodeCategoryId` Input from [Fetching Protocol Data](#fetching-protocol-data), `userReserves.userEmodeCategoryId`\n- @param `reserveIncentives` Input from [Fetching Protocol Data](#fetching-protocol-data), `reserveIncentives`\n- @param `userIncentives` Input from [Fetching Protocol Data](#fetching-protocol-data), `userIncentives`\n*/\nconst userSummary = formatUserSummaryAndIncentives({\n  currentTimestamp,\n  marketReferencePriceInUsd: baseCurrencyData.marketReferenceCurrencyPriceInUsd,\n  marketReferenceCurrencyDecimals:\n    baseCurrencyData.marketReferenceCurrencyDecimals,\n  userReserves: userReservesArray,\n  formattedReserves,\n  userEmodeCategoryId: userReserves.userEmodeCategoryId,\n  reserveIncentives,\n  userIncentives,\n});\n```\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n# Transaction Methods\n\nThe transaction methods package provides an sdk to interact with Aave Protocol\ncontracts. See [ethers.js](#ethers.js) for instructions on installing setting up\nan ethers provider\n\nOnce initialized this sdk can be used to generate the transaction data needed to\nperform protocol interactions. If an approval is required, the method will\nreturn an array with two transactions, or single transaction if no approval is\nneeded.\n\n## Transactions Setup\n\nAll transaction methods will return an array of transaction objects of this\ntype:\n\n```ts\nimport { EthereumTransactionTypeExtended } from '@aave/contract-helpers';\n```\n\nTo send a transaction from this object:\n\n```ts\nimport { BigNumber, providers } from 'ethers';\n\nfunction submitTransaction({\n  provider: providers.Web3Provider,  // Signing transactions requires a wallet provider, Aave UI currently uses web3-react (https://github.com/NoahZinsmeister/web3-react) for connecting wallets and accessing the wallet provider\n  tx: EthereumTransactionTypeExtended\n}){\n  const extendedTxData = await tx.tx();\n  const { from, ...txData } = extendedTxData;\n  const signer = provider.getSigner(from);\n  const txResponse = await signer.sendTransaction({\n    ...txData,\n    value: txData.value ? BigNumber.from(txData.value) : undefined,\n  });\n}\n```\n\n\u003cbr /\u003e\n\n## Submitting Transactions\n\nAll transaction methods will return an array of transaction objects of the\nfollowing type:\n\n```\nimport { EthereumTransactionTypeExtended } from '@aave/contract-helpers';\n```\n\nTo send a transaction from this object:\n\n```\nimport { BigNumber, providers } from 'ethers';\n\nfunction submitTransaction({\n  provider: ethers.providers.provider,  // Signing transactions requires a wallet provider\n  tx: EthereumTransactionTypeExtended\n}){\n  const extendedTxData = await tx.tx();\n  const { from, ...txData } = extendedTxData;\n  const signer = provider.getSigner(from);\n  const txResponse = await signer.sendTransaction({\n    ...txData,\n    value: txData.value ? BigNumber.from(txData.value) : undefined,\n  });\n}\n```\n\n\u003cbr /\u003e\n\n## Pool V3\n\nTransaction methods to perform actions on the V3 Pool contract\n\n### supplyBundle\n\nA [bundle method](#bundle-methods) for supply, formerly deposit, which supplies\nthe underlying asset into the Pool reserve. For every token that is supplied, a\ncorresponding amount of aTokens is minted.\n\nThe bundle method provides the transaction for the action, approval if required\n(txn or signature request), and callback to generate signed supplyWithPermit\ntxn.\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n````ts\nimport { PoolBundle } from '@aave/contract-helpers';\n\nconst poolBundle = new PoolBundle(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit\n- @param `reserve` The ethereum address of the reserve\n- @param `amount` The amount to be deposited\n- @param @optional `onBehalfOf` The ethereum address for which user is depositing. It will default to the user address\n*/\nconst supplyBundle: ActionBundle = await poolBundle.supplyBundle({\n  user,\n  reserve,\n  amount,\n  onBehalfOf,\n});\n\n// Submit bundle components as shown in #bundle-methods section\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### supply\n\nFormerly `deposit`, supply the underlying asset into the Pool reserve. For every\ntoken that is supplied, a corresponding amount of aTokens is minted\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit\n- @param `reserve` The ethereum address of the reserve\n- @param `amount` The amount to be deposited\n- @param @optional `onBehalfOf` The ethereum address for which user is depositing. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.supply({\n  user,\n  reserve,\n  amount,\n  onBehalfOf,\n});\n\n// If the user has not approved the pool contract to spend their tokens, txs will also contain two transactions: approve and supply. These approval and supply transactions can be submitted just as in V2,OR you can skip the first approval transaction with a gasless signature by using signERC20Approval -\u003e supplyWithPermit which are documented below\n\n// If there is no approval transaction, then supply() can called without the need for an approval or signature\n````\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### signERC20Approval\n\nThis method is used to generate the raw signature data to be signed by the user.\nOnce generated, a function is called to trigger a signature request from the\nusers wallet. This signature can be passed a parameter to `supplyWithPermit` or\n`repayWithPermit` in place of an approval transaction.\n\nNote: Not all tokens are compatible with the ERC-2612 permit functionality. You\ncan check the\n\u003ca href=\"https://github.com/aave/interface/blob/main/src/ui-config/permitConfig.ts\" target=\"_blank\"\u003eAave\ninterface config\u003c/a\u003e for an updated list of supported tokens by network.\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `reserve` The ethereum address of the reserve \n- @param `amount` The amount to be deposited \n- @param `deadline` Expiration of signature in seconds, for example, 1 hour = Math.floor(Date.now() / 1000 + 3600).toString()\n*/\nconst dataToSign: string = await pool.signERC20Approval({\n  user,\n  reserve,\n  amount,\n  deadline,\n});\n\nconst signature = await provider.send('eth_signTypedData_v4', [\n  currentAccount,\n  dataToSign,\n]);\n\n// This signature can now be passed into the supplyWithPermit() function below\n```\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### supplyWithPermit\n\nSame underlying method as `supply` but uses a signature based approval passed as\na parameter.\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `reserve` The ethereum address of the reserve \n- @param `amount` The amount to be deposited \n- @param `signature` Signature approving Pool to spend user funds, received from signing output data of signERC20Approval()\n- @param @optional `onBehalfOf` The ethereum address for which user is depositing. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.supplyWithPermit({\n  user,\n  reserve,\n  amount,\n  signature,\n  onBehalfOf,\n});\n```\n\nSubmit transaction as shown [here](#transactions-setup)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### borrow (V3)\n\nBorrow an `amount` of `reserve` asset.\n\nUser must have a collateralized position (i.e. aTokens in their wallet)\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool, InterestRate } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that repays \n- @param `reserve` The ethereum address of the reserve on which the user borrowed\n- @param `amount` The amount to repay, or (-1) if the user wants to repay everything\n- @param `interestRateMode` // Whether the borrow will incur a stable (InterestRate.Stable) or variable (InterestRate.Variable) interest rate\n- @param @optional `onBehalfOf` The ethereum address for which user is repaying. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = pool.Borrow({\n  user,\n  reserve,\n  amount,\n  interestRateMode,\n  onBehalfOf,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### repay (V3)\n\nRepays a borrow on the specific reserve, for the specified amount (or for the\nwhole amount, if (-1) is specified). the target user is defined by `onBehalfOf`.\nIf there is no repayment on behalf of another account, `onBehalfOf` must be\nequal to `user`\n\nIf the Pool is not approved to spend `user` funds, an approval transaction will\nalso be returned\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `reserve` The ethereum address of the reserve \n- @param `amount` The amount to be deposited \n- @param `interestRateMode` // Whether stable (InterestRate.Stable) or variable (InterestRate.Variable) debt will be repaid\n- @param @optional `onBehalfOf` The ethereum address for which user is depositing. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.repay({\n  user,\n  reserve,\n  amount,\n  interestRateMode,\n  onBehalfOf,\n});\n\n// If the user has not approved the pool contract to spend their tokens, txs will also contain two transactions: approve and repay. This approval transaction can be submitted just as in V2, OR you approve with a gasless signature by using signERC20Approval -\u003e supplyWithPermit which are documented below\n\n// If there is no approval transaction, then repay() can called without the need for an approval or signature\n```\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### repayWithPermit\n\nSame underlying method as `repay` but uses a signature based approval passed as\na parameter.\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `reserve` The ethereum address of the reserve \n- @param `amount` The amount to be deposited \n- @param `signature` Signature approving Pool to spend user funds, from signERC20Approval()\n- @param @optional `onBehalfOf` The ethereum address for which user is depositing. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.supplyWithPermit({\n  user,\n  reserve,\n  amount,\n  signature,\n  onBehalfOf,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### repayWithATokens\n\nRepays a borrow on the specific reserve, for the specified amount, deducting\nfunds from a users aToken balance instead of the underlying balance. To repay\nthe max debt amount or max aToken balance without dust (whichever is lowest),\nset the amount to -1\n\nThere is no need for an approval or signature when repaying with aTokens\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool, InterestRate } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `amount` The amount to be deposited, -1 to repay max aToken balance or max debt balance without dust (whichever is lowest)\n- @param `reserve` The ethereum address of the reserve \n- @param `rateMode` The debt type to repay, stable (InterestRate.Stable) or variable (InterestRate.Variable)\n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.repayWithATokens({\n  user,\n  amount,\n  reserve,\n  reateMode,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### withdraw (V3)\n\nWithdraws the underlying asset of an aToken asset.\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `reserve` The ethereum address of the reserve \n- @param `amount` The amount to be deposited \n- @param `aTokenAddress` The aToken to redeem for underlying asset\n- @param @optional `onBehalfOf` The ethereum address for which user is depositing. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.withdraw({\n  user,\n  reserve,\n  amount,\n  aTokenAddress,\n  onBehalfOf,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### swapBorrowRateMode (V3)\n\nBorrowers can use this function to swap between stable and variable borrow rate\nmodes\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool, InterestRate } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `reserve` The ethereum address of the reserve \n- @param `interestRateMode` The rate mode to swap to, stable (InterestRate.Stable) or variable (InterestRate.Variable) \n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.swapBorrowRateMode({\n  user,\n  reserve,\n  amount,\n  onBehalfOf,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### setUsageAsCollateral (V3)\n\nAllows depositors to enable or disable a specific deposit as collateral\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `reserve` The ethereum address of the reserve \n- @param `usageAsCollateral` Boolean, true if the user wants to use the deposit as collateral, false otherwise\n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.setUsageAsCollateral({\n  user,\n  reserve,\n  usageAsCollateral,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### liquidationCall (V3)\n\nUsers can invoke this function to liquidate an undercollateralized position\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `liquidator` The ethereum address that will liquidate the position \n- @param `liquidatedUser` The address of the borrower \n- @param `debtReserve` The ethereum address of the principal reserve \n- @param `collateralReserve` The address of the collateral to liquidated \n- @param `purchaseAmount` The amount of principal that the liquidator wants to repay \n- @param @optional `getAToken` Boolean to indicate if the user wants to receive the aToken instead of the asset. Defaults to false\n*/\nconst txs: EthereumTransactionTypeExtended[] = lendingPool.liquidationCall({\n  liquidator,\n  liquidatedUser,\n  debtReserve,\n  collateralReserve,\n  purchaseAmount,\n  getAToken,\n});\n```\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### swapCollateral (V3)\n\nUtilizes flashloan to swap to a different collateral asset\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  SWAP_COLLATERAL_ADAPTER: swapCollateralAdapterAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will liquidate the position \n- @param @optional `flash` If the transaction will be executed through a flashloan(true) or will be done directly through the adapters(false). Defaults to false \n- @param `fromAsset` The ethereum address of the asset you want to swap \n- @param `fromAToken` The ethereum address of the aToken of the asset you want to swap \n- @param `toAsset` The ethereum address of the asset you want to swap to (get) \n- @param `fromAmount` The amount you want to swap \n- @param `toAmount` The amount you want to get after the swap \n- @param `maxSlippage` The max slippage that the user accepts in the swap \n- @param @optional `permitSignature` A permit signature of the tx. Only needed when previously signed (Not needed at the moment). \n- @param `swapAll` Bool indicating if the user wants to swap all the current collateral \n- @param @optional `onBehalfOf` The ethereum address for which user is swapping. It will default to the user address \n- @param @optional `referralCode` Integrators are assigned a referral code and can potentially receive rewards. It defaults to 0 (no referrer) \n- @param @optional `useEthPath` Boolean to indicate if the swap will use an ETH path. Defaults to false\n*/\nconst txs: EthereumTransactionTypeExtended[] = await lendingPool.swapCollateral(\n  {\n    user,\n    flash,\n    fromAsset,\n    fromAToken,\n    toAsset,\n    fromAmount,\n    toAmount,\n    maxSlippage,\n    permitSignature,\n    swapAll,\n    onBehalfOf,\n    referralCode,\n    useEthPath,\n  },\n);\n```\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### repayWithCollateral (V3)\n\nAllows a borrower to repay the open debt with their collateral\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  REPAY_WITH_COLLATERAL_ADAPTER: repayWithCollateralAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will liquidate the position \n- @param `fromAsset` The ethereum address of the asset you want to repay with (collateral) \n- @param `fromAToken` The ethereum address of the aToken of the asset you want to repay with (collateral) \n- @param `assetToRepay` The ethereum address of the asset you want to repay \n- @param `repayWithAmount` The amount of collateral you want to repay the debt with\n- @param `repayAmount` The amount of debt you want to repay \n- @param `permitSignature` A permit signature of the tx. Optional\n- @param @optional `repayAllDebt` Bool indicating if the user wants to repay all current debt. Defaults to false \n- @param `rateMode` //Enum indicating the type of the interest rate of the collateral\n- @param @optional `onBehalfOf` The ethereum address for which user is swapping. It will default to the user address \n- @param @optional `referralCode` Integrators are assigned a referral code and can potentially receive rewards. It defaults to 0 (no referrer) \n- @param @optional `flash` If the transaction will be executed through a flashloan(true) or will be done directly through the adapters(false). Defaults to false \n- @param @optional `useEthPath` Boolean to indicate if the swap will use an ETH path. Defaults to false\n*/\nconst txs: EthereumTransactionTypeExtended[] =\n  await lendingPool.repayWithCollateral({\n    user,\n    fromAsset,\n    fromAToken,\n    assetToRepay,\n    repayWithAmount,\n    repayAmount,\n    permitSignature,\n    repayAllDebt,\n    rateMode,\n    onBehalfOf,\n    referralCode,\n    flash,\n    useEthPath,\n  });\n```\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### setUserEMode\n\nFunction to enable eMode on a user account IF conditions are met:\n\nTo enable, pass `categoryId` of desired eMode (1 = stablecoins), can only be\nenabled if a users currently borrowed assets are ALL within this eMode category\nTo disable, pass `categoryId` of 0, can only be disabled if new LTV will not\nleave user undercollateralized\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { Pool } from '@aave/contract-helpers';\n\nconst pool = new Pool(provider, {\n  POOL: poolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit \n- @param `categoryId` number representing the eMode to switch to, 0 = disable, 1 = stablecoins\n*/\nconst txs: EthereumTransactionTypeExtended[] = await pool.setUserEMode({\n  user,\n  categoryId,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n## Lending Pool V2\n\nObject that contains all the necessary methods to create Aave V2 lending pool\ntransactions\n\n### depositBundle\n\nA [bundle method](#bundle-methods) for deposit, which supplies the underlying\nasset into the Pool reserve. For every token that is supplied, a corresponding\namount of aTokens is minted.\n\nThe bundle method generates the deposit tx data and approval tx data (if\nrequired).\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n````ts\nimport { LendingPoolBundle } from '@aave/contract-helpers';\n\nconst lendingPoolBundle = new LendingPoolBundle(provider, {\n  LENDING_POOL: lendingPoolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit\n- @param `reserve` The ethereum address of the reserve\n- @param `amount` The amount to be deposited\n- @param @optional `onBehalfOf` The ethereum address for which user is depositing. It will default to the user address\n*/\nconst depositBundle: ActionBundle = await lendingPoolBundle.depositBundle({\n  user,\n  reserve,\n  amount,\n  onBehalfOf,\n});\n\n// Submit bundle components as shown in #bundle-methods section\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### deposit\n\nDeposits the underlying asset into the reserve. For every token that is\ndeposited, a corresponding amount of aTokens is minted\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { LendingPool } from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will make the deposit\n- @param `reserve` The ethereum address of the reserve\n- @param `amount` The amount to be deposited\n- @param @optional `onBehalfOf` The ethereum address for which user is depositing. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = await lendingPool.deposit({\n  user,\n  reserve,\n  amount,\n  onBehalfOf,\n});\n````\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### borrow\n\nBorrow an `amount` of `reserve` asset.\n\nUser must have a collateralized position (i.e. aTokens in their wallet)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { LendingPool, InterestRate } from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will receive the borrowed amount \n- @param `reserve` The ethereum address of the reserve asset \n- @param `amount` The amount to be borrowed, in human readable units (e.g. 2.5 ETH)\n- @param `interestRateMode`//Whether the borrow will incur a stable (InterestRate.Stable) or variable (InterestRate.Variable) interest rate\n- @param @optional `debtTokenAddress` The ethereum address of the debt token of the asset you want to borrow. Only needed if the reserve is ETH mock address \n- @param @optional `onBehalfOf` The ethereum address for which user is borrowing. It will default to the user address \n*/\nconst txs: EthereumTransactionTypeExtended[] = await lendingPool.borrow({\n  user,\n  reserve,\n  amount,\n  interestRateMode,\n  debtTokenAddress,\n  onBehalfOf,\n  referralCode,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### repay\n\nRepays a borrow on the specific reserve, for the specified amount (or for the\nwhole amount, if (-1) is specified). the target user is defined by `onBehalfOf`.\nIf there is no repayment on behalf of another account, `onBehalfOf` must be\nequal to `user`\n\nIf the `user` is not approved, an approval transaction will also be returned\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { LendingPool, InterestRate } from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that repays \n- @param `reserve` The ethereum address of the reserve on which the user borrowed\n- @param `amount` The amount to repay, or (-1) if the user wants to repay everything\n- @param `interestRateMode` // Whether stable (InterestRate.Stable) or variable (InterestRate.Variable) debt will be repaid\n- @param @optional `onBehalfOf` The ethereum address for which user is repaying. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = lendingPool.repay({\n  user,\n  reserve,\n  amount,\n  interestRateMode,\n  onBehalfOf,\n});\n```\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### withdraw\n\nWithdraws the underlying asset of an aToken asset.\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { LendingPool } from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will receive the aTokens \n- @param `reserve` The ethereum address of the reserve asset \n- @param `amount` The amount of aToken being redeemed \n- @param @optional `aTokenAddress` The ethereum address of the aToken. Only needed if the reserve is ETH mock address \n- @param @optional `onBehalfOf` The amount of aToken being redeemed. It will default to the user address\n*/\nconst txs: EthereumTransactionTypeExtended[] = lendingPool.withdraw({\n  user,\n  reserve,\n  amount,\n  aTokenAddress,\n  onBehalfOf,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### swapBorrowRateMode\n\nBorrowers can use this function to swap between stable and variable borrow rate\nmodes.\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { LendingPool, InterestRate } from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n});\n\n/*\n- @param `user` The ethereum address that wants to swap rate modes \n- @param `reserve` The address of the reserve on which the user borrowed \n- @param `interestRateMode` //Whether the borrow will incur a stable (InterestRate.Stable) or variable (InterestRate.Variable) interest rate\n*/\nconst txs: EthereumTransactionTypeExtended[] = lendingPool.swapBorrowRateMode({\n  user,\n  reserve,\n  interestRateMode,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### setUsageAsCollateral\n\nAllows depositors to enable or disable a specific deposit as collateral\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { LendingPool, InterestRate } from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n});\n\n/*\n- @param `user` The ethereum address that enables or disables the deposit as collateral\n- @param `reserve` The ethereum address of the reserve \n- @param `useAsCollateral` Boolean, true if the user wants to use the deposit as collateral, false otherwise\n*/\nconst txs: EthereumTransactionTypeExtended[] = lendingPool.setUsageAsCollateral(\n  {\n    user,\n    reserve,\n    usageAsCollateral,\n  },\n);\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### liquidationCall\n\nUsers can invoke this function to liquidate an undercollateralized position.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { LendingPool } from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `liquidator` The ethereum address that will liquidate the position \n- @param `liquidatedUser` The address of the borrower \n- @param `debtReserve` The ethereum address of the principal reserve \n- @param `collateralReserve` The address of the collateral to liquidated \n- @param `purchaseAmount` The amount of principal that the liquidator wants to repay\n- @param @optional `getAToken` Boolean to indicate if the user wants to receive the aToken instead of the asset. Defaults to false\n*/\nconst txs: EthereumTransactionTypeExtended[] = lendingPool.liquidationCall({\n  liquidator,\n  liquidatedUser,\n  debtReserve,\n  collateralReserve,\n  purchaseAmount,\n  getAToken,\n});\n```\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### swapCollateral\n\nAllows users to swap a collateral to another asset\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport {\n  LendingPool,\n  InterestRate,\n  PermitSignature,\n} from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n  SWAP_COLLATERAL_ADAPTER: swapCollateralAdapterAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will liquidate the position \n- @param @optional `flash` If the transaction will be executed through a flashloan(true) or will be done directly through the adapters(false). Defaults to false \n- @param `fromAsset` The ethereum address of the asset you want to swap \n- @param `fromAToken` The ethereum address of the aToken of the asset you want to swap\n- @param `toAsset` The ethereum address of the asset you want to swap to (get) \n- @param `fromAmount` The amount you want to swap \n- @param `toAmount` The amount you want to get after the swap \n- @param `maxSlippage` The max slippage that the user accepts in the swap \n- @param @optional `permitSignature` A permit signature of the tx. Only needed when previously signed (Not needed at the moment).\n- @param `swapAll` Bool indicating if the user wants to swap all the current collateral\n- @param @optional `onBehalfOf` The ethereum address for which user is swapping. It will default to the user address\n- @param @optional `referralCode` Integrators are assigned a referral code and can potentially receive rewards. It defaults to 0 (no referrer)\n- @param @optional `useEthPath` Boolean to indicate if the swap will use an ETH path. Defaults to false\n*/\nconst txs: EthereumTransactionTypeExtended[] = await lendingPool.swapCollateral(\n  {\n    user,\n    flash,\n    fromAsset,\n    fromAToken,\n    toAsset,\n    fromAmount,\n    toAmount,\n    maxSlippage,\n    permitSignature,\n    swapAll,\n    onBehalfOf,\n    referralCode,\n    useEthPath,\n  },\n);\n```\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### repayWithCollateral\n\nAllows a borrower to repay the open debt with their collateral\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport {\n  LendingPool,\n  InterestRate,\n  PermitSignature,\n} from '@aave/contract-helpers';\n\nconst lendingPool = new LendingPool(provider, {\n  LENDING_POOL: lendingPoolAddress,\n  REPAY_WITH_COLLATERAL_ADAPTER: repayWithCollateralAddress,\n  WETH_GATEWAY: wethGatewayAddress,\n});\n\n/*\n- @param `user` The ethereum address that will liquidate the position \n- @param `fromAsset` The ethereum address of the asset you want to repay with (collateral)\n- @param `fromAToken` The ethereum address of the aToken of the asset you want to repay with (collateral)\n- @param `assetToRepay` The ethereum address of the asset you want to repay \n- @param `repayWithAmount` The amount of collateral you want to repay the debt with\n- @param `repayAmount` The amount of debt you want to repay \n- @param `permitSignature` A permit signature of the tx. Optional\n- @param @optional `repayAllDebt` Bool indicating if the user wants to repay all current debt. Defaults to false\n- @param `rateMode` //Enum indicating the type of the interest rate of the collateral\n- @param @optional `onBehalfOf` The ethereum address for which user is swapping. It will default to the user address\n- @param @optional `referralCode` Integrators are assigned a referral code and can potentially receive rewards. It defaults to 0 (no referrer)\n- @param @optional `flash` If the transaction will be executed through a flashloan(true) or will be done directly through the adapters(false). Defaults to false\n- @param @optional `useEthPath` Boolean to indicate if the swap will use an ETH path. Defaults to false\n*/\nconst txs: EthereumTransactionTypeExtended[] =\n  await lendingPool.repayWithCollateral({\n    user,\n    fromAsset,\n    fromAToken,\n    assetToRepay,\n    repayWithAmount,\n    repayAmount,\n    permitSignature,\n    repayAllDebt,\n    rateMode,\n    onBehalfOf,\n    referralCode,\n    flash,\n    useEthPath,\n  });\n```\n\nSubmit transaction(s) as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n## Governance V2\n\nExample of how to use functions of the Aave governance service\n\n```ts\nimport { AaveGovernanceService } from '@aave/contract-helpers';\n\nconst httpProvider = new Web3.providers.HttpProvider(\n  process.env.ETHEREUM_URL || 'https://kovan.infura.io/v3/\u003cproject_id\u003e',\n);\n\nconst governanceService = new AaveGovernanceService(httpProvider, {\n  GOVERNANCE_ADDRESS: aaveGovernanceV2Address,\n  GOVERNANCE_HELPER_ADDRESS: aaveGovernanceV2HelperAddress,\n  ipfsGateway: IPFS_ENDPOINT,\n});\n```\n\n### create\n\nCreates a Proposal (needs to be validated by the Proposal Validator)\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { AaveGovernanceService } from '@aave/contract-helpers';\n\nconst governanceService = new AaveGovernanceService(rpcProvider, {\n  GOVERNANCE_ADDRESS: aaveGovernanceV2Address,\n  GOVERNANCE_HELPER_ADDRESS: aaveGovernanceV2HelperAddress,\n  ipfsGateway: IPFS_ENDPOINT,\n});\n\n/*\n- @param `user` The ethereum address that will create the proposal\n- @param `targets` list of contracts called by proposal's associated transactions\n- @param `values` list of value in wei for each proposal's associated transaction\n- @param `signatures` list of function signatures (can be empty) to be used when created the callData\n- @param `calldatas` list of calldatas: if associated signature empty, calldata ready, else calldata is arguments\n- @param `withDelegatecalls` boolean, true = transaction delegatecalls the target, else calls the target\n- @param `ipfsHash` IPFS hash of the proposal\n- @param `executor` The ExecutorWithTimelock contract that will execute the proposal: ExecutorType.Short or ExecutorType.Long\n*/\nconst tx = governanceService.create({\n  user,\n  targets,\n  values,\n  signatures,\n  calldatas,\n  withDelegatecalls,\n  ipfsHash,\n  executor,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\u003cbr /\u003e\n\n### cancel\n\nCancels a Proposal. Callable by the guardian with relaxed conditions, or by\nanybody if the conditions of cancellation on the executor are fulfilled\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { AaveGovernanceService } from '@aave/contract-helpers';\n\nconst governanceService = new AaveGovernanceService(rpcProvider, {\n  GOVERNANCE_ADDRESS: aaveGovernanceV2Address,\n  GOVERNANCE_HELPER_ADDRESS: aaveGovernanceV2HelperAddress,\n  ipfsGateway: IPFS_ENDPOINT,\n});\n\n/*\n- @param `user` The ethereum address that will create the proposal\n- @param `proposalId` Id of the proposal we want to queue\n*/\nconst tx = governanceService.cancel({ user, proposalId });\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\u003cbr /\u003e\n\n### queue\n\nQueue the proposal (If Proposal Succeeded)\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { AaveGovernanceService } from '@aave/contract-helpers';\n\nconst governanceService = new AaveGovernanceService(rpcProvider, {\n  GOVERNANCE_ADDRESS: aaveGovernanceV2Address,\n  GOVERNANCE_HELPER_ADDRESS: aaveGovernanceV2HelperAddress,\n  ipfsGateway: IPFS_ENDPOINT,\n});\n\n/*\n- @param `user` The ethereum address that will create the proposal\n- @param `proposalId` Id of the proposal we want to queue\n*/\nconst tx = governanceService.queue({ user, proposalId });\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### execute\n\nExecute the proposal (If Proposal Queued)\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { AaveGovernanceService } from '@aave/contract-helpers';\n\nconst governanceService = new AaveGovernanceService(rpcProvider, {\n  GOVERNANCE_ADDRESS: aaveGovernanceV2Address,\n  GOVERNANCE_HELPER_ADDRESS: aaveGovernanceV2HelperAddress,\n  ipfsGateway: IPFS_ENDPOINT,\n});\n\n/*\n- @param `user` The ethereum address that will create the proposal\n- @param `proposalId` Id of the proposal we want to execute\n*/\nconst tx = governanceService.execute({ user, proposalId });\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\u003cbr /\u003e\n\n### submitVote\n\nFunction allowing msg.sender to vote for/against a proposal\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { AaveGovernanceService } from '@aave/contract-helpers';\n\nconst governanceService = new AaveGovernanceService(rpcProvider, {\n  GOVERNANCE_ADDRESS: aaveGovernanceV2Address,\n  GOVERNANCE_HELPER_ADDRESS: aaveGovernanceV2HelperAddress,\n  ipfsGateway: IPFS_ENDPOINT,\n});\n\n/*\n- @param `user` The ethereum address that will create the proposal \n- @param `proposalId` Id of the proposal we want to vote \n- @param `support` Bool indicating if you are voting in favor (true) or against (false)\n*/\nconst tx = governanceService.submitVote({ user, proposalId, support });\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### delegate\n\nMethod for the user to delegate voting `and` proposition power to the chosen\naddress\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { GovernancePowerDelegationTokenService } from '@aave/contract-helpers';\n\nconst powerDelegation = new GovernancePowerDelegationTokenService(rpcProvider);\n\n/*\n- @param `user` The ethereum address that will create the proposal \n- @param `delegatee` The ethereum address to which the user wants to delegate proposition power and voting power\n- @param `governanceToken` The ethereum address of the governance token\n*/\nconst tx = powerDelegation.delegate({ user, delegatee, governanceToken });\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n### delegateByType\n\nMethod for the user to delegate voting `or` proposition power to the chosen\naddress\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { GovernancePowerDelegationTokenService } from '@aave/contract-helpers';\n\nconst powerDelegation = new GovernancePowerDelegationTokenService(rpcProvider);\n\n/*\n- @param `user` The ethereum address that will create the proposal \n- @param `delegatee` The ethereum address to which the user wants to delegate proposition power and voting power\n- @param `delegationType` The type of the delegation the user wants to do: voting power ('0') or proposition power ('1')\n- @param `governanceToken` The ethereum address of the governance token\n*/\nconst tx = powerDelegation.delegateByType({\n  user,\n  delegatee,\n  delegationType,\n  governanceToken,\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n## Faucets\n\nTo use the testnet faucets which are compatible with Aave:\n\n### mint\n\nMint tokens for the usage on the Aave protocol on a test network. The amount of\nminted tokens is fixed and depends on the token\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { FaucetService } from '@aave/contract-helpers';\n\nconst faucetService = new FaucetService(provider, faucetAddress);\n\n/*\n- @param `userAddress` The ethereum address of the wallet the minted tokens will go\n- @param `reserve` The ethereum address of the token you want to mint \n- @param `tokenSymbol` The symbol of the token you want to mint\n*/\nconst tx = faucet.mint({ userAddress, reserve, tokenSymbol });\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n## Credit Delegation\n\nCredit delegation is performed on the debtToken contract through the\n`approveDelegation` function, which approves a spender to borrow a specified\namount of that token.\n\nAccessing delegated credit is done by passing the delegator address as the\n`onBehalfOf` parameter when calling `borrow` on the `Pool` (V3) or `LendingPool`\n(V2).\n\n### approveDelegation\n\n\u003cdetails\u003e\n  \u003csummary\u003eSample Code\u003c/summary\u003e\n\n```ts\nimport { BaseDebtToken, ERC20Service } from '@aave/contract-helpers';\nimport { ethers } from 'ethers';\n\n// Sample public RPC address for querying polygon mainnet\nconst provider = new ethers.providers.JsonRpcProvider(\n  'https://polygon-rpc.com',\n);\n\nconst delegationServicePolygonV2USDC = new BaseDebtToken(\n  provider,\n  new ERC20Service(provider), // This parameter will be removed in future utils version\n);\n\nconst approveDelegation = delegationServicePolygonV2USDC.approveDelegation({\n  user: '...', /// delegator\n  delegatee: '...',\n  debtTokenAddress: '...', // can be any V2 or V3 debt token\n  amount: 1, // in decimals of underlying token\n});\n```\n\nSubmit transaction as shown [here](#submitting-transactions)\n\n\u003c/details\u003e\n\n\u003cbr /\u003e\n\n## New Transaction Methods\n\nThe @aave/contract-helpers package is currently undergoing a refactor to\nsimplify the end-to-end process of building transactions. This section is a work\nin progress and working and will be updated as new methods are added. \u003cbr /\u003e\n\n### Setup\n\nThe samples given below will also use the following packages:\n\n```\nnpm i @aave/contract-helpers @bgd-labs/aave-address-book ethers@5\n```\n\n### Samples\n\n\u003cdetails\u003e\n  \u003csummary\u003eGetting Started\u003c/summary\u003e\n\nNew transaction methods are accessible from the PoolBundle and LendingPool\nobjects. The following script demonstrates how to initialize these objects and\nthe functions which are available.\n\n```\nconst ethers = require(\"ethers\");\nconst markets = require(\"@bgd-labs/aave-address-book\");\nconst { PoolBundle, LendingPoolBundle } = require(\"@aave/contract-helpers\");\n\n// Create provider\n// Can use custom RPC orR a local fork network from tenderly, ganache, foundry, hardhat, etc. for testing\nconst provider = ethers.getDefaultProvider(\"homestead\");\n\nfunction getPoolBundle(v2, marketKey) {\n  if (v2) {\n    return new LendingPoolBundle(provider, {\n      LENDING_POOL: markets[marketKey].POOL,\n      WETH_GATEWAY: markets[marketKey].WETH_GATEWAY,\n    });\n  } else {\n    return new PoolBundle(provider, {\n      POOL: markets[marketKey].POOL,\n      WETH_GATEWAY: markets[marketKey].WETH_GATEWAY,\n    });\n  }\n}\n\nconsole.log(\"Available markets\", markets);\n\n// V2 + V3 Methods\n\nasync function getApprovedAmount(v2, marketKey, user, token) {\n  const poolBundle = getPoolBundle(v2, marketKey);\n  if (v2) {\n    try {\n      const approvedAmount =\n        await poolBundle.depositTxBuilder.getApprovedAmount({\n          user,\n          token,\n        });\n      return approvedAmount;\n    } catch (error) {\n      console.error(\"Error fetching approved amount\", error);\n    }\n  } else {\n    try {\n      const approvedAmount = await poolBundle.supplyTxBuilder.getApprovedAmount(\n        {\n          user,\n          token,\n        }\n      );\n      return approvedAmount;\n    } catch (error) {\n      console.error(\"Error fetching approved amount\", error);\n    }\n  }\n}\n\nfunction generateApprovalTx(user, token, amount, marketKey) {\n  const poolBundle = getPoolBundle(v2, marketKey);\n  if (v2) {\n    try {\n      const approvedAmount = poolBundle.depositTxBuilder.generateApprovalTx({\n        user,\n        token,\n        amount,\n      });\n      return approvedAmount;\n    } catch (error) {\n      console.error(\"Error fetching approved amount\", error);\n    }\n  } else {\n    try {\n      const approvedAmount = poolBundle.supplyTxBuilder.generateApprovalTx({\n        user,\n        token,\n        amount,\n      });\n      return approvedAmount;\n    } catch (error) {\n      console.error(\"Error fetching approved amount\", error);\n    }\n  }\n}\n\nfunction generateSupplyTx(v2, user, token, amount, marketKey) {\n  const poolBundle = getPoolBundle(v2, marketKey);\n  if (v2) {\n    try {\n      const txData = poolBundle.depositTxBuilder.generateTxData({\n        user,\n        reserve: token,\n        amount,\n      });\n      return txData;\n    } catch (error) {\n      console.error(\"Error generating supply tx data\", error);\n    }\n  } else {\n    try {\n      const txData = poolBundle.supplyTxBuilder.generateTxData({\n        user,\n        reserve: token,\n        amount,\n      });\n      return txData;\n    } catch (error) {\n      console.error(\"Errorgenerating deposit tx data\", error);\n    }\n  }\n}\n\n// V3 Methods\n\nfunction generateSupplyWithPermitTx(\n  user,\n  token,\n  amount,\n  signature,\n  marketKey,\n  deadline\n) {\n  const poolBundle = getPoolBundle(false, marketKey);\n  try {\n    const txData = poolBundle.supplyTxBuilder.generateSignedTxData({\n      user,\n      reserve: token,\n      amount,\n      signature,\n      deadline,\n    });\n    return txData;\n  } catch (error) {\n    console.error(\"Errorgenerating deposit tx data\", error);\n  }\n}\n\nasync function generateSupplySignatureRequest(user, token, marketKey, amount) {\n  const spender = markets[marketKey].POOL;\n  const tokenERC20Service = new ERC20Service(provider);\n  const tokenERC2612Service = new ERC20_2612Service(provider);\n  const { name } = await tokenERC20Service.getTokenData(token);\n  const { chainId } = await provider.getNetwork();\n  const nonce = await tokenERC2612Service.getNonce({\n    token,\n    owner: user,\n  });\n  const deadline = Math.floor(Date.now() / 1000 + 3600).toString();\n  const typeData = {\n    types: {\n      EIP712Domain: [\n        { name: \"name\", type: \"string\" },\n        { name: \"version\", type: \"string\" },\n        { name: \"chainId\", type: \"uint256\" },\n        { name: \"verifyingContract\", type: \"address\" },\n      ],\n      Permit: [\n        { name: \"owner\", type: \"address\" },\n        { name: \"spender\", type: \"address\" },\n        { name: \"value\", type: \"uint256\" },\n        { name: \"nonce\", type: \"uint256\" },\n        { name: \"deadline\", type: \"uint256\" },\n      ],\n    },\n    primaryType: \"Permit\",\n    domain: {\n      name,\n      version: \"1\",\n      chainId,\n      verifyingContract: token,\n    },\n    message: {\n      owner: user,\n      spender: spender,\n      value: amount,\n      nonce,\n      deadline,\n    },\n  };\n  return JSON.stringify(typeData);\n}\n\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eComplete CLI Example\u003c/summary\u003e\n\nThe following is a script which generates a command line interface to interact\nwith the V2 and V3 Ethereum markets. This can be used to generate txns or used\nas a reference for how to integrate new transaction methods.\n\n```\nconst ethers = require(\"ethers\");\nconst markets = require(\"@bgd-labs/aave-address-book\");\nconst {\n  PoolBundle,\n  LendingPoolBundle,\n  ERC20Service,\n  ERC20_2612Service,\n  UiPoolDataProvider,\n  ChainId,\n} = require(\"@aave/contract-helpers\");\nconst readline = require(\"readline\");\n\n// Create provider and connect wallet\n// Can use a local fork network from tenderly, ganache, foundry, hardhat, etc. for testing\nconst provider = ethers.getDefaultProvider(\"homestead\");\n\nfunction getPoolBundle(v2, marketKey) {\n  if (v2) {\n    return new LendingPoolBundle(provider, {\n      LENDING_POOL: markets[marketKey].POOL,\n      WETH_GATEWAY: markets[marketKey].WETH_GATEWAY,\n    });\n  } else {\n    return new PoolBundle(provider, {\n      POOL: markets[marketKey].POOL,\n      WETH_GATEWAY: markets[marketKey].WETH_GATEWAY,\n    });\n  }\n}\n\nasync function getApprovedAmount(v2, marketKey, user, token) {\n  const poolBundle = getPoolBundle(v2, marketKey);\n  if (v2) {\n    try {\n      const approvedAmount =\n        await poolBundle.depositTxBuilder.getApprovedAmount({\n          user,\n          token,\n        });\n      return approvedAmount;\n    } catch (error) {\n      console.error(\"Error fetching approved amount\", error);\n    }\n  } else {\n    try {\n      const approvedAmount = await poolBundle.supplyTxBuilder.getApprovedAmount(\n        {\n          user,\n          token,\n        }\n      );\n      return approvedAmount;\n    } catch (error) {\n      console.error(\"Error fetching approved amount\", error);\n    }\n  }\n}\n\nfunction isValidUint256(input) {\n  try {\n    const inputBN = ethers.BigNumber.from(input);\n    const zero = ethers.BigNumber.from(0);\n    const maxUint256 = ethers.constants.MaxUint256;\n\n    if (inputBN.gte(zero) \u0026\u0026 inputBN.lte(maxUint256)) {\n      return true;\n    } else {\n      return false;\n    }\n  } catch (error) {\n    return false;\n  }\n}\n\nfunction generateApprovalTx(user, token, amount, marketKey) {\n  const poolBundle = getPoolBundle(v2, marketKey);\n  if (v2) {\n    try {\n      const approvedAmount = poolBundle.depositTxBuilder.generateApprovalTx({\n        user,\n        token,\n        amount,\n      });\n      return approvedAmount;\n    } catch (error) {\n      console.error(\"Error fetching approved amount\", error);\n    }\n  } else {\n    try {\n      const approvedAmount = poolBundle.supplyTxBuilder.generateApprovalTx({\n        user,\n        token,\n        amount,\n      });\n      return approvedAmount;\n    } catch (error) {\n      console.error(\"Error fetching approved amount\", error);\n    }\n  }\n}\n\nfunction generateSupplyTx(v2, user, token, amount, marketKey) {\n  const poolBundle = getPoolBundle(v2, marketKey);\n  if (v2) {\n    try {\n      const txData = poolBundle.depositTxBuilder.generateTxData({\n        user,\n        reserve: token,\n        amount,\n      });\n      return txData;\n    } catch (error) {\n      console.error(\"Error generating supply tx data\", error);\n    }\n  } else {\n    try {\n      const txData = poolBundle.supplyTxBuilder.generateTxData({\n        user,\n        reserve: token,\n        amount,\n      });\n      return txData;\n    } catch (error) {\n      console.error(\"Errorgenerating deposit tx data\", error);\n    }\n  }\n}\n\nfunction generateSupplyWithPermitTx(\n  user,\n  token,\n  amount,\n  signature,\n  marketKey,\n  deadline\n) {\n  const poolBundle = getPoolBundle(false, marketKey);\n  try {\n    const txData = poolBundle.supplyTxBuilder.generateSignedTxData({\n      user,\n      reserve: token,\n      amount,\n      signature,\n      deadline,\n    });\n    return txData;\n  } catch (error) {\n    console.error(\"Errorgenerating deposit tx data\", error);\n  }\n}\n\nasync function generateSupplySignatureRequest(user, token, marketKey, amount) {\n  const spender = markets[marketKey].POOL;\n  const tokenERC20Service = new ERC20Service(provider);\n  const tokenERC2612Service = new ERC20_2612Service(provider);\n  const { name } = await tokenERC20Service.getTokenData(token);\n  const { chainId } = await provider.getNetwork();\n  const nonce = await tokenERC2612Service.getNonce({\n    token,\n    owner: user,\n  });\n  const deadline = Math.floor(Date.now() / 1000 + 3600).toString();\n  const typeData = {\n    types: {\n      EIP712Domain: [\n        { name: \"name\", type: \"string\" },\n        { name: \"version\", type: \"string\" },\n        { name: \"chainId\", type: \"uint256\" },\n        { name: \"verifyingContract\", type: \"address\" },\n      ],\n      Permit: [\n        { name: \"owner\", type: \"address\" },\n        { name: \"spender\", type: \"address\" },\n        { name: \"value\", type: \"uint256\" },\n        { name: \"nonce\", type: \"uint256\" },\n        { name: \"deadline\", type: \"uint256\" },\n      ],\n    },\n    primaryType: \"Permit\",\n    domain: {\n      name,\n      version: \"1\",\n      chainId,\n      verifyingContract: token,\n    },\n    message: {\n      owner: user,\n      spender: spender,\n      value: amount,\n      nonce,\n      deadline,\n    },\n  };\n  return JSON.stringify(typeData);\n}\n\nconst rl = readline.createInterface({\n  input: process.stdin,\n  output: process.stdout,\n});\n\nfunction marketContinue(marketName) {\n  console.log(\"Press enter to continue\");\n  let load = true;\n  rl.on(\"line\", () =\u003e {\n    if (load) {\n      marketOptions(marketName);\n      load = false;\n    }\n  });\n}\n\nasync function marketOptions(marketName) {\n  const v2 = marketName.includes(\"V2\");\n  console.log(\"\\n\");\n  console.log(\"Type the number of action to perform and press Enter\");\n  console.log(\"1. Print market addresses\");\n  console.log(\"2. Print reserves info\");\n  console.log(\"3. Print user info\");\n  console.log(\"4. Check approved amount to supply\");\n  console.log(\"5. Build approval tx\");\n  if (v2) {\n    console.log(\"6. Build deposit tx\");\n  } else {\n    console.log(\"6. Build supply tx\");\n    console.log(\"7. Build signature request\");\n    console.log(\"8. Build supplyWithPermit tx data\");\n  }\n  console.log(`${v2 ? \"7\" : \"9\"}. \u003c- Back`);\n  console.log(\"\\n\");\n\n  rl.question(\"Your choice: \", async (answer) =\u003e {\n    const choice = parseInt(answer);\n    switch (choice) {\n      case 1:\n        const marketAddresses = markets[marketName];\n        console.log(marketAddresses);\n        console.log(\"\\n\");\n        marketContinue(marketName);\n        break;\n      case 2:\n        console.log(\"Fetching reserves...\");\n        try {\n          // Create UiPoolDataProvider object for fetching protocol reserves data\n          const uiPoolDataProvider = new UiPoolDataProvider({\n            uiPoolDataProviderAddress: v2\n              ? markets.AaveV2Ethereum.UI_POOL_DATA_PROVIDER\n              : markets.AaveV3Ethereum.UI_POOL_DATA_PROVIDER,\n            provider,\n            chainId: ChainId.mainnet,\n          });\n          const reserves = await uiPoolDataProvider.getReservesHumanized({\n            lendingPoolAddressProvider: v2\n              ? markets.AaveV2Ethereum.POOL_ADDRESSES_PROVIDER\n              : markets.AaveV3Ethereum.POOL_ADDRESSES_PROVIDER,\n          });\n          console.log(reserves);\n          console.log(\"\\n\");\n        } catch (error) {\n          console.log(\"Error fetching pool reserves\", error);\n        } finally {\n          marketContinue(marketName);\n        }\n        break;\n      case 3:\n        console.log(\"Enter an ethereum address\");\n        rl.question(\"Input: \", async (answer) =\u003e {\n          if (!ethers.utils.isAddress(answer)) {\n            console.log(\"Not a valid ethereum address\");\n            marketContinue(marketName);\n          } else {\n            console.log(\"Fetching user reserves...\");\n            try {\n              // Create UiPoolDataProvider object for fetching protocol reserves data\n              const uiPoolDataProvider = new UiPoolDataProvider({\n                uiPoolDataProviderAddress: v2\n                  ? markets.AaveV2Ethereum.UI_POOL_DATA_PROVIDER\n                  : markets.AaveV3Ethereum.UI_POOL_DATA_PROVIDER,\n                provider,\n                chainId: ChainId.mainnet,\n              });\n              const reserves = await uiPoolDataProvider.getReservesHumanized({\n                lendingPoolAddressProvider: v2\n                  ? markets.AaveV2Ethereum.POOL_ADDRESSES_PROVIDER\n                  : markets.AaveV3Ethereum.POOL_ADDRESSES_PROVIDER,\n              });\n              console.log(reserves);\n              console.log(\"\\n\");\n            } catch (error) {\n              console.log(\"Error fetching pool reserves\", error);\n            } finally {\n              marketContinue(marketName);\n            }\n          }\n        });\n        break;\n      case 4:\n        console.log(\"Enter a user address\");\n        rl.question(\"Input: \", async (user) =\u003e {\n          if (!ethers.utils.isAddress(user)) {\n            console.log(\"Not a valid ethereum address\");\n            marketContinue(marketName);\n          } else {\n            console.log(\"Input address of underyling token to suply\");\n            rl.question(\"Input: \", async (token) =\u003e {\n              if (!ethers.utils.isAddress(token)) {\n                console.log(\"Not a valid ethereum address\");\n                marketContinue(marketName);\n              } else {\n                const approvedAmount = await getApprovedAmount(\n                  v2,\n                  marketName,\n                  user,\n                  token\n                );\n                console.log(`Approved amount: ${approvedAmount}`);\n                console.log(\"\\n\");\n                console.log(\n                  \"Note: an approval amount of -1 represents a uint256.max approval or an asset that doesn't require approval (base assets)\"\n                );\n                console.log(\"\\n\");\n                marketContinue(marketName);\n              }\n            });\n          }\n        });\n        break;\n      case 5:\n        console.log(\"Enter a user address\");\n        rl.question(\"Input: \", async (user) =\u003e {\n          if (!ethers.utils.isAddress(user)) {\n            console.log(\"Not a valid ethereum address\");\n            marketContinue(marketName);\n          } else {\n            console.log(\"Input address of underyling token to suply\");\n            rl.question(\"Input: \", async (token) =\u003e {\n              if (!ethers.utils.isAddress(token)) {\n                console.log(\"Not a valid ethereum address\");\n                marketContinue(marketName);\n              } else {\n                console.log(\"Input amount to supply, in native token decimals\");\n                rl.question(\"Input: \", async (amount) =\u003e {\n                  if (isValidUint256(amount)) {\n                    const txData = generateApprovalTx(\n                      user,\n                      token,\n                      amount,\n                      marketName\n                    );\n                    console.log(txData);\n                    console.log(\"\\n\");\n                    marketContinue(marketName);\n                  } else {\n                    console.log(\n                      \"Invalid amount input, must be number between 0 and uint256.max\"\n                    );\n                  }\n                });\n              }\n            });\n          }\n        });\n        break;\n      case 6:\n        console.log(\"Enter a user address\");\n        rl.question(\"Input: \", async (user) =\u003e {\n          if (!ethers.utils.isAddress(user)) {\n            console.log(\"Not a valid ethereum address\");\n            marketContinue(marketName);\n          } else {\n            console.log(\"Input address of underyling token to suply\");\n            rl.question(\"Input: \", async (token) =\u003e {\n              if (!ethers.utils.isAddress(token)) {\n                console.log(\"Not a valid ethereum address\");\n                marketContinue(marketName);\n              } else {\n                console.log(\"Input amount to supply, in native token decimals\");\n                rl.question(\"Input: \", async (amount) =\u003e {\n                  if (isValidUint256(amount)) {\n                    const txData = generateSupplyTx(\n                      v2,\n                      user,\n                      token,\n                      amount,\n                      marketName\n                    );\n                    console.log(txData);\n                    console.log(\"\\n\");\n                    marketContinue(marketName);\n                  } else {\n                    console.log(\n                      \"Invalid amount input, must be number between 0 and uint256.max\"\n                    );\n                    marketContinue(marketName);\n                  }\n                });\n              }\n            });\n          }\n        });\n        break;\n      case 7:\n        if (v2) {\n          promptUser();\n          break;\n        }\n        console.log(\"Enter a user address\");\n        rl.question(\"Input: \", async (user) =\u003e {\n          if (!ethers.utils.isAddress(user)) {\n            console.log(\"Not a valid ethereum address\");\n            marketContinue(marketName);\n          } else {\n            console.log(\"Input address of underyling token to suply\");\n            rl.question(\"Input: \", async (token) =\u003e {\n              if (!ethers.utils.isAddress(token)) {\n                console.log(\"Not a valid ethereum address\");\n                marketContinue(marketName);\n              } else {\n                console.log(\"Input amount to supply, in native token decimals\");\n                rl.question(\"Input: \", async (amount) =\u003e {\n                  if (isValidUint256(amount)) {\n                    const dataToSign = await generateSupplySignatureRequest(\n                      user,\n                      token,\n                      marketName,\n                      amount\n                    );\n                    console.log(`Data to sign: ${dataToSign}`);\n                    console.log(\"\\n\");\n                    marketContinue(marketName);\n                  } else {\n                    console.log(\n                      \"Invalid amount input, must be number between 0 and uint256.max\"\n                    );\n                    marketContinue(marketName);\n                  }\n                });\n              }\n            });\n          }\n        });\n        break;\n\n      case 8:\n        if (v2) {\n          console.log(\"action not implemented\");\n        }\n        console.log(\"Enter a user address\");\n        rl.question(\"Input: \", async (user) =\u003e {\n          if (!ethers.utils.isAddress(user)) {\n            console.log(\"Not a valid ethereum address\");\n            marketContinue(marketName);\n          } else {\n            console.log(\"Input address of underyling token to suply\");\n            rl.question(\"Input: \", async (token) =\u003e {\n              if (!ethers.utils.isAddress(token)) {\n                console.log(\"Not a valid ethereum address\");\n                marketContinue(marketName);\n              } else {\n                console.log(\"Input amount to supply, in native token decimals\");\n                rl.question(\"Input: \", async (amount) =\u003e {\n                  if (isValidUint256(amount)) {\n                    console.log(\"Input signature\");\n                    const deadline = Math.floor(\n                      Date.now() / 1000 + 3600\n                    ).toString();\n                    rl.question(\"Input: \", async (signature) =\u003e {\n                      const txData = generateSupplyWithPermitTx(\n                        user,\n                        token,\n                        amount,\n                        signature,\n                        marketName,\n                        deadline\n                      );\n                      console.log(txData);\n                      console.log(\"\\n\");\n                      marketContinue(marketName);\n                    });\n                  } else {\n                    console.log(\n                      \"Invalid amount input, must be number between 0 and uint256.max\"\n                    );\n                  }\n                });\n              }\n            });\n          }\n        });\n        break;\n      case 9:\n        promptUser();\n        break;\n      default:\n        console.log(\"action not implemented\");\n        marketContinue(marketName);\n        break;\n    }\n  });\n}\n\nfunction promptUser() {\n  console.log(\"1. AaveV3Ethereum\");\n  console.log(\"2. AaveV2Ethereum\");\n  console.log(\"3. Exit\");\n  console.log(\"\\n\");\n  console.log(\n    \"Type the number of the market you would like to interact with and press Enter.\"\n  );\n\n  rl.question(\"Your choice: \", async (answer) =\u003e {\n    const choice = parseInt(answer);\n\n    if (choice === 1) {\n      console.log(\"You selected AaveV3Ethereum\");\n      marketOptions(\"AaveV3Ethereum\");\n    } else if (choice === 2) {\n      console.log(\"You selected AaveV2Ethereum\");\n      marketOptions(\"AaveV2Ethereum\");\n    } else if (choice === 3) {\n      rl.close();\n    } else {\n      console.log(\"Invalid market selection\");\n      promptUser();\n    }\n  });\n}\n\nfunction welcome() {\n  console.log(\"Welcome to\");\n  console.log(`\n\n     ######   ##     ##  #######   ######  ########     ######  ##       ####\n    ##    ##  ##     ## ##     ## ##    ##    ##       ##    ## ##        ##\n    ##        ##     ## ##     ## ##          ##       ##       ##        ##\n    ##   #### ######### ##     ##  ######     ##       ##       ##        ##\n    ##    ##  ##     ## ##     ##       ##    ##       ##       ##        ##\n    ##    ##  ##     ## ##     ## ##    ##    ##       ##    ## ##        ##\n     ######   ##     ##  #######   ######     ##        ######  ######## ####\n\n    `);\n  console.log(\"Press enter to begin\");\n  let load = true;\n  rl.on(\"line\", () =\u003e {\n    if (load) {\n      promptUser();\n      load = false;\n    }\n  });\n}\n\nwelcome();\n\n```\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faave%2Faave-utilities","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faave%2Faave-utilities","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faave%2Faave-utilities/lists"}