Finally compileable again

This commit is contained in:
2026-06-15 20:37:42 +02:00
parent a65ac072e7
commit 125255cdf7
11 changed files with 108 additions and 144 deletions
@@ -4,10 +4,9 @@ import com.r35157.libs.basic.Pair;
import com.fanitas.evelyn.raydium.RaydiumLiquidityPoolPositionConcentrated; import com.fanitas.evelyn.raydium.RaydiumLiquidityPoolPositionConcentrated;
import com.fanitas.evelyn.core.DesiredPositionCalculator; import com.fanitas.evelyn.core.DesiredPositionCalculator;
import com.r35157.libs.valuetypes.basic.AssetPrice; import com.r35157.libs.valuetypes.basic.*;
import com.r35157.libs.valuetypes.basic.CurrencyType;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
@@ -43,7 +42,7 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
); );
ΩSyrupPriceΩ lastLessThanOrEqual = intervalEnds.get(indexOfPositionWithAnEndPriceBeforePositionWithCurrentPrice); ΩSyrupPriceΩ lastLessThanOrEqual = intervalEnds.get(indexOfPositionWithAnEndPriceBeforePositionWithCurrentPrice);
HashMap<ΩRaydiumLiquidityPoolPositionIdΩ, MoneyAmount> desiredPositions = new HashMap<>(); HashMap<ΩRaydiumLiquidityPoolPositionIdΩ, Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ>> desiredPositions = new HashMap<>();
boolean beforeNonZeroPos = true; boolean beforeNonZeroPos = true;
@@ -68,18 +67,8 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
break; break;
} }
ΩSolanaAmountΩ desiredPositionSizeSolana = new MoneyAmount(
desiredSolanaPosSize,
totalReadyAmountMintA.currencyType()
);
ΩSyrupAmountΩ desiredPositionSizeSyrup = new MoneyAmount(
desiredSyrupPosSize,
totalReadyAmountMintB.currencyType()
);
Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> desiredPositionSizes = Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> desiredPositionSizes =
new Pair<>(desiredPositionSizeSolana, desiredPositionSizeSyrup); new Pair<>(desiredSolanaPosSize, desiredSyrupPosSize);
RaydiumLiquidityPoolPositionConcentrated position = getPositionByStartPriceA(iStart); RaydiumLiquidityPoolPositionConcentrated position = getPositionByStartPriceA(iStart);
// TODO: What if null is return above? // TODO: What if null is return above?
@@ -121,7 +110,7 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
@Override @Override
public Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> calculateLockedSums(ΩSyrupPriceΩ currentPrice) { public Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> calculateLockedSums(ΩSyrupPriceΩ currentPrice) {
List<ΩPriceΩ> ascendingPrices = getSortedPositionIntervalFromValues(liquidityProviderPositions); List<ΩSyrupPriceΩ> ascendingPrices = getSortedPositionIntervalFromValues(liquidityProviderPositions);
ΩAmountΩ sumA = ZERO; ΩAmountΩ sumA = ZERO;
ΩAmountΩ sumB = ZERO; ΩAmountΩ sumB = ZERO;
@@ -129,9 +118,9 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
CurrencyType ctA = null; CurrencyType ctA = null;
CurrencyType ctB = null; CurrencyType ctB = null;
int index = lookupIndexOfFirstGreaterThanOrEqual(ascendingPrices, currentPrice.price()); int index = lookupIndexOfFirstGreaterThanOrEqual(ascendingPrices, currentPrice);
if(index >= 0) { if(index >= 0) {
ΩPriceΩ startPriceOfStartPos = ascendingPrices.get(index); AssetPrice startPriceOfStartPos = ascendingPrices.get(index);
for (RaydiumLiquidityPoolPositionConcentrated position : liquidityProviderPositions.values()) { for (RaydiumLiquidityPoolPositionConcentrated position : liquidityProviderPositions.values()) {
if (position.priceRange().from().compareTo(startPriceOfStartPos) >= 0) { if (position.priceRange().from().compareTo(startPriceOfStartPos) >= 0) {
@@ -157,15 +146,15 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
ΩSyrupAmountΩ inactiveInAccountMintB, ΩSyrupAmountΩ inactiveInAccountMintB,
ΩSyrupAmountΩ reservedForBurnMintB ΩSyrupAmountΩ reservedForBurnMintB
) { ) {
List<ΩPriceΩ> ascendingValues = getSortedPositionIntervalFromValues(liquidityProviderPositions); List<AssetPrice> ascendingValues = getSortedPositionIntervalFromValues(liquidityProviderPositions);
ΩAmountΩ redistSumA = ZERO; ΩAmountΩ redistSumA = ZERO;
ΩAmountΩ redistSumB = ZERO; ΩAmountΩ redistSumB = ZERO;
CurrencyType ctA = null; CurrencyType ctA = null;
CurrencyType ctB = null; CurrencyType ctB = null;
int index = lookupIndexOfLastLessThan(ascendingValues, currentPrice.price()); int index = lookupIndexOfLastLessThan(ascendingValues, currentPrice);
if(index >= 0) { if(index >= 0) {
ΩPriceΩ startPriceOfStartPos = ascendingValues.get(index); AssetPrice startPriceOfStartPos = ascendingValues.get(index);
for (RaydiumLiquidityPoolPositionConcentrated position : liquidityProviderPositions.values()) { for (RaydiumLiquidityPoolPositionConcentrated position : liquidityProviderPositions.values()) {
if (position.priceRange().from().compareTo(startPriceOfStartPos) <= 0) { if (position.priceRange().from().compareTo(startPriceOfStartPos) <= 0) {
@@ -205,8 +194,8 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
return a.subtract(b.amount()); return a.subtract(b.amount());
} }
private RaydiumLiquidityPoolPositionConcentrated getPositionByStartPriceA(@NotNull ΩPriceΩ startPriceA) { private @Nullable RaydiumLiquidityPoolPositionConcentrated getPositionByStartPriceA(@NotNull AssetPrice startPriceA) {
for (RaydiumLiquidityPoolPositionConcentrated candidate : liquidityProviderPositions.values()) { for(RaydiumLiquidityPoolPositionConcentrated candidate : liquidityProviderPositions.values()) {
if (candidate.priceRange().from().compareTo(startPriceA) == 0) { if (candidate.priceRange().from().compareTo(startPriceA) == 0) {
return candidate; return candidate;
} }
@@ -222,47 +211,51 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
@NotNull ΩSyrupPriceΩ intervalPriceTo, @NotNull ΩSyrupPriceΩ intervalPriceTo,
@NotNull ΩSyrupPriceΩ lookupPrice @NotNull ΩSyrupPriceΩ lookupPrice
) { ) {
ΩPriceΩ curveStartPrice = currentPrice.multiply( ΩPriceΩ curveStartPrice = currentPrice.price().multiply(
ONE.subtract(curveWidth, MC), ONE.subtract(curveWidth, MC),
MC MC
); );
boolean intervalIsCompletelyBeforeCurve = boolean intervalIsCompletelyBeforeCurve =
intervalPriceTo.compareTo(curveStartPrice) <= 0; intervalPriceTo.price().compareTo(curveStartPrice) <= 0;
boolean intervalIsCompletelyAfterLookupLimit = boolean intervalIsCompletelyAfterLookupLimit =
intervalPriceFrom.compareTo(lookupPrice) >= 0; intervalPriceFrom.price().compareTo(lookupPrice.price()) >= 0;
if (intervalIsCompletelyBeforeCurve || intervalIsCompletelyAfterLookupLimit) { if (intervalIsCompletelyBeforeCurve || intervalIsCompletelyAfterLookupLimit) {
return ZERO; return new ΩSyrupAmountΩ(ZERO, WellKnownCurrencyTypes.SYRUPUSDC.getCurrencyType());
} }
ΩPriceΩ effectiveIntervalFrom = max(intervalPriceFrom, curveStartPrice); ΩPriceΩ effectiveIntervalFrom = max(intervalPriceFrom.price(), curveStartPrice);
ΩPriceΩ effectiveIntervalTo = min(intervalPriceTo, lookupPrice); ΩPriceΩ effectiveIntervalTo = min(intervalPriceTo.price(), lookupPrice.price());
BigDecimal sigma = currentPrice.multiply(curveWidth, MC) BigDecimal sigma = currentPrice.price().multiply(curveWidth, MC)
.divide(THREE, MC); .divide(THREE, MC);
BigDecimal sqrtTwo = sqrt(TWO, MC); BigDecimal sqrtTwo = sqrt(TWO, MC);
BigDecimal denominator = sigma.multiply(sqrtTwo, MC); BigDecimal denominator = sigma.multiply(sqrtTwo, MC);
ΩPriceΩ normalizedEffectiveTo = effectiveIntervalTo.subtract(currentPrice, MC) ΩPriceΩ normalizedEffectiveTo = effectiveIntervalTo.subtract(currentPrice.price(), MC)
.divide(denominator, MC); .divide(denominator, MC);
ΩPriceΩ normalizedEffectiveFrom = effectiveIntervalFrom.subtract(currentPrice, MC) ΩPriceΩ normalizedEffectiveFrom = effectiveIntervalFrom.subtract(currentPrice.price(), MC)
.divide(denominator, MC); .divide(denominator, MC);
ΩPriceΩ normalizedLookupPrice = lookupPrice.subtract(currentPrice, MC) ΩPriceΩ normalizedLookupPrice = lookupPrice.price().subtract(currentPrice.price(), MC)
.divide(denominator, MC); .divide(denominator, MC);
ΩPriceΩ normalizedCurveStart = curveStartPrice.subtract(currentPrice, MC) ΩPriceΩ normalizedCurveStart = curveStartPrice.subtract(currentPrice.price(), MC)
.divide(denominator, MC); .divide(denominator, MC);
BigDecimal intervalWeight = new BigDecimal(erf(normalizedEffectiveTo) - erf(normalizedEffectiveFrom)); BigDecimal intervalWeight = new BigDecimal(erf(normalizedEffectiveTo) - erf(normalizedEffectiveFrom));
BigDecimal totalWeightInActiveCurve = new BigDecimal(erf(normalizedLookupPrice) - erf(normalizedCurveStart)); BigDecimal totalWeightInActiveCurve = new BigDecimal(erf(normalizedLookupPrice) - erf(normalizedCurveStart));
ΩAmountΩ dps = totalSyrupToDistribution.multiply(intervalWeight, MC) ΩSyrupAmountΩ dps = new ΩSyrupAmountΩ(
.divide(totalWeightInActiveCurve, MC); totalSyrupToDistribution.amount()
.multiply(intervalWeight, MC)
.divide(totalWeightInActiveCurve, MC),
WellKnownCurrencyTypes.SYRUPUSDC.getCurrencyType()
);
return dps; return dps;
} }
@@ -274,8 +267,8 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
int index = -1; int index = -1;
for (int i = ascendingPrices.size() - 1; i >= 0; i--) { for (int i = ascendingPrices.size() - 1; i >= 0; i--) {
BigDecimal p = ascendingPrices.get(i); ΩPriceΩ p = ascendingPrices.get(i).price();
if (p.compareTo(searchPrice) <= 0) { if (p.compareTo(searchPrice.price()) <= 0) {
break; break;
} else { } else {
index = i; index = i;
@@ -298,8 +291,8 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
int index = -1; int index = -1;
for (int i = ascendingPrices.size() - 1; i >= 0; i--) { for (int i = ascendingPrices.size() - 1; i >= 0; i--) {
BigDecimal p = ascendingPrices.get(i); ΩPriceΩ p = ascendingPrices.get(i).price();
if (p.compareTo(searchPrice) <= 0) { if (p.compareTo(searchPrice.price()) <= 0) {
break; break;
} else { } else {
index = i; index = i;
@@ -321,8 +314,8 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
) { ) {
int index = -1; int index = -1;
for (int i = 0; i < ascendingPrices.size() - 1; i++) { for (int i = 0; i < ascendingPrices.size() - 1; i++) {
ΩSyrupPriceΩ p = ascendingPrices.get(i); ΩPriceΩ p = ascendingPrices.get(i).price();
if (p.compareTo(searchPrice) < 0) { if (p.compareTo(searchPrice.price()) < 0) {
index = i - 1; index = i - 1;
} else { } else {
break; break;
@@ -339,8 +332,8 @@ public class DesiredPositionCalculatorImpl implements DesiredPositionCalculator
int index = -1; int index = -1;
for (int i = 0; i < ascendingPrices.size() - 1; i++) { for (int i = 0; i < ascendingPrices.size() - 1; i++) {
ΩPriceΩ p = ascendingPrices.get(i); ΩPriceΩ p = ascendingPrices.get(i).price();
if (p.compareTo(searchPrice) < 0) { if (p.compareTo(searchPrice.price()) < 0) {
index = i - 1; index = i - 1;
} else { } else {
break; break;
@@ -10,9 +10,7 @@ import com.r35157.libs.raydium.RaydiumLiquidityPoolPrice;
import com.r35157.libs.solana.SPLTokenHolding; import com.r35157.libs.solana.SPLTokenHolding;
import com.r35157.libs.solana.SolanaBlockChain; import com.r35157.libs.solana.SolanaBlockChain;
import com.r35157.libs.solana.SolanaConstants; import com.r35157.libs.solana.SolanaConstants;
import com.r35157.libs.solana.valuetypes.WellKnownCurrencyTypes;
import com.r35157.libs.valuetypes.basic.AssetPrice; import com.r35157.libs.valuetypes.basic.AssetPrice;
import com.r35157.libs.valuetypes.basic.CurrencyType;
import com.r35157.libs.valuetypes.basic.MoneyAmount; import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.libs.valuetypes.basic.TradingPair; import com.r35157.libs.valuetypes.basic.TradingPair;
@@ -22,8 +20,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import static com.r35157.libs.solana.valuetypes.WellKnownCurrencyTypes.SOLANA; import static com.r35157.libs.valuetypes.basic.WellKnownCurrencyTypes.SOLANA;
import static com.r35157.libs.solana.valuetypes.WellKnownCurrencyTypes.SYRUPUSDC; import static com.r35157.libs.valuetypes.basic.WellKnownCurrencyTypes.SYRUPUSDC;
import static com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram.SPL_TOKEN_PROGRAM; import static com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram.SPL_TOKEN_PROGRAM;
import static com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram.TOKEN_2022_PROGRAM; import static com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram.TOKEN_2022_PROGRAM;
@@ -102,7 +100,6 @@ public class EvelynImpl implements Evelyn {
ΩSPLMintAddressΩ syrupUSDCMintAddr = SolanaConstants.SPL_TOKEN_SYRUPUSDC; ΩSPLMintAddressΩ syrupUSDCMintAddr = SolanaConstants.SPL_TOKEN_SYRUPUSDC;
AssetPrice currentPriceFromRaydium; AssetPrice currentPriceFromRaydium;
ΩSyrupPriceΩ currentPriceFromChain;
SPLTokenHolding syrupHolding = getSPLHolding(solanaAddressForEvelynIOU, syrupUSDCMintAddr); SPLTokenHolding syrupHolding = getSPLHolding(solanaAddressForEvelynIOU, syrupUSDCMintAddr);
ΩSyrupAmountΩ inactiveInAccountSyrup = new ΩSyrupAmountΩ( ΩSyrupAmountΩ inactiveInAccountSyrup = new ΩSyrupAmountΩ(
@@ -124,16 +121,9 @@ public class EvelynImpl implements Evelyn {
); );
concentratedResult = cFuture.get(); concentratedResult = cFuture.get();
currentPriceFromRaydium = concentratedResult.price();
currentPriceFromRaydium = new AssetPrice(
concentratedResult.price(),
tpSolSyrup
);
} }
ΩPriceΩ price = raydium.fetchPoolPrice(state.getRaydiumPoolId());
currentPriceFromChain = new AssetPrice(price, tpSolSyrup);
System.out.println("Iteration interval: " + (state.getIterationInterval() / 1000) + " secs"); System.out.println("Iteration interval: " + (state.getIterationInterval() / 1000) + " secs");
System.out.println("Solana balances:"); System.out.println("Solana balances:");
@@ -144,7 +134,7 @@ public class EvelynImpl implements Evelyn {
System.out.println("SYRUP owned by Evelyn: " + state.getSyrupOwnedByEvelyn().amount()); System.out.println("SYRUP owned by Evelyn: " + state.getSyrupOwnedByEvelyn().amount());
System.out.println("SYRUP inactive on Evelyn account: " + inactiveInAccountSyrup); System.out.println("SYRUP inactive on Evelyn account: " + inactiveInAccountSyrup);
System.out.println("Pool price: " + currentPriceFromRaydium + "/" + currentPriceFromChain); System.out.println("Pool price: " + currentPriceFromRaydium);
Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> totalDistributedSums = Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> totalDistributedSums =
desiredPositionCalculator.calculateTotalDistributedSums(); desiredPositionCalculator.calculateTotalDistributedSums();
@@ -154,7 +144,7 @@ public class EvelynImpl implements Evelyn {
+ " / " + totalDistributedSumSyrup); + " / " + totalDistributedSumSyrup);
Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> amountsLocked = Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> amountsLocked =
desiredPositionCalculator.calculateLockedSums(currentPriceFromChain); desiredPositionCalculator.calculateLockedSums(currentPriceFromRaydium);
ΩSolanaAmountΩ amountLockedSolana = amountsLocked.left(); ΩSolanaAmountΩ amountLockedSolana = amountsLocked.left();
ΩSyrupAmountΩ amountLockedSyrup = amountsLocked.right(); ΩSyrupAmountΩ amountLockedSyrup = amountsLocked.right();
System.out.println("Total amount locked due to HIGH price: " + amountLockedSolana); System.out.println("Total amount locked due to HIGH price: " + amountLockedSolana);
@@ -170,7 +160,7 @@ public class EvelynImpl implements Evelyn {
Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> totalReadyAmount = desiredPositionCalculator Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ> totalReadyAmount = desiredPositionCalculator
.calculateRedistributableSums( .calculateRedistributableSums(
currentPriceFromChain, currentPriceFromRaydium,
solBalanceEvelynAccount, solBalanceEvelynAccount,
amountZeroSolana, // We do not burn Solana amountZeroSolana, // We do not burn Solana
inactiveInAccountSyrup, inactiveInAccountSyrup,
@@ -182,7 +172,7 @@ public class EvelynImpl implements Evelyn {
HashMap<ΩRaydiumLiquidityPoolPositionNftIdΩ, Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ>> rebalancingProposal = HashMap<ΩRaydiumLiquidityPoolPositionNftIdΩ, Pair<ΩSolanaAmountΩ, ΩSyrupAmountΩ>> rebalancingProposal =
desiredPositionCalculator.calculateRebalancingProposal( desiredPositionCalculator.calculateRebalancingProposal(
currentPriceFromChain, currentPriceFromRaydium,
solTotalReadyAmount, solTotalReadyAmount,
syrupTotalReadyAmount syrupTotalReadyAmount
); );
@@ -194,32 +184,35 @@ public class EvelynImpl implements Evelyn {
calculateDiffs(rebalancingProposal, liquidityPositions); calculateDiffs(rebalancingProposal, liquidityPositions);
String minKey = diffs.entrySet().stream() String minKey = diffs.entrySet().stream()
.min(Comparator.comparing(entry -> entry.getValue().diff())) .min(Comparator.comparing(entry -> entry.getValue().right().amount()))
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.orElseThrow(); .orElseThrow();
String maxKey = diffs.entrySet().stream() String maxKey = diffs.entrySet().stream()
.max(Comparator.comparing(entry -> entry.getValue().diff())) .max(Comparator.comparing(entry -> entry.getValue().right().amount()))
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.orElseThrow(); .orElseThrow();
System.out.println("Move value from (" + maxKey + "): "); System.out.println("Move value from (" + maxKey + "): ");
RaydiumLiquidityPoolPositionConcentrated maxPos = liquidityPositions.get(maxKey); RaydiumLiquidityPoolPositionConcentrated maxPos = liquidityPositions.get(maxKey);
Triblet maxDiff = diffs.get(maxKey); Triblet<ΩSyrupAmountΩ, ΩSyrupAmountΩ, ΩSyrupAmountΩ> maxDiff = diffs.get(maxKey);
System.out.println(" " + maxPos.priceRange().from() + ".." System.out.println(" " + maxPos.priceRange().from() + ".."
+ maxPos.priceRange().to() + " - Current: " + maxPos.priceRange().to()
+ maxDiff.currentAmount() + ", Suggested: " + maxDiff.suggestedAmount() + " - Current: " + maxDiff.left().amount()
+ ", Diff: " + maxDiff.diff()); + ", Suggested: " + maxDiff.middle().amount()
+ ", Diff: " + maxDiff.right().amount()
);
System.out.println(" --> "); System.out.println(" --> ");
RaydiumLiquidityPoolPositionConcentrated minPos = liquidityPositions.get(minKey); RaydiumLiquidityPoolPositionConcentrated minPos = liquidityPositions.get(minKey);
Triblet minDiff = diffs.get(minKey); Triblet<ΩSyrupAmountΩ, ΩSyrupAmountΩ, ΩSyrupAmountΩ> minDiff = diffs.get(minKey);
System.out.println(" " + minPos.priceRange().from() + ".." System.out.println(" " + minPos.priceRange().from() + ".."
+ minPos.priceRange().to() + " - Current: " + minPos.priceRange().to()
+ minDiff.currentAmount() + ", Suggested: " + minDiff.suggestedAmount() + " - Current: " + minDiff.left().amount()
+ ", Diff: " + minDiff.diff()); + ", Suggested: " + minDiff.middle().amount()
+ ", Diff: " + minDiff.right().amount());
ΩmilliSecondsΩ iterationExecutionTime = (System.currentTimeMillis() - iterationStartTime); ΩmilliSecondsΩ iterationExecutionTime = (System.currentTimeMillis() - iterationStartTime);
@@ -245,12 +238,12 @@ public class EvelynImpl implements Evelyn {
for(ΩRaydiumLiquidityPoolPositionNftIdΩ nftId : rebalancingProposal.keySet()) { for(ΩRaydiumLiquidityPoolPositionNftIdΩ nftId : rebalancingProposal.keySet()) {
RaydiumLiquidityPoolPositionConcentrated pos = liquidityProviderPositionMap.get(nftId); RaydiumLiquidityPoolPositionConcentrated pos = liquidityProviderPositionMap.get(nftId);
ΩAmountΩ currentlyAmountAdded = pos.amountMintB().amount(); ΩSyrupAmountΩ currentlyAmountAdded = pos.amountMintB();
ΩSyrupAmountΩ suggestedAmount = rebalancingProposal.get(nftId); ΩSyrupAmountΩ suggestedAmount = rebalancingProposal.get(nftId).right();
ΩAmountΩ diff = subtract(currentlyAmountAdded, suggestedAmount); ΩSyrupAmountΩ diff = subtract(currentlyAmountAdded, suggestedAmount);
Triblet<ΩSyrupAmountΩ, ΩSyrupAmountΩ, ΩSyrupAmountΩ> t = new Triblet<>( Triblet<ΩSyrupAmountΩ, ΩSyrupAmountΩ, ΩSyrupAmountΩ> t = new Triblet<>(
currentlyAmountAdded, currentlyAmountAdded,
suggestedAmount.amount(), suggestedAmount,
diff diff
); );
diffs.put(nftId, t); diffs.put(nftId, t);
@@ -259,11 +252,6 @@ public class EvelynImpl implements Evelyn {
return diffs; return diffs;
} }
private final static TradingPair tpSolSyrup = new TradingPair(
SOLANA.getCurrencyType(),
SYRUPUSDC.getCurrencyType()
);
private final static ΩSolanaAmountΩ amountZeroSolana = new ΩSolanaAmountΩ( private final static ΩSolanaAmountΩ amountZeroSolana = new ΩSolanaAmountΩ(
BigDecimal.ZERO, BigDecimal.ZERO,
SOLANA.getCurrencyType() SOLANA.getCurrencyType()
@@ -1,11 +1,10 @@
package com.fanitas.evelyn.core.impl.ref; package com.fanitas.evelyn.core.impl.ref;
import com.fanitas.evelyn.core.State; import com.fanitas.evelyn.core.State;
import com.fanitas.evelyn.raydium.PriceRange;
import com.fanitas.evelyn.raydium.RaydiumLiquidityPoolPositionAccounting; import com.fanitas.evelyn.raydium.RaydiumLiquidityPoolPositionAccounting;
import com.fanitas.evelyn.raydium.RaydiumLiquidityPoolPositionConcentrated; import com.fanitas.evelyn.raydium.RaydiumLiquidityPoolPositionConcentrated;
import com.r35157.libs.raydium.*; import com.r35157.libs.raydium.*;
import com.r35157.libs.solana.valuetypes.WellKnownCurrencyTypes; import com.r35157.libs.valuetypes.basic.WellKnownCurrencyTypes;
import com.r35157.libs.valuetypes.basic.*; import com.r35157.libs.valuetypes.basic.*;
import java.io.BufferedReader; import java.io.BufferedReader;
@@ -105,17 +104,12 @@ public class StateImpl implements State {
CurrencyType ctSyrup = WellKnownCurrencyTypes.SYRUPUSDC.getCurrencyType(); CurrencyType ctSyrup = WellKnownCurrencyTypes.SYRUPUSDC.getCurrencyType();
int mintBDecimals = poolInfo.mintBDecimals(); int mintBDecimals = poolInfo.mintBDecimals();
Range<ΩPriceΩ> raydiumPriceRange = raydium.calculateConcentratedPositionPriceRange( Range<AssetPrice> priceRange = raydium.calculateConcentratedPositionPriceRange(
positionState, positionState,
poolInfo, poolInfo,
mintBDecimals mintBDecimals
); );
PriceRange priceRange = new PriceRange(
ctSyrup,
raydiumPriceRange
);
RaydiumLiquidityPoolTokenAmounts tokenAmounts = RaydiumLiquidityPoolTokenAmounts tokenAmounts =
raydium.calculateConcentratedPositionTokenAmounts( raydium.calculateConcentratedPositionTokenAmounts(
positionState, positionState,
@@ -1,33 +0,0 @@
package com.fanitas.evelyn.raydium;
import com.r35157.libs.valuetypes.basic.CurrencyType;
import com.r35157.libs.valuetypes.basic.Range;
import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
public record PriceRange(
CurrencyType currencyType,
Range<ΩPriceΩ> range
) {
public ΩPriceΩ from() {
return range.from();
}
public boolean fromIncluding() {
return range.fromIncluding();
}
public ΩPriceΩ to() {
return range.to();
}
public boolean toIncluding() {
return range.toIncluding();
}
@Override
public @NotNull String toString() {
return range + " " + currencyType().name();
}
}
@@ -1,10 +1,10 @@
package com.fanitas.evelyn.raydium; package com.fanitas.evelyn.raydium;
import com.r35157.libs.valuetypes.basic.AssetPrice;
import com.r35157.libs.valuetypes.basic.MoneyAmount; import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.libs.valuetypes.basic.Range;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal;
/** /**
* Represents a concentrated liquidity position in a Raydium liquidity pool. * Represents a concentrated liquidity position in a Raydium liquidity pool.
* *
@@ -24,7 +24,7 @@ import java.math.BigDecimal;
public record RaydiumLiquidityPoolPositionConcentrated( public record RaydiumLiquidityPoolPositionConcentrated(
@NotNull ΩRaydiumLiquidityPoolConcentratedIdΩ poolId, @NotNull ΩRaydiumLiquidityPoolConcentratedIdΩ poolId,
@NotNull ΩRaydiumLiquidityPoolPositionNftIdΩ nftId, @NotNull ΩRaydiumLiquidityPoolPositionNftIdΩ nftId,
@NotNull PriceRange priceRange, @NotNull Range<AssetPrice> priceRange,
@NotNull MoneyAmount amountMintA, @NotNull MoneyAmount amountMintA,
@NotNull MoneyAmount amountMintB, @NotNull MoneyAmount amountMintB,
@NotNull RaydiumLiquidityPoolPositionAccounting accountingInfo @NotNull RaydiumLiquidityPoolPositionAccounting accountingInfo
@@ -1,5 +1,6 @@
package com.r35157.libs.raydium; package com.r35157.libs.raydium;
import com.r35157.libs.valuetypes.basic.AssetPrice;
import com.r35157.libs.valuetypes.basic.MoneyAmount; import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.libs.valuetypes.basic.Range; import com.r35157.libs.valuetypes.basic.Range;
@@ -19,7 +20,7 @@ public interface Raydium {
* @throws IOException if the price could not be fetched or the response could not be parsed * @throws IOException if the price could not be fetched or the response could not be parsed
* @throws InterruptedException if the calling thread is interrupted while fetching the price * @throws InterruptedException if the calling thread is interrupted while fetching the price
*/ */
ΩPriceΩ fetchPoolPrice(ΩRaydiumLiquidityPoolIdΩ poolId) throws IOException, InterruptedException; AssetPrice fetchPoolPrice(ΩRaydiumLiquidityPoolIdΩ poolId) throws IOException, InterruptedException;
/** /**
* Fetches the Raydium liquidity pool ids where the supplied Solana owner address has positions. * Fetches the Raydium liquidity pool ids where the supplied Solana owner address has positions.
@@ -183,7 +184,7 @@ public interface Raydium {
* @param decimalPlaces the number decimal places in the resulting price currency * @param decimalPlaces the number decimal places in the resulting price currency
* @return the price range represented by the concentrated liquidity position * @return the price range represented by the concentrated liquidity position
*/ */
Range<ΩPriceΩ> calculateConcentratedPositionPriceRange( Range<AssetPrice> calculateConcentratedPositionPriceRange(
RaydiumConcentratedPositionState positionState, RaydiumConcentratedPositionState positionState,
RaydiumConcentratedPoolInfo poolInfo, RaydiumConcentratedPoolInfo poolInfo,
int decimalPlaces int decimalPlaces
@@ -1,6 +1,6 @@
package com.r35157.libs.raydium; package com.r35157.libs.raydium;
import java.math.BigDecimal; import com.r35157.libs.valuetypes.basic.AssetPrice;
/** /**
* Represents the current price of the tokens in a Raydium liquidity pool. * Represents the current price of the tokens in a Raydium liquidity pool.
@@ -13,6 +13,6 @@ import java.math.BigDecimal;
*/ */
public record RaydiumLiquidityPoolPrice( public record RaydiumLiquidityPoolPrice(
ΩRaydiumLiquidityPoolIdΩ poolId, ΩRaydiumLiquidityPoolIdΩ poolId,
ΩPriceΩ price AssetPrice price
) { ) {
} }
@@ -1,5 +1,6 @@
package com.r35157.libs.raydium.impl.ref; package com.r35157.libs.raydium.impl.ref;
import com.r35157.libs.valuetypes.basic.WellKnownTradingPairs;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.r35157.libs.raydium.Raydium; import com.r35157.libs.raydium.Raydium;
@@ -13,11 +14,8 @@ import com.r35157.libs.solana.SolanaAccountInfo;
import com.r35157.libs.solana.SolanaBlockChain; import com.r35157.libs.solana.SolanaBlockChain;
import com.r35157.libs.solana.SolanaProgramAddressSeed; import com.r35157.libs.solana.SolanaProgramAddressSeed;
import com.r35157.libs.solana.valuetypes.SolanaProgramDerivedAddress; import com.r35157.libs.solana.valuetypes.SolanaProgramDerivedAddress;
import com.r35157.libs.solana.valuetypes.WellKnownCurrencyTypes; import com.r35157.libs.valuetypes.basic.*;
import com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram;
import com.r35157.libs.valuetypes.basic.CurrencyType;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.libs.valuetypes.basic.Range;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
@@ -27,7 +25,6 @@ import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -45,7 +42,7 @@ public class RaydiumImpl implements Raydium {
} }
@Override @Override
public ΩPriceΩ fetchPoolPrice(ΩRaydiumLiquidityPoolIdΩ raydiumLiquidityPoolId) throws IOException, InterruptedException { public AssetPrice fetchPoolPrice(ΩRaydiumLiquidityPoolIdΩ raydiumLiquidityPoolId) throws IOException, InterruptedException {
ΩRestEndpointΩ endpoint = createPoolInfoByIdEndpoint(raydiumLiquidityPoolId); ΩRestEndpointΩ endpoint = createPoolInfoByIdEndpoint(raydiumLiquidityPoolId);
JsonNode root = fetchJson(endpoint); JsonNode root = fetchJson(endpoint);
@@ -57,8 +54,12 @@ public class RaydiumImpl implements Raydium {
throw new IOException("Could NOT find field 'price' in JSON!"); throw new IOException("Could NOT find field 'price' in JSON!");
} }
ΩPriceΩ price = new ΩPriceΩ(priceNode.toString()); // TODO: Find out how not to hardcode the trading pair here
return price; TradingPair tp = WellKnownTradingPairs.SOL_SYRUPUSDC.getTradingPair();
ΩPriceΩ p = new ΩPriceΩ(priceNode.toString());
AssetPrice ap = new AssetPrice(p, tp);
return ap;
} }
@Override @Override
@@ -257,24 +258,28 @@ public class RaydiumImpl implements Raydium {
} }
@Override @Override
public Range<ΩPriceΩ> calculateConcentratedPositionPriceRange( public Range<AssetPrice> calculateConcentratedPositionPriceRange(
RaydiumConcentratedPositionState positionState, RaydiumConcentratedPositionState positionState,
RaydiumConcentratedPoolInfo poolInfo, RaydiumConcentratedPoolInfo poolInfo,
int decimalPlaces int decimalPlaces
) { ) {
TradingPair tp = WellKnownTradingPairs.SOL_SYRUPUSDC.getTradingPair();
ΩPriceΩ priceFrom = calculatePriceFromTick( ΩPriceΩ priceFrom = calculatePriceFromTick(
positionState.tickLowerIndex(), positionState.tickLowerIndex(),
poolInfo, poolInfo,
decimalPlaces decimalPlaces
); );
AssetPrice apFrom = new AssetPrice(priceFrom, tp);
ΩPriceΩ priceTo = calculatePriceFromTick( ΩPriceΩ priceTo = calculatePriceFromTick(
positionState.tickUpperIndex(), positionState.tickUpperIndex(),
poolInfo, poolInfo,
decimalPlaces decimalPlaces
); );
AssetPrice apTo = new AssetPrice(priceTo, tp);
Range<ΩPriceΩ> range = new Range<>(priceFrom, true, priceTo, false); Range<AssetPrice> range = new Range<>(apFrom, true, apTo, false);
return range; return range;
} }
@@ -4,10 +4,10 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.r35157.libs.solana.*; import com.r35157.libs.solana.*;
import com.r35157.libs.solana.valuetypes.SolanaProgramDerivedAddress; import com.r35157.libs.solana.valuetypes.SolanaProgramDerivedAddress;
import com.r35157.libs.solana.valuetypes.WellKnownCurrencyTypes; import com.r35157.libs.valuetypes.basic.MoneyAmount;
import com.r35157.libs.valuetypes.basic.WellKnownCurrencyTypes;
import com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram; import com.r35157.libs.solana.valuetypes.economic.SolanaSPLTokenProgram;
import com.r35157.libs.valuetypes.basic.CurrencyType; import com.r35157.libs.valuetypes.basic.CurrencyType;
import com.r35157.libs.valuetypes.basic.MoneyAmount;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -1,6 +1,4 @@
package com.r35157.libs.solana.valuetypes; package com.r35157.libs.valuetypes.basic;
import com.r35157.libs.valuetypes.basic.CurrencyType;
import java.util.UUID; import java.util.UUID;
@@ -0,0 +1,18 @@
package com.r35157.libs.valuetypes.basic;
import static com.r35157.libs.valuetypes.basic.WellKnownCurrencyTypes.SOLANA;
import static com.r35157.libs.valuetypes.basic.WellKnownCurrencyTypes.SYRUPUSDC;
public enum WellKnownTradingPairs {
SOL_SYRUPUSDC(new TradingPair(SOLANA.getCurrencyType(), SYRUPUSDC.getCurrencyType()));
WellKnownTradingPairs(TradingPair tradingPair) {
this.tradingPair = tradingPair;
}
public TradingPair getTradingPair() {
return tradingPair;
}
private final TradingPair tradingPair;
}