Skip to content

Commit

Permalink
Merge branch 'main' into feat/usdc_staking
Browse files Browse the repository at this point in the history
# Conflicts:
#	core-contracts/Dex/src/main/java/network/balanced/score/core/dex/AbstractDex.java
#	core-contracts/Router/src/main/java/network/balanced/score/core/router/RouterImpl.java
#	core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java
#	score-lib/src/main/java/network/balanced/score/lib/interfaces/Dex.java
#	score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java
  • Loading branch information
sagars committed Nov 29, 2024
2 parents db53648 + 094861e commit 4c2f87a
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 375 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,19 @@ public void govWithdraw(int id, Address token, BigInteger value) {
Context.call(token, "transfer", getDaofund(), value);
}

@External
public void governanceBorrow(Address token, BigInteger amount, Address recipient) {
onlyGovernance();
BigInteger currentDebt = governanceDebt.getOrDefault(token, BigInteger.ZERO);
governanceDebt.set(token, currentDebt.add(amount));
Context.call(token, "transfer", recipient, amount);
}

@External(readonly=true)
public BigInteger getGovernanceDebt(Address token) {
return governanceDebt.getOrDefault(token, BigInteger.ZERO);
}

@External
public void govSetPoolTotal(int pid, BigInteger total) {
onlyGovernance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class DexDBVariables {
private static final String TOKEN_PRECISIONS = "token_precisions";
public static final String VERSION = "version";
public static final String ORACLE_PROTECTION = "oracle_protection";
public static final String GOV_DEBT = "governance_debt";


final static VarDB<Address> governance = Context.newVarDB(GOVERNANCE_ADDRESS, Address.class);
Expand Down Expand Up @@ -137,4 +138,8 @@ public class DexDBVariables {

//Map: pid -> percentage
public final static DictDB<BigInteger, BigInteger> oracleProtection = Context.newDictDB(ORACLE_PROTECTION, BigInteger.class);

//Map: token -> amount
final static DictDB<Address, BigInteger> governanceDebt = Context.newDictDB(GOV_DEBT, BigInteger.class);

}
Original file line number Diff line number Diff line change
Expand Up @@ -353,107 +353,6 @@ void repayDebt() throws Exception {
assertEquals(debt, loanTakerMultiPartialRepayBaS.get("_balance"));
}

@Test
@Order(4)
void sellCollateral() throws Exception {
// Arrange
BalancedClient loanTakerFullDebtSell = balanced.newClient();
BalancedClient loanTakerPartialDebtSell = balanced.newClient();
BalancedClient loanTakerETHFullSell = balanced.newClient();
BalancedClient loanTakerETHPartialSell = balanced.newClient();
BigInteger collateral = BigInteger.TEN.pow(5).multiply(sicxDecimals);
BigInteger collateralETH = BigInteger.TEN.multiply(iethDecimals);

owner.irc2(ethAddress).mintTo(loanTakerETHFullSell.getAddress(), collateralETH, null);
owner.irc2(ethAddress).mintTo(loanTakerETHPartialSell.getAddress(), collateralETH, null);

BigInteger loanAmount = BigInteger.valueOf(17).multiply(EXA);
BigInteger ethLoanAmount = BigInteger.TEN.pow(23);

BigInteger collateralToSellFullDebt = BigInteger.TEN.pow(19);
BigInteger ETHCollateralToSellFullDebt = BigInteger.valueOf(28).multiply(BigInteger.TEN.pow(22));
BigInteger collateralToSellPartialDebt = BigInteger.valueOf(5).multiply(EXA);
BigInteger ETHCollateralToSellPartialDebt = BigInteger.valueOf(2).multiply(BigInteger.TEN.pow(23));

BigInteger minimumReceiveToSellFullDebt = BigInteger.valueOf(16).multiply(EXA);
BigInteger minimumReceiveToSellPartialDebt = BigInteger.valueOf(8).multiply(EXA);

// Act
loanTakerFullDebtSell.stakeDepositAndBorrow(collateral, loanAmount);
loanTakerPartialDebtSell.stakeDepositAndBorrow(collateral, loanAmount);
loanTakerETHFullSell.depositAndBorrow(ethAddress, collateralETH, ethLoanAmount);
loanTakerETHPartialSell.depositAndBorrow(ethAddress, collateralETH, ethLoanAmount);

// requested collateral sell worth is more than debt
assertThrows(UserRevertedException.class, () ->
loanTakerFullDebtSell.loans.sellCollateral(collateral, "sICX", minimumReceiveToSellFullDebt));
assertThrows(UserRevertedException.class, () ->
loanTakerFullDebtSell.loans.sellCollateral(collateralETH, "iETH", minimumReceiveToSellFullDebt));

// minimum receive is more than users debt
assertThrows(UserRevertedException.class, () ->
loanTakerFullDebtSell.loans.sellCollateral(collateral, "sICX", loanAmount.add(BigInteger.TEN.pow(19))));
assertThrows(UserRevertedException.class, () ->
loanTakerFullDebtSell.loans.sellCollateral(collateralETH, "iETH",
ethLoanAmount.add(BigInteger.TEN.pow(19))));

BigInteger loanTakerFullDebtSellCollateralPre = loanTakerFullDebtSell.getLoansCollateralPosition("sICX");
BigInteger loanTakerETHFullDebtSellCollateralPre = loanTakerETHFullSell.getLoansCollateralPosition("iETH");
BigInteger loanTakerPartialDebtSellCollateralPre = loanTakerPartialDebtSell.getLoansCollateralPosition("sICX");
BigInteger loanTakerETHPartialDebtSellCollateralPre = loanTakerETHPartialSell.getLoansCollateralPosition(
"iETH");

BigInteger loanTakerFullDebtSellDebtPositionPre = loanTakerFullDebtSell.getLoansAssetPosition("sICX", "bnUSD");
BigInteger loanTakerETHFullDebtSellDebtPositionPre = loanTakerETHFullSell.getLoansAssetPosition("iETH",
"bnUSD");
BigInteger loanTakerPartialDebtSellDebtPositionPre = loanTakerPartialDebtSell.getLoansAssetPosition("sICX",
"bnUSD");
BigInteger loanTakerETHPartialDebtSellDebtPositionPre = loanTakerETHPartialSell.getLoansAssetPosition("iETH",
"bnUSD");

loanTakerFullDebtSell.loans.sellCollateral(collateralToSellFullDebt, "sICX", minimumReceiveToSellFullDebt);
loanTakerETHFullSell.loans.sellCollateral(ETHCollateralToSellFullDebt, "iETH", minimumReceiveToSellFullDebt);
loanTakerPartialDebtSell.loans.sellCollateral(collateralToSellPartialDebt, "sICX",
minimumReceiveToSellPartialDebt);
loanTakerETHPartialSell.loans.sellCollateral(ETHCollateralToSellPartialDebt, "iETH",
minimumReceiveToSellPartialDebt);

BigInteger loanTakerFullDebtSellCollateralPost = loanTakerFullDebtSell.getLoansCollateralPosition("sICX");
BigInteger loanTakerETHFullDebtSellCollateralPost = loanTakerETHFullSell.getLoansCollateralPosition("iETH");
BigInteger loanTakerPartialDebtSellCollateralPost = loanTakerPartialDebtSell.getLoansCollateralPosition("sICX");
BigInteger loanTakerETHPartialDebtSellCollateralPost = loanTakerETHPartialSell.getLoansCollateralPosition(
"iETH");

BigInteger loanTakerFullDebtSellDebtPositionPost = loanTakerFullDebtSell.getLoansAssetPosition("sICX", "bnUSD");
BigInteger loanTakerETHFullDebtSellDebtPositionPost = loanTakerETHFullSell.getLoansAssetPosition("iETH",
"bnUSD");
BigInteger loanTakerPartialDebtSellDebtPositionPost = loanTakerPartialDebtSell.getLoansAssetPosition("sICX",
"bnUSD");
BigInteger loanTakerETHPartialDebtSellDebtPositionPost = loanTakerETHPartialSell.getLoansAssetPosition("iETH"
, "bnUSD");

// Assert
// requested collateral sell more than available collateral
assertThrows(UserRevertedException.class, () ->
loanTakerFullDebtSell.loans.sellCollateral(collateral, "sICX", minimumReceiveToSellFullDebt));
assertThrows(UserRevertedException.class, () ->
loanTakerFullDebtSell.loans.sellCollateral(collateralETH, "iETH", minimumReceiveToSellFullDebt));

assertEquals(loanTakerFullDebtSellCollateralPost,
loanTakerFullDebtSellCollateralPre.subtract(collateralToSellFullDebt));
assertEquals(loanTakerETHFullDebtSellCollateralPost,
loanTakerETHFullDebtSellCollateralPre.subtract(ETHCollateralToSellFullDebt));
assertEquals(loanTakerPartialDebtSellCollateralPost,
loanTakerPartialDebtSellCollateralPre.subtract(collateralToSellPartialDebt));
assertEquals(loanTakerETHPartialDebtSellCollateralPost,
loanTakerETHPartialDebtSellCollateralPre.subtract(ETHCollateralToSellPartialDebt));

assertTrue(loanTakerFullDebtSellDebtPositionPost.compareTo(loanTakerFullDebtSellDebtPositionPre) < 0);
assertTrue(loanTakerETHFullDebtSellDebtPositionPost.compareTo(loanTakerETHFullDebtSellDebtPositionPre) < 0);
assertTrue(loanTakerPartialDebtSellDebtPositionPost.compareTo(loanTakerPartialDebtSellDebtPositionPre) < 0);
assertTrue(loanTakerETHPartialDebtSellDebtPositionPost.compareTo(loanTakerETHPartialDebtSellDebtPositionPre) < 0);
}

@Test
@Order(4)
void rateLimits() throws Exception {
Expand Down Expand Up @@ -736,7 +635,7 @@ void redeemCollateral_iETH() throws Exception {

BalancedClient loanTaker = balanced.newClient();
BigInteger collateral = BigInteger.TEN.multiply(iethDecimals);
BigInteger redeemAmount = BigInteger.TEN.pow(22);
BigInteger redeemAmount = BigInteger.TEN.pow(21);
owner.irc2(ethAddress).mintTo(loanTaker.getAddress(), collateral, null);
loanTaker.depositAndBorrow(ethAddress, collateral, redeemAmount);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ private void _returnAsset(String _from, BigInteger _value, String _collateralSym
public void redeemCollateral(Address _collateralAddress, BigInteger _amount) {
checkStatus();
loansOn();
Context.require(!getRedemptionExemption(_collateralAddress), "bnUSD cannot be redeemed for this collateral");
Address caller = Context.getCaller();
String collateralSymbol = CollateralDB.getSymbol(_collateralAddress);
BigInteger daofundFee = redemptionDaoFee.getOrDefault(BigInteger.ZERO).multiply(_amount).divide(POINTS);
Expand Down Expand Up @@ -559,16 +560,6 @@ public void withdrawCollateral(BigInteger _value, @Optional String _collateralSy
transferCollateral(collateralSymbol, from, _value, "Collateral withdrawn.", new byte[0]);
}

@External
public void sellCollateral(BigInteger collateralAmountToSell, String collateralSymbol,
BigInteger minimumDebtRepaid) {
checkStatus();
loansOn();
Address from = Context.getCaller();
sellUserCollateral(from.toString(), collateralAmountToSell, collateralSymbol, minimumDebtRepaid);
}


public class LiquidationResult {
public BigInteger liquidationAmount;
public BigInteger collateralToLiquidate;
Expand Down Expand Up @@ -703,66 +694,6 @@ private void depositCollateral(String _symbol, BigInteger _amount, String _from)
CollateralReceived(_from, _symbol, _amount);
}

private void sellUserCollateral(String from, BigInteger collateralToSell, String collateralSymbol,
BigInteger minimumDebtToRepay) {
Context.require(collateralToSell.compareTo(BigInteger.ZERO) > 0, TAG + ": Sell amount must be more than zero.");
Context.require(PositionsDB.hasPosition(from), TAG + ": This address does not have a position on Balanced.");

Position position = PositionsDB.getPosition(from);
BigInteger userCollateral = position.getCollateral(collateralSymbol);

Context.require(userCollateral.compareTo(collateralToSell) >= 0, TAG + ": Position holds less " +
"collateral than the requested sell.");

Address bnUSDAddress = getBnusd();
BigInteger userDebt = position.getDebt(collateralSymbol);

Address collateralAddress = CollateralDB.getAddress(collateralSymbol);
Address dexAddress = getDex();

amountReceived.set(null);
BigInteger poolID = Context.call(BigInteger.class, dexAddress, "getPoolId", collateralAddress, bnUSDAddress);
Context.require(poolID != null, TAG + ": There doesn't exist a bnUSD pool for " + collateralSymbol + ".");

Context.require(userDebt.compareTo(minimumDebtToRepay) >= 0, TAG + ": Minimum receive cannot be greater than " +
"your debt.");
expectedToken.set(bnUSDAddress);

JsonObject swapParams = Json.object()
.add("toToken", bnUSDAddress.toString())
.add("minimumReceive", minimumDebtToRepay.toString());
JsonObject swapData = Json.object()
.add("method", "_swap")
.add("params", swapParams);
byte[] data = swapData.toString().getBytes();

transferCollateral(collateralSymbol, dexAddress, collateralToSell,
collateralSymbol + " swapped for " + BNUSD_SYMBOL, data);
BigInteger bnUSDReceived = amountReceived.get();
amountReceived.set(null);

Context.require(userDebt.compareTo(bnUSDReceived) >= 0, TAG + ": Cannot sell collateral worth more than your " +
"debt.");

BigInteger remainingDebt = userDebt.subtract(bnUSDReceived);
BigInteger remainingCollateral = userCollateral.subtract(collateralToSell);

position.setCollateral(collateralSymbol, remainingCollateral);

if (remainingDebt.compareTo(BigInteger.ZERO) > 0) {
position.setDebt(collateralSymbol, remainingDebt);
} else {
position.setDebt(collateralSymbol, null);
}

TokenUtils.burnAssetFrom(Context.getAddress(), bnUSDReceived);

Context.call(getRewards(), "updateBalanceAndSupply", "Loans", DebtDB.getTotalDebt(), from.toString(), position.getTotalDebt());

String logMessage = "Loan of " + bnUSDReceived + " " + BNUSD_SYMBOL + " sold for" + collateralToSell + " " +
collateralSymbol + " to Balanced.";
CollateralSold(from, BNUSD_SYMBOL, collateralSymbol, bnUSDReceived, logMessage);
}

private void removeCollateral(String from, BigInteger value, String collateralSymbol) {
Context.require(value.compareTo(BigInteger.ZERO) > 0, TAG + ": Withdraw amount must be more than zero.");
Expand Down Expand Up @@ -958,6 +889,17 @@ public BigInteger getRedemptionFee() {
return redemptionFee.get();
}

@External
public void setRedemptionExemption(Address token, boolean exempt) {
onlyGovernance();
redemptionExemptions.set(token, exempt);
}

@External(readonly = true)
public boolean getRedemptionExemption(Address token) {
return redemptionExemptions.getOrDefault(token, false);
}

@External
public void setRedemptionDaoFee(BigInteger _fee) {
onlyGovernance();
Expand Down Expand Up @@ -1104,11 +1046,6 @@ public void OriginateLoan(String recipient, String symbol, BigInteger amount, St
public void LoanRepaid(String account, String symbol, BigInteger amount, String note) {
}

@EventLog(indexed = 3)
public void CollateralSold(String account, String assetSymbol, String collateralSymbol, BigInteger amount,
String note) {
}

@EventLog(indexed = 3)
public void BadDebtCancelled(String account, String symbol, BigInteger amount) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class LoansVariables {
private static final String REDEMPTION_DAO_FEE = "redemption_dao_fee";
private static final String RETIREMENT_BONUS = "retirement_bonus";
private static final String NEW_LOAN_MINIMUM = "new_loan_minimum";
private static final String REDEMPTION_EXEMPTIONS = "redemption_exemptions";

private static final String REDEEM_BATCH_SIZE = "redeem_batch_size";
private static final String MAX_RETIRE_PERCENT = "max_retire_percent";
Expand Down Expand Up @@ -69,6 +70,7 @@ public class LoansVariables {
static final VarDB<BigInteger> newLoanMinimum = Context.newVarDB(NEW_LOAN_MINIMUM, BigInteger.class);
static final VarDB<Integer> redeemBatch = Context.newVarDB(REDEEM_BATCH_SIZE, Integer.class);
static final VarDB<BigInteger> maxRetirePercent = Context.newVarDB(MAX_RETIRE_PERCENT, BigInteger.class);
static final DictDB<Address, Boolean> redemptionExemptions= Context.newDictDB(REDEMPTION_EXEMPTIONS, Boolean.class);

static final VarDB<Address> expectedToken = Context.newVarDB(EXPECTED_TOKEN, Address.class);
static final VarDB<BigInteger> amountReceived = Context.newVarDB(AMOUNT_RECEIVED, BigInteger.class);
Expand Down
Loading

0 comments on commit 4c2f87a

Please sign in to comment.