Which one should you use? Arithmetic or geometric mean TWAP

Delphi Labs
22 min readOct 21, 2022

--

By Jonathan Erlich

Introduction

In this piece we’ll try to answer a simple question: within the context of DeFi lending protocols, is it preferable to use an arithmetic mean (AM) TWAP or a geometric mean (GM) TWAP as an oracle? To answer this question, we’ll compare these two pricing methodologies in two dimensions: manipulation cost and price freshness. The first one refers to the cost of manipulating the TWAP, while the latter refers to how closely the TWAP tracks the spot price. As we’ll see, these two dimensions cover the most relevant factors when assessing DEX-based TWAP oracles.

To achieve our goal, this piece will be divided into 3 additional sections. In the first one we’ll contrast the costs of manipulating an AM vs. a GM TWAP under different scenarios. In the next section, we’ll explore how each of these two methodologies fare in regards to price accuracy. Lastly, in the last section, we’ll briefly wrap up with some final conclusions.

Definitions

Before starting, it’s important to define what we mean by AM and GM TWAP.

The AM TWAP can be calculated over n blocks as the sum of the spot price on each block divided by n:

And the GM TWAP can be calculated over n blocks as the nth root of the product of the spot price on each block:

Where Pi denotes the spot price at block i.

Cost of Manipulation

Types of Manipulation Attacks

We’ve identified three types of oracle manipulation attacks:

  1. Artificially increasing the price of an asset used as collateral: in this scenario, the attacker deposits an asset X into the platform to use it as collateral and then proceeds to artificially increase the price of asset X to be able to borrow as much as possible of every other asset in the platform. For this attack to be profitable, the value of the assets borrowed needs to be higher than the collateral deposited by the attacker.
  2. Artificially decreasing the price of an asset to be borrowed: in this attack, the attacker also deposits an asset X into the platform as collateral. However, in contrast to the previous attack, in this scenario the attacker doesn’t manipulate the price of asset X but rather that of another asset Y. Specifically, the attacker artificially decreases the price of asset Y to be able to borrow as much of it as possible. As in the previous attack, for this attack to be profitable, the value of the assets borrowed needs to be higher than the collateral deposited by the attacker.
  3. Manipulating the price of an asset to cause a liquidation: this attack consists of manipulating the prices of certain assets in the platform to cause a position (or group of positions) to become liquidatable and, in turn, liquidating them to earn the liquidation bonus related to those positions. Notice that, depending on the position, the attack may consist of artificially increasing or decreasing the price of an asset. Specifically, given that a borrow position consists of collateral (deposits) and debt (borrowed) assets, the position can become liquidatable if either the price of the collateral drops relative to its debt or the price of its debt increases relative to the price of its collateral.

For the first two attacks, the cost of the attack can be defined as follows:

Notice that these two attacks differ from the third one in that they require the attacker to deposit collateral into the lending protocol. In both attacks, this collateral needs to be forfeited by the attacker in order to conduct the attack. That’s the reason why it needs to be included in the cost. Now, for the third attack the cost would be formulated as follows:

Within this section, we’ll focus specifically on the TWAP Manipulation Cost. The methodology we’ll use to determine this cost is the one pioneered by Euler (for GM TWAPs) and expanded by Delphi Labs for AM TWAPs. While thoroughly exploring this methodology is besides the scope of this piece, it’s worth understanding at a high level how it works (for a more in-depth explanation we recommend the papers linked above). The methodology for calculating the manipulation cost consists of 2 steps:

  1. Calculating the DEX target price: the price the attacker needs to take the DEX spot price to in order to manipulate the TWAP to a given target (over a certain number of blocks).
  2. Calculating the swap in/out amounts: the amount of assets needed to be swapped in the DEX to take the spot price to the target calculated in step 1. The difference between the value of the assets swapped in and the assets received is understood as the cost of the attack (this is an oversimplification, for a more thorough explanation please check the pieces linked above). The reason for this is that the methodology assumes that whenever an attacker manipulates the price on an underlying DEX, an arbitrageur (different from the attacker) will bring the price back to its real level. Thus, the attacker loses the difference in value between the assets swapped in and the assets received back.

It’s important to reiterate the main assumption this methodology makes: that there’s an active arbitrage ecosystem where, whenever the price of an asset diverges considerably from its real level, it will be quickly arbitraged back. In the event that there is inefficient arbitrage, the true cost of the attack would likely be lower than that calculated using this methodology.

Note: for both AM and GM TWAPs we’ll assume the same window (300 blocks) and the same underlying DEX liquidity.

Relative Cost Analysis

So, how does the AM fare against the GM in this regard? Let’s first explore the case where the attacker is trying to manipulate the price to the upside. The following figure shows the relationship between the manipulation cost using a GM and an AM TWAP. Specifically, the y axis (log-scale) is the ratio between the manipulation cost using GM TWAP and the manipulation cost of using AM TWAP (GM Cost / AM Cost). Thus, if the value of y is higher than 1, GM is costlier to manipulate than AM (the horizontal red line at the bottom of the figure marks y=1). The x axis is the number of blocks the attacker manipulates the price for. Lastly, each label (each color) represents a different manipulation target. For instance, a target of 25% means that the attacker is trying to manipulate the price to a level 25% higher than the spot price.

From the figure above, it’s worth pointing the following:

  • Under all scenarios considered, the GM is costlier to manipulate than the AM.
  • It is not only costlier, but significantly costlier, especially at the lower end of blocks manipulated.
  • As the number of blocks the price is manipulated for increases, the manipulation cost difference between the GM and AM tends to diminish.
  • The higher the manipulation target, the higher the difference between the GM and the AM.

Now let’s explore the opposite case: where the attacker is trying to manipulate the price to the downside. As with the figure above, the following figure shows the relationship between the manipulation cost using a GM and an AM TWAP. The y axis, x axis and labels mean the same as in the figure above. As can be seen, however, this figure looks completely different. Specifically, this figure seems to be less crowded, showing only one curve: the one associated with a -5% manipulation target (and only from block 16). Below we’ll explore why this is the case.

To explain what’s going on in the figure above, it’s worth recalling the previous explanation of how the cost of manipulating a TWAP is calculated. Briefly, the methodology consists of two steps: 1) calculating the DEX target price; and 2) calculating the swap in/out amounts.

So, how is this related to the figure above? Well, it turns out that given certain conditions, an attack is impossible to be performed when using an AM TWAP. Specifically, under certain scenarios, step 1 above returns a negative price for AM TWAPs. This result basically means that to manipulate the AM TWAP to a certain level, the attacker would need to take the DEX spot price to a negative value, which is impossible on an AMM.

To better understand why this is the case let’s explore an example:

Assume we’re trying to calculate the AM TWAP over 20 blocks of a given asset. The asset’s spot price over the last 20 blocks has been constant at 1. The following array represents the latest 20 spot prices, where the last position indicates the latest block:

At this point the AM TWAP would be:

Nothing surprising here. Now assume the next block an attacker tries to manipulate the price downwards as much as possible. Let’s assume the attacker is able to get the price to 0 (which is impossible on an AMM). Then the spot prices during the last 20 blocks would be:

And the AM TWAP would have been manipulated to:

What the above example shows is that, for a single block attack and 20 block window, the maximum manipulation achievable on an AM TWAP would be -5%. As said above, anything further would require making the spot price negative, which is impossible on an AMM.

Going back to the figure above, whenever there’s a missing curve (or a missing curve for some blocks) it’s because it was impossible to calculate the AM TWAP manipulation cost (given the DEX target price returned a negative value). Another way to look at it is that whenever there’s a missing curve above it’s because the cost of manipulating the AM TWAP was infinite. The only case where it was possible to calculate the cost in the figure above (light blue curve), it can be clearly seen that the AM TWAP is significantly costlier to manipulate than the GM TWAP (y < 1).

From the above analysis, it can be seen that the answer to which type of TWAP is more resistant to manipulation attacks is not as straightforward. Particularly, GM TWAPs are better for mitigating upwards price manipulation attacks while AM TWAPs are more resistant to downwards price manipulation attacks. To further explore this question, we’re going to move from a relative analysis to an absolute analysis of the costs associated with attacking each of these mechanisms. The objective is to look at the problem from another perspective. It may be the case that, even though in a relative sense one approach is better than the other, on an absolute basis the worse approach is still significantly robust.

Absolute Cost Analysis

As previously, let’s start with the upwards price manipulation case. The following figures show the cost of manipulating the 2 types of TWAP (AM on the left, GM on the right) over a given number of blocks. To generalize the results for any given pool depth, the manipulation cost (MC) is divided by the pool liquidity (PL) and the resulting ratio is shown in the y axis. In other words, the y axis shows the manipulation cost in relation to the underlying DEX pool liquidity. For example, for an AM TWAP, the cost of manipulating the TWAP 25% (blue curve) over the course of 1 block is 3.4, which indicates that the manipulation cost is equivalent to 3.4 times the underlying DEX liquidity. Thus, if the underlying liquidity is $1M, then the attack would cost $3,4M; if it’s $10M it would cost $34M and so on. Even though it’s impossible to determine with certainty the resources an attacker would be able to gather to conduct a manipulation attack, the costs of manipulating an AM TWAP don’t seem extraordinary, even for higher manipulation targets. Contrast these results to the ones in the figure to the right, which shows the costs associated with manipulating a GM TWAP. As expected from the analysis above, the GM TWAP is significantly costlier to manipulate (notice that the y axis is in log scale). For instance, a single block attack to manipulate the TWAP 25% would cost a whopping 172 trillion times the underlying pool’s liquidity (as opposed to 3.4 times for the AM).

Now let’s do the same exercise for downwards manipulation attacks. Here we’ll only provide the figure for the GM since we already know that the AM TWAP is not vulnerable to most considered scenarios (as explained above). The following figure shows the results of this exercise. As can be seen, the GM TWAP is significantly robust to downward price manipulation attacks, especially at the lower end of the number of blocks manipulated (x axis). For example, just to manipulate the TWAP -20% in 1 block, the attack would cost 172 trillion times the liquidity in the underlying pool. If performed in 2 and 3 blocks, the attack would cost 18,546,028 and 105,094 times the liquidity in the pool respectively. This means that, for instance, a 3 block attack on a pool with just $1M in liquidity would cost the attacker $105B.

As can be seen, though, the higher the number of blocks an attack is performed for, the lower the cost of the attack. For instance, considering the same manipulation target as above (-20% target) but over 10 blocks, the cost of the manipulation attack is reduced to ~130 times the liquidity in the pool (from 172 trillion times for a 1 block attack). However, as was pointed out by Euler, the longer an attack takes place for, the higher the risks for the attacker. In a similar vein, Torgin et al recently showed how 1 block attacks (in PoS (and PoW) Ethereum) could be performed with close to no risk for the attacker. Thus, when assessing TWAP robustness, short span manipulation attacks should be given a higher importance. Having said that, as Torgin et al correctly point out, more research is needed to better understand the likelihood of multiblock TWAP manipulation attacks.

Closing Thoughts on Manipulation Cost

In the sections above we’ve shown that the GM TWAP is significantly more robust than the AM TWAP for mitigating upwards price manipulation attacks. Not only is the GM TWAP robust in a relative sense but also in an absolute sense, especially at lower block span attacks, where the implied cost makes manipulation attacks impossible. This, however, wasn’t the case for the AM TWAP, which at lower block spans was manipulatable at reasonable (far from impossible) implied costs.

For downwards manipulation attacks, we showed that the AM TWAP is more robust than the GM TWAP. Having said that, we also pointed out that, while being less robust than the AM TWAP, the GM TWAP is significantly robust to downward manipulation attacks by itself, especially at lower block span attacks.

Given the above, we can conclude that the GM TWAP is generally a better option when it comes to mitigating oracle manipulation attacks.

One last aspect worth highlighting that reinforces the above conclusion is related to the potential magnitude of the three different types of attacks covered at the beginning of this section. Attack 1 (upwards price manipulation) can have systemic and catastrophic consequences for a protocol, as an attacker could potentially be able to steal all assets in the platform (with the exception of the collateral asset the attacker uses). Attack 2 can have systemic consequences, although it’s likely to have a more limited impact than Attack 1 since the attacker would only be able to steal the assets of one single pool (not every other pool). Thus, the damage the attack causes on the protocol will depend on the size of the attacked pool. Lastly, attack 3 is the least problematic since it cannot have systemic consequences nor does it necessarily lead to insolvencies for the protocol (and it’s also hard for the attacker to guarantee he will be the liquidator of the position). Thus, it follows that mitigating attack #1 should have the highest priority, followed by attack 2 and lastly attack 3. As covered above, the GM TWAP is significantly more robust to attack 1 than the AM TWAP (upwards manipulation) while also being robust to attacks 2 and 3.

Price Accuracy

In this section we’ll compare the GM and AM TWAPs in another fundamental dimension: accuracy, understood as how closely the TWAP follows the spot price. While it’s obvious why accuracy is important for an oracle (it’s the raison d’être of an oracle), its relevance within the context of lending protocols goes far beyond what’s evident at a surface level. Thus, in addition to contrasting how both GM and AM TWAPs fare in this regard, we’ll be shedding light on some of the non-obvious implications of oracle accuracy for lending protocols.

This section will be divided into two subsections. In the first one we’ll compare the performance of both AM and GM TWAPs with regards to accuracy under different scenarios. In the second one, we’ll expand on why oracle accuracy is of critical importance to DeFi lending protocols.

Accuracy Performance

We’ll compare the accuracy of GM and AM TWAPs under 2 sets of scenarios:

  1. Spot price increases linearly over a given number of blocks.
  2. Spot price decreases linearly over a given number of blocks.

While these scenarios are obviously non-exhaustive, they help paint a broad picture of the underlying dynamics at play here.

Note: For all scenarios, we’ll use the same TWAP window: 300 blocks (or 30 minutes assuming 6 second blocks).

Let’s start with scenario 1. For this scenario we’ll assume the price increases linearly by 100% over the course of 300 blocks. In the figure below, this increase happens from blocks 400 to 700. As can be seen, as soon as the spot price starts increasing, both AM and GM TWAPs start increasing as well, but at a lower pace. In other words, even though the TWAPs start trending towards the spot, a lag or a difference between both TWAPs and the spot price starts emerging. Additionally, it’s worth noting that both TWAPs seem to follow a very similar trajectory.

The next figure shows how the difference between the spot price and both TWAPs evolves over time. Notice that the spot price (green line) is plotted on the left y axis, while the difference between the spot price and the TWAPs (blue and orange curves) is shown on the right. Lastly, the red line plots the difference between the GM and AM differences themselves; in other words, it shows the accuracy performance difference between the 2 evaluated TWAP types. Note: the percentage difference in the right indicates how higher the spot price is from the TWAP at that block. For example, a 10% difference indicates that, at that block, the spot price is 10% higher than the TWAP.

It’s important to highlight 2 important aspects from this figure:

  1. Under this scenario both TWAPs become highly inaccurate during a large portion of blocks. For instance, the difference between the spot price and the AM TWAP is above 10% in 388 blocks. For the GM TWAP this happens in 393 blocks. Furthermore, for both TWAPs the difference gets significantly high, peaking at around ~40%. This dynamic has important implications for lending protocols, which will be explored in the next subsection.
  2. While the AM TWAP is slightly more accurate than the GM TWAP, both perform similarly, as shown by the red curve below. Specifically, the difference between the two TWAPs (difference in accuracy) never goes above 5%.

In the next figure we’ll generalize the above results (particularly the performance difference between the two TWAPs) for different price increase scenarios. Specifically, we plotted the difference in performance for linear price increase scenarios from 25 to 200% over a period of 300 blocks (the label of each curve indicates the price increase). In a similar fashion to the preceding figures, the price increases from blocks 400 to 700. As can be seen, the higher the price increase, the higher the performance difference between the two TWAPs. While even at relatively high price increases the difference is small (lower than 3% for a 100% increase), at extreme enough price trajectories the performance difference starts becoming significant.

Now let’s explore scenario 2. For this scenario we’ll assume the price halves linearly over the course of 300 blocks. All other details (aside from price trajectory) are the same as in the preceding figures. The next figure shows the results of this exercise. The main point to highlight here is that, as opposed to the previous scenario, the GM tracks the spot price better than the AM (although slightly, as in scenario 1).

The next figure shows how the difference between the spot price and both TWAPs evolves over time. Given that the spot price is lower than the TWAPs when the price is decreasing, here the difference indicates how much higher the TWAP is from the spot price at that block. For example, a 10% difference indicates that, at that block, the TWAP is 10% higher than the spot price. Two conclusions (similar to those of scenario 1) can be drawn from this figure:

  1. The TWAPs become highly inaccurate during a large portion of the blocks.
  2. While the GM TWAP is slightly more accurate, both tend to perform similarly.

In the next figure we’ll generalize the above results (particularly the performance difference between the two TWAPs) for different price trajectories. Specifically, we plotted the difference in performance for linear price decreases from -20 to -67% (the inverse of the price trajectories presented in scenario 1) over a period of 300 blocks. Predictably, the conclusions are similar to those found in scenario 1: 1) the larger the price decrease, the higher the performance difference between the two TWAPs; and 2) although at large price decreases, the performance difference tends to be small, at extreme price trajectories it starts becoming significant.

As mentioned previously, the above scenarios are far from being exhaustive, as the possible price trajectories of any given asset are infinite. Having said that, we think the scenarios explored provide a reasonable high-level understanding of the dynamics at play here and, specifically, of the performance difference between the two studied types of TWAP. Further research could extend this analysis to other price trajectories, including real spot price data from DEXes and other edge cases not considered here.

How Price Accuracy Affects Liquidations

The implications of oracle accuracy for lending protocols cannot be overstated. Specifically, as will be explored below, a large divergence between the spot price and the oracle (the TWAP in this case) can lead to liquidations malfunctioning (either happening at an untimely manner or not happening at all) and, in turn, to protocol insolvency.

To understand how oracle inaccuracy can have a negative impact on lending protocols, let’s go over an example. We’ll assume that this is a health factor-based lending protocol (as the majority in DeFi are) where whenever a position’s health factor falls below 1, it becomes liquidatable.

Additionally, we’ll assume this is a fixed liquidation bonus protocol (again as most in DeFi). This means that whenever a liquidator liquidates a position, the liquidator will repay the debt of the position and receive back a portion of the user’s collateral worth the debt repaid, plus the liquidation bonus. For this example we’ll assume a 10% fixed liquidation bonus.

Having set the context, let’s assume we have a simple debt position in this protocol with the following characteristics:

  • Collateral: 1 token of asset X worth $180 USD
  • LTV of collateral asset: 70%
  • Debt: 1 token of asset Y worth $100 USD

Now, let’s model what happens to this position when the price of the collateral starts falling linearly over time, while the price of the debt remains constant. Specifically, we’ll simulate a scenario where the price of the collateral halves linearly over the course of 300 blocks, starting from block 400. In the next figure we can see the spot price and TWAP evolution of the collateral over time. Nothing particularly interesting to highlight here but nevertheless it’s necessary context for the next figures.

The next figure shows the evolution of the health factor and the collateralization ratio over time. From this figure, it’s worth highlighting two important things.

First, there are two health factors, one calculated using the real spot price of the assets (Spot HF) and the other using the GM TWAP. This is critically important because, even though the real health of the position is determined by the former, the latter is what’s available to the protocol and what ultimately determines when (and how) liquidations can happen. In other words, the only health factor and price the protocol “sees” are those determined by the GM TWAP.

The main implication of this dynamic is that the position becomes liquidatable significantly later than it should. Concretely, while the position should become liquidatable when the real HF (Spot HF) falls below 1, which happens at block 524 (where the horizontal red line crosses the Spot HF line), it only becomes liquidatable when the GM TWAP HF goes below 1, which happens at block 664; 140 blocks late. This has important negative implications on liquidation profitability, which will be further explored below.

The second aspect worth highlighting from the figure below is that, at some point, if the position isn’t liquidated in time, the collateralization ratio (value of assets over value of debt) falls below 1. When (and if) that happens, the position becomes effectively bankrupt and the protocol starts accruing bad debt.

Let’s now focus on liquidation profitability. For this analysis, we’ll calculate the liquidation profit at block i at as follows:

Where the value of the collateral received should be equal to the sum of the value of the debt repaid and the liquidation bonus. For liquidations to be profitable, the value of the collateral received should be higher than the debt repaid.

However, notice the following nuance that complicates this problem. At any given point where the position is liquidatable and the GM TWAP is higher than the spot price, the protocol will value the user’s collateral higher than what it’s really worth. This will translate into the protocol offering less collateral than it should to liquidators trying to liquidate a position, which can in turn lead to liquidations not happening.

Let’s explore this with a concrete example. Specifically, we’ll calculate the profitability of a liquidation happening at block 664 in the figure above, the first block the position becomes liquidatable (when the GM TWAP HF first drops below 1). At that block, the GM TWAP of the collateral is ~$143 while the real spot price is $101. So, at that block, the business case for a liquidator trying to liquidate that position will look as follows*:

  1. The liquidator would repay $100 worth of the user’s debt.
  2. The liquidator should receive $110 (value of debt repaid + 10% liquidation bonus) of the user’s collateral back. At a real price of $101 per token, the liquidator should receive 1.09 tokens in return for the liquidation.
  3. However, at that block the protocol is overvaluing the collateral at $143 (the GM TWAP) instead of $101. Thus, the protocol calculates the amount of tokens to be granted to the liquidator at the inflated GM TWAP, which results in offering only 0.77 tokens in return for the liquidation.
  4. The real value of the 0.77 tokens is ~$78, making the liquidation unprofitable: the liquidator would repay $100 of debt and receive just ~$78 of collateral back, which would imply a $22 loss (or -22% profit as defined above). Thus, at this point liquidations will not happen.

* For simplicity, we assume a 100% close factor, which means that liquidations need to repay 100% of the user’s debt.

In the following figure, we expand the above calculation (liquidation profitability) over the course of the whole example, starting from the first block the position becomes liquidatable. As can be seen, from the moment the position becomes liquidatable until the end of the example, the liquidation profitability is negative. This means that this position won’t be liquidated, leading to the collateralization ratio falling below 1 and making the position bankrupt. The reason this happens is that, from the moment the position becomes liquidatable, the difference between the GM TWAP and the spot price is already higher than the liquidation bonus, thus making liquidations unprofitable. Notice that, as the divergence between the TWAP and the spot price starts decreasing, the profitability starts improving (although it never becomes positive). Lastly, the reason profitability stays constant at the end is that the user’s collateral is limited and at that point the liquidator is already receiving 100% of the user’s collateral back.

While the above example represents an unlikely and extreme scenario (given the magnitude of the drop and its linear nature), it helps illustrate the point: TWAP (and oracle) accuracy is critical to the health of lending protocols. With this section, though, our intention isn’t to discourage the use of TWAPs within lending protocols but, to the contrary, to shed light on their underlying, core mechanics and promote their adequate use.

Lastly, even though exploring mitigation strategies is outside the scope of this piece, it’s worth noting that there are several levers lending protocols can use to mitigate scenarios like the above materializing. These levers include tweaking lending related risk parameters such as the LTV and liquidation bonus, modifying TWAP specific parameters such as its window and employing different liquidation mechanisms, among others. As with most solutions in DeFi, though, none of these represent silver bullets but rather tradeoffs where some stakeholders tend to benefit at the expense of others. We encourage more research into each of these areas to help further illuminate the art of using TWAPs within lending protocols.

Conclusion

Throughout this piece, we compared the performance of AM and GM TWAPs in two dimensions: cost of manipulation and price accuracy. With regards to the former, we argued why GM TWAPs are a better alternative than AM TWAPs. Particularly, we showed that GM TWAPs are significantly more robust to upwards price manipulation attacks and, while they are less robust to downwards price attacks than AM TWAPs, they are still considerably costly to manipulate.

In terms of price accuracy, we showed how both types of TWAP perform similarly under different scenarios. While the GM TWAP tends to perform slightly better when the spot price of the asset is declining, the AM TWAP tends to slightly outperform in the opposite scenario. Thus, in terms of accuracy, there’s no strong argument for choosing one over the other.

All in all, considering the GM TWAP’s outperformance in regards to manipulation cost and the similar performance between both TWAPs in terms of accuracy, we can conclude that the GM TWAP is a better alternative for most generalized DeFi lending protocols. Having said that, as was explored in the accuracy section, the correct use of TWAPs within lending protocols requires a deep understanding of not just the mechanics of the chosen oracle, but also how it interacts with the different pieces of the protocol, including its risk parameters and liquidations mechanism. While we don’t discourage the use of TWAPs within DeFi, we recommend deep care when incorporating them.

Lastly, as highlighted throughout this piece, there’s substantially more research to be done within this field. If you’re interested in collaborating to deepen the understanding of TWAPs within DeFi, please reach out!

Special thanks to Michael Bentley, Yaron Velner and Tatiana Pashinskaya for their valuable feedback for this piece!

Disclaimer

This article is for educational purposes only; nothing herein is intended to be relied upon as advice, promises, representations, warranties or otherwise.

--

--

Delphi Labs
Delphi Labs

Written by Delphi Labs

The next evolution of incubation leveraging our hivemind of expertise at @delphi_digital