Add marginal price capability and update integration tests

Balancer now passes the test
Some misc aesthetics
This commit is contained in:
czanella
2024-07-18 16:12:50 +01:00
parent ab3723f29b
commit 772566c590
3 changed files with 32 additions and 20 deletions

View File

@@ -188,11 +188,10 @@ contract BalancerV2SwapAdapter is ISwapAdapter {
override
returns (Capability[] memory capabilities)
{
capabilities = new Capability[](4);
capabilities = new Capability[](3);
capabilities[0] = Capability.SellOrder;
capabilities[1] = Capability.BuyOrder;
capabilities[2] = Capability.PriceFunction;
capabilities[3] = Capability.HardLimits;
}
function getTokens(bytes32 poolId)

View File

@@ -33,7 +33,11 @@ interface ISwapAdapterTypes {
ScaledPrices,
// Indicates that if we try to go over the sell limits, the pool will
// revert (optional)
HardLimits
HardLimits,
// Indicates whether the pool's price function can be called with
// amountIn=0 to return the
// current price (optional)
MarginalPrice
}
/// @dev Representation used for rational numbers such as prices.

View File

@@ -11,7 +11,7 @@ contract AdapterTest is Test, ISwapAdapterTypes {
using FractionMath for Fraction;
uint256 constant pricePrecision = 10e24;
string[] public stringPctgs = ["0%", "0.01%", "50%", "100%"];
string[] public stringPctgs = ["0%", "0.1%", "50%", "100%"];
// @notice Test the behavior of a swap adapter for a list of pools
// @dev Computes limits, prices, and swaps on the pools on both directions
@@ -29,6 +29,7 @@ contract AdapterTest is Test, ISwapAdapterTypes {
for (uint256 i = 0; i < poolIds.length; i++) {
address[] memory tokens = adapter.getTokens(poolIds[i]);
IERC20(tokens[0]).approve(address(adapter), type(uint256).max);
IERC20(tokens[1]).approve(address(adapter), type(uint256).max);
testPricesForPair(
adapter, poolIds[i], tokens[0], tokens[1], hasPriceImpact
@@ -59,7 +60,13 @@ contract AdapterTest is Test, ISwapAdapterTypes {
tokenOut,
sellLimit
);
uint256[] memory amounts = calculateTestAmounts(sellLimit);
bool hasMarginalPrices = hasCapability(
adapter.getCapabilities(poolId, tokenIn, tokenOut),
Capability.MarginalPrice
);
uint256[] memory amounts =
calculateTestAmounts(sellLimit, hasMarginalPrices);
Fraction[] memory prices =
adapter.price(poolId, tokenIn, tokenOut, amounts);
assertGt(
@@ -78,17 +85,15 @@ contract AdapterTest is Test, ISwapAdapterTypes {
assertGt(prices[0].denominator, 0, "Denominator shouldn't be 0");
Trade memory trade;
deal(tokenIn, address(this), 2 * amounts[amounts.length - 1]);
deal(tokenIn, address(this), 5 * amounts[amounts.length - 1]);
for (uint256 j = 1; j < amounts.length; j++) {
console2.log(
"TEST: Testing behavior for price at %s of limit: %d",
"TEST: Testing behavior for price at %s of limit.",
stringPctgs[j],
amounts[j]
);
uint256 priceAtAmount = fractionToInt(prices[j]);
assertGt(prices[j].numerator, 0, "Nominator shouldn't be 0");
assertGt(prices[j].denominator, 0, "Denominator shouldn't be 0");
console2.log("TEST: Swapping %d of %s", amounts[j], tokenIn);
trade = adapter.swap(
@@ -97,12 +102,12 @@ contract AdapterTest is Test, ISwapAdapterTypes {
uint256 executedPrice =
trade.calculatedAmount * pricePrecision / amounts[j];
uint256 priceAfterSwap = fractionToInt(trade.price);
console2.log("TEST: Pool price: %d", priceAtAmount);
console2.log("TEST: Executed price: %d", executedPrice);
console2.log("TEST: Price after swap: %d", priceAfterSwap);
console2.log("TEST: - Pool price: %d", priceAtAmount);
console2.log("TEST: - Executed price: %d", executedPrice);
console2.log("TEST: - Price after swap: %d", priceAfterSwap);
if (hasPriceImpact) {
assertGt(
assertGe(
priceAtAmount,
executedPrice,
"Price should be greated than executed price."
@@ -121,17 +126,17 @@ contract AdapterTest is Test, ISwapAdapterTypes {
assertGe(
priceAtAmount,
executedPrice,
"Price should be greated than executed price."
"Price should be greater or equal to executed price."
);
assertGe(
executedPrice,
priceAfterSwap,
"Executed price should be greater than price after swap."
"Executed price should be or equal to price after swap."
);
assertGe(
priceAtAmount,
priceAfterSwap,
"Price should be greated than price after swap."
"Price should be or equal to price after swap."
);
}
}
@@ -151,6 +156,8 @@ contract AdapterTest is Test, ISwapAdapterTypes {
adapter, poolId, tokenIn, tokenOut, amountAboveLimit
);
}
console2.log("TEST: All tests passed.");
}
function testRevertAboveLimit(
@@ -165,7 +172,9 @@ contract AdapterTest is Test, ISwapAdapterTypes {
aboveLimitArray[0] = amountAboveLimit;
try adapter.price(poolId, tokenIn, tokenOut, aboveLimitArray) {
revert("Pool shouldn't be fetch prices above the sell limit");
revert(
"Pool shouldn't be able to fetch prices above the sell limit"
);
} catch Error(string memory s) {
console2.log(
"TEST: Expected error when fetching price above limit: %s", s
@@ -199,14 +208,14 @@ contract AdapterTest is Test, ISwapAdapterTypes {
);
}
function calculateTestAmounts(uint256 limit)
function calculateTestAmounts(uint256 limit, bool hasMarginalPrices)
internal
pure
returns (uint256[] memory)
{
uint256[] memory amounts = new uint256[](4);
amounts[0] = 0;
amounts[1] = limit / 10000;
amounts[0] = hasMarginalPrices ? 0 : limit / 10000;
amounts[1] = limit / 1000;
amounts[2] = limit / 2;
amounts[3] = limit;
return amounts;