npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@morpho-org/morpho-aave-v3-sdk

v3.3.0

Published

📦 SDK library for interacting with Morpho AaveV3

Downloads

361

Readme

Morpho's AaveV3-ETH Optimizer SDK

This repository contains the core typescript features used to build a dapp based on Morpho-AaveV3 smart contracts.

Warning
This package is used by the morpho association to build the morpho-aaveV3 dapp but is still under development and subject to changes.
Use at your own risk. Any feedback is welcome.

Installation

You need to use a node version >= 18.0.0

npm install @morpho-org/morpho-aave-v3-sdk
yarn add @morpho-org/morpho-aave-v3-sdk

Configuration

At the root of your dapp or your script:

/* _app.ts */
import sdk from "@morpho-org/morpho-aave-v3-sdk/configuration";

sdk.setConfiguration(config);

where config is an object with the following optional properties:

| property | type | default | description | |------------------------| ------------------------------------ |---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| | isProd | boolean | false | Set to true if the dapp is running in production | | defaultProvider | string | process.env.RPC_URL | The default provider to use. It fallbacks on the default provider from ethers | | defaultMaxIterations | { supply: number; borrow: number } | { supply: 4, borrow: 4 } | Max number of iterations run by the matching engine | | gasLimitPercent | ethers.BigNumber | 11000 (110%) | Percentage of the gas estimation used as the gas limit for transactions (with 4 decimals) | | percentApproximation | ethers.BigNumber | 9900 (99%) | Scaling applied to transactions' amount to prevent reverting due to block inclusion delay | | txSignature | string | undefined | If provided, the signature will be appended to the transaction's data to identify the transaction's origin. It must be in hex format |

Usage

The whole sdk is built around the MorphoAaveV3Adapter class. This is the core element of the sdk.

Data structure

Within the adapter, data are stored in different objects:

| name | public* | source | interface | description | | --------------------- | -------- | ----------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------ | | globalData |   ✅ yes | ⚡️ fetched | GlobalData | Global data about the chain and the protocol | | marketsConfigs |   ✅ yes | ⚡️ fetched | MarketMapping<MarketConfig> | Properties of each market that don't (or rarely) change | | marketsData |   ✅ yes | ⚙️ computed | MarketMapping<MarketData> | Data by market (metrics, apys, ...) that need to be updated frequently | | marketsList |   ✅ yes | ⚡️ fetched | string[] | List of the markets listed on Morpho-AaveV3 | | userData |   ✅ yes | ⚙️ computed | UserData | User Data that are not specific to a market | | userMarketsData |   ✅ yes | ⚙️ computed | MarketMapping<UserMarketData> | User Data by market | | scaledMarketsData |   ❌ no | ⚡️ fetched | MarketMapping<ScaledMarketData> | Raw data by market, before any processing or computation | | scaledUserMarketsData |   ❌ no | ⚡️ fetched | MarketMapping<ScaledUserMarketData> | Raw user data by market, before any processing or computation | | rewardsDistribution |   ❌ no | ⚡️ fetched | MorphoEpochDistribution | Morpho rewards distribution of the current epoch |

* see the section about data to see how to access public data

Initialization

To create an adapter, you must provide fetchers. These are special entities that are used to fetch data. For each fetcher, you can use one from this fetchers or use your own one (as long as it matches the interface). You have 5 different fetchers:

| fetcher | fetched data | available | | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | MarketFetcher | marketsConfigs, marketsList, scaledMarketsData | chain, static | | UserFetcher | scaledUserMarketsData, userData.ethBalance | chain, static | | GlobalDataFetcher | globalData | chain, static | | RewardsFetcher | rewardsDistribution | api, static |

From chain

If you want to fetch all data from the chain, you can use MorphoAaveV3Adapter.fromChain

const adapter = MorphoAaveV3Adapter.fromChain();
  • you can provide a specific provider from ethers to use:
const adapter = MorphoAaveV3Adapter.fromChain({ provider: myProvider });
await adapter.refreshAll("latest");

by default, the one from the configuration will be used

  • Since some data can't be fetched from chain, you can provide specific fetcher for them:
const adapter = MorphoAaveV3Adapter.fromChain({ extraFetchersConfig });
await adapter.refreshAll("latest");

where extraFetchersConfig has the following interface:

const extraFetchersConfig: {
  rewards?: "api" | RewardsFetcher;
}

By default,

  • marketSupply will be fetched from the morpho-labs subgraph
  • rewards will be fetched from morpho API

From mock

You can also provide static data to the adapter to have a static state in the adapter using MorphoAaveV3Adapter.fromMock

const adapter = MorphoAaveV3Adapter.fromMock(mock);
await adapter.refreshAll("latest");

Where mock can be an AdapterMock. If no mock is provided, this one will be used

Note
You can provide loading delays to the fromMock function for testing purposes to simulate real conditions

Read Data

RxJs

The sdk leverages on RxJS to allow you to build highly reactive apps out of the box. To do so, every public data (see Data structure) are associated with an rxjs Subject:

const adapter = MorphoAaveV3Adapter.fromChain();
await adapter.refreshAll("latest");

adapter.marketsConfigs$.subscribe((marketsConfigs) => ...);
adapter.marketsData$.subscribe((marketsData) => ...);
adapter.userMarketsData$.subscribe((userMarketsData) => ...);
adapter.marketsList$.subscribe((marketsList) => ...);
adapter.userData$.subscribe((userData) => ...);
adapter.globalData$.subscribe((globalData) => ...);

Getters

If you don't use RxJs, you can access these data using getter functions:

const adapter = MorphoAaveV3Adapter.fromChain();
await adapter.refreshAll("latest");

const marketsConfigs = adapter.getMarketsConfigs();
const marketsData = adapter.getMarketsData();
const userMarketsData = adapter.getUserMarketsData();
const marketsList = adapter.getMarketsList();
const userData = adapter.getUserData();
const globalData = adapter.getGlobalData();

Execute a transaction

Notifications

To keep track of what's happening during the transactions' executions, the adapter can be provided with a notifier

adapter.addNotifier(notifier); // Adds `notifier` to the list of the adapter's notifiers.
adapter.removeNotifier(notifier); // Removes `notifier` from the list of adapter's notifiers. It needs to be the same object (reference) as the one that has been added
adapter.resetNotifiers(); // Removes all the notifiers and return them in an array.

A notifier can be any instance/object matching the ITransactionNotifier interface.

The handlers are called according to the following timeline:

transaction flow

Transactions with Morpho-AaveV3 contract

adapter.handleMorphoTransaction(txType, underlyingAddress, amount, options);

with

| Param | Type | Description | | ------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------------- | | txType | TransactionType | Type of the operation to perfom | | underlyingAddress | string | Address of the underlying market on which to perform the operation | | amount | ethers.BigNumber | Amount of the transaction. Use ethers.constants.MaxUint256 to use the maximum amount | | options | optional, TransactionOptions | Transaction options |

Approval

Morpho-AaveV3 leverages the Permit2 Approval feature, but you can still perform classic approvals.

Permit2
adapter.handlePermit2Approval(underlyingAddress, deadline, amount, options);

| Param | Type | Description | | ------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------- | | underlyingAddress | string | Address of the underlying token you wanna provide | | deadline | ethers.BigNumber | Deadline after which the approval isn't valid anymore | | amount | ethers.BigNumber | Amount to approve | | options | optional, ApprovalHandlerOptions | Transaction options |

Classic
adapter.handleApproval(underlyingAddress, amount, options);

| Param | Type | Description | | ------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------- | | underlyingAddress | string | Address of the underlying token you wanna provide | | amount | ethers.BigNumber | Amount to approve | | options | optional, ApprovalHandlerOptions | Transaction options |

Claim Morpho rewards

adapter.handleClaimMorpho({ overrides });

Wrap ETH

adapter.handleWrapEth(amount, { overrides });

With amount being of type ethers.BigNumber

Connection

  • Connect a user to the adapter:
adapter.connect(user, signer); // Data will be fetched for `user` and `signer` will be used for transactions
// in read-only

adapter.connect(user); // Data will be fetched for `user` but transactions will be ignored
  • Disconnect connected user:
adapter.disconnect();
  • Get the connection state:
adapter.isConnected();

Refreshing

refreshAll
adapter.refreshAll("latest");

All the data will be refreshed.

Note If the block is undefined, the data will be fetched at the last fetched block. If refreshAll is called for the first time, the data will be fetched at the block "latest"

refreshData
adapter.refreshData();

Fetch a new block from the chain and update all indexes locally without fetching markets data If the block is not a new block, the update will be ignored.

refetchData
adapter.refetchData();

Refetch the data from the chain and recompute computed data.

Note Only globalData, scaledMarketsData, scaledUserMarketsData and rewardsDistribution will be refetched since the others are not likely to change between two blocks

Max capacity

You can use getUserMaxCapacity to get the maximum amount for a given operation on a given market.

const { amount, limiter } = adapter.getUserMaxCapacity(underlyingAddress, txType);

The maximum amount is given in underlying and the limiter is one of the following (see MaxCapacityLimiter)

"LIMITED_BY_WALLET_BALANCE"; // The user can't supply/repay more than his wallet balance
"LIMITED_BY_OPERATION_PAUSED"; // The required operation is paused
"LIMITED_BY_ZERO_PRICE"; // The amount can't be estimated because the fetched price for the given market is zero
"LIMITED_BY_BORROW_CAPACITY"; // The user can't borrow more than his borrow capacity
"LIMITED_BY_POOL_LIQUIDITY"; // The amount is limited by AaveV3 liquidity
"LIMITED_BY_CAP"; // There is a borrow/supply cap on AaveV3 and it limits the operation
"LIMITED_BY_BALANCE"; // The user can't withdraw/repay more than his current balance on Morpho

Simulation

The adapter provides a simulation tool that allows you to simulate the impact of a transaction on its data.

const simulator = adapter.getSimulator(timeout);

with timeout being the minimum delay (in ms) between two refresh. Explicitly set to O to prevent it from refreshing. The default value is 1000 (1s)

Data structure

The simulator has the same data structure as the adapter. See Data Structure for more details.

Note Since the adapter's values are evolving, the simulator will re-run the simulation on the new values when they change.

Simulate

simulator.simulate([
  {
    type,
    amount,
    underlyingAddress
  },
  ...
]);

Reset

Run simulator.reset() reset the operation list.

Note This is equivalent to simulator.simulate([])

Close

When you don't need the simulator anymore, run simulator.close() to free the memory.

Warning Not closing simulators can lead to big performance issues