diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/AbstractDex.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/AbstractDex.java
index eefdbf0e6..59467f03d 100644
--- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/AbstractDex.java
+++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/AbstractDex.java
@@ -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();
diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexDBVariables.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexDBVariables.java
index 97c8e40af..78aed6a20 100644
--- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexDBVariables.java
+++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexDBVariables.java
@@ -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
governance = Context.newVarDB(GOVERNANCE_ADDRESS, Address.class);
@@ -137,4 +138,8 @@ public class DexDBVariables {
//Map: pid -> percentage
public final static DictDB oracleProtection = Context.newDictDB(ORACLE_PROTECTION, BigInteger.class);
+
+ //Map: token -> amount
+ final static DictDB governanceDebt = Context.newDictDB(GOV_DEBT, BigInteger.class);
+
}
diff --git a/core-contracts/Loans/src/intTest/java/network/balanced/score/core/loans/LoansIntegrationTest.java b/core-contracts/Loans/src/intTest/java/network/balanced/score/core/loans/LoansIntegrationTest.java
index 20419b767..7e27e5a7a 100644
--- a/core-contracts/Loans/src/intTest/java/network/balanced/score/core/loans/LoansIntegrationTest.java
+++ b/core-contracts/Loans/src/intTest/java/network/balanced/score/core/loans/LoansIntegrationTest.java
@@ -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 {
@@ -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);
diff --git a/core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansImpl.java b/core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansImpl.java
index 4038e95ab..731d9e806 100644
--- a/core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansImpl.java
+++ b/core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansImpl.java
@@ -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);
@@ -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;
@@ -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.");
@@ -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();
@@ -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) {
}
diff --git a/core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansVariables.java b/core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansVariables.java
index 70271a9ed..c6ec50817 100644
--- a/core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansVariables.java
+++ b/core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansVariables.java
@@ -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";
@@ -69,6 +70,7 @@ public class LoansVariables {
static final VarDB newLoanMinimum = Context.newVarDB(NEW_LOAN_MINIMUM, BigInteger.class);
static final VarDB redeemBatch = Context.newVarDB(REDEEM_BATCH_SIZE, Integer.class);
static final VarDB maxRetirePercent = Context.newVarDB(MAX_RETIRE_PERCENT, BigInteger.class);
+ static final DictDB redemptionExemptions= Context.newDictDB(REDEMPTION_EXEMPTIONS, Boolean.class);
static final VarDB expectedToken = Context.newVarDB(EXPECTED_TOKEN, Address.class);
static final VarDB amountReceived = Context.newVarDB(AMOUNT_RECEIVED, BigInteger.class);
diff --git a/core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTest.java b/core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTest.java
index 5aef1bff1..238bc010c 100644
--- a/core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTest.java
+++ b/core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTest.java
@@ -906,157 +906,6 @@ void returnAsset_AlreadyAboveCeiling() {
verifyTotalDebt(expectedDebt.multiply(BigInteger.TWO).subtract(loanToRepay));
}
- @Test
- void sellCollateral() {
- // Arrange
- Account account = sm.createAccount();
- BigInteger collateral = BigInteger.valueOf(2000).multiply(EXA);
- BigInteger loan = BigInteger.valueOf(200).multiply(EXA);
- BigInteger collateralToSell = BigInteger.valueOf(100).multiply(EXA);
- BigInteger minimumReceiveSicxCollateralSell = BigInteger.valueOf(100).multiply(EXA);
- BigInteger iETHCollateralToSell = BigInteger.valueOf(80).multiply(EXA);
- BigInteger minimumReceiveiETHCollateralSell = BigInteger.valueOf(80).multiply(EXA);
- BigInteger expectedFee = calculateFee(loan);
-
- takeLoanICX(account, "bnUSD", collateral, loan);
- takeLoaniETH(account, collateral, loan);
-
- BigInteger rate = EXA.divide(BigInteger.TWO);
- mockSicxBnusdPrice(rate);
- mockiETHBnusdPrice(rate);
-
- BigInteger expectedBnusdRepaidForSicx = collateralToSell.multiply(BigInteger.TWO);
- BigInteger expectedBnusdRepaidForiETH = iETHCollateralToSell.multiply(BigInteger.ONE);
- mockSwap(sicx, bnusd, collateralToSell, expectedBnusdRepaidForSicx);
- mockSwap(ieth, bnusd, iETHCollateralToSell, expectedBnusdRepaidForiETH);
-
- // Act
- loans.invoke(account, "sellCollateral", collateralToSell, "sICX", minimumReceiveSicxCollateralSell);
- loans.invoke(account, "sellCollateral", iETHCollateralToSell, "iETH", minimumReceiveiETHCollateralSell);
-
- // Assert
- verifyPosition(account.getAddress(), collateral.subtract(collateralToSell),
- loan.add(expectedFee).subtract(expectedBnusdRepaidForSicx), "sICX");
- verifyPosition(account.getAddress(), collateral.subtract(iETHCollateralToSell),
- loan.add(expectedFee).subtract(expectedBnusdRepaidForiETH), "iETH");
- }
-
- @Test
- void sellCollateral_ZeroCollateral() {
- // Arrange
- Account account = sm.createAccount();
- BigInteger collateral = BigInteger.valueOf(1000).multiply(EXA);
- BigInteger loan = BigInteger.valueOf(200).multiply(EXA);
- BigInteger collateralToSell = BigInteger.valueOf(0).multiply(EXA);
- BigInteger minimumReceiveAfterSell = BigInteger.valueOf(50).multiply(EXA);
- String expectedErrorMessage = "Reverted(0): " + TAG + "Sell amount must be more than zero.";
-
- takeLoanICX(account, "bnUSD", collateral, loan);
-
- // Assert & Act
- Executable sellZeroCollateral = () -> loans.invoke(account, "sellCollateral", collateralToSell,
- "sICX", minimumReceiveAfterSell);
- expectErrorMessage(sellZeroCollateral, expectedErrorMessage);
- }
-
- @Test
- void sellCollateral_NoPosition() {
- // Arrange
- Account account = sm.createAccount();
- BigInteger collateralToSell = BigInteger.valueOf(200).multiply(EXA);
- BigInteger minimumReceiveAfterSell = BigInteger.valueOf(50).multiply(EXA);
-
- String expectedErrorMessage = "Reverted(0): " + TAG + "This address does not have a position on Balanced.";
-
- // Assert & Act
- Executable sellWithNoPosition = () -> loans.invoke(account, "sellCollateral", collateralToSell,
- "sICX", minimumReceiveAfterSell);
- expectErrorMessage(sellWithNoPosition, expectedErrorMessage);
- }
-
- @Test
- void sellCollateral_TooMuchCollateral() {
- // Arrange
- Account account = sm.createAccount();
- BigInteger collateral = BigInteger.valueOf(1000).multiply(EXA);
- BigInteger loan = BigInteger.valueOf(200).multiply(EXA);
- BigInteger collateralToSell = BigInteger.valueOf(1100).multiply(EXA);
- BigInteger minimumReceiveAfterSell = BigInteger.valueOf(50).multiply(EXA);
- String expectedErrorMessage = "Reverted(0): " + TAG + "Position holds less collateral than the requested " +
- "sell.";
-
- takeLoanICX(account, "bnUSD", collateral, loan);
-
- // Assert & Act
- Executable sellTooMuchCollateral = () -> loans.invoke(account, "sellCollateral", collateralToSell, "sICX",
- minimumReceiveAfterSell);
- expectErrorMessage(sellTooMuchCollateral, expectedErrorMessage);
- }
-
- @Test
- void sellCollateral_NoAvailablePool() {
- // Arrange
- Account account = sm.createAccount();
- BigInteger collateral = BigInteger.valueOf(1000).multiply(EXA);
- BigInteger loan = BigInteger.valueOf(200).multiply(EXA);
- BigInteger collateralToSell = BigInteger.valueOf(300).multiply(EXA);
- BigInteger minimumReceiveAfterSell = BigInteger.valueOf(300).multiply(EXA);
- String collateralSymbol = "sICX";
- String expectedErrorMessage = "Reverted(0): " + TAG + "There doesn't exist a bnUSD pool for " + collateralSymbol
- + ".";
-
- takeLoanICX(account, "bnUSD", collateral, loan);
-
- // Assert & Act
- Executable noAvailablePool = () -> loans.invoke(account, "sellCollateral", collateralToSell, collateralSymbol,
- minimumReceiveAfterSell);
- expectErrorMessage(noAvailablePool, expectedErrorMessage);
- }
-
- @Test
- void sellCollateral_TooMuchDebt() {
- // Arrange
- Account account = sm.createAccount();
- BigInteger collateral = BigInteger.valueOf(1000).multiply(EXA);
- BigInteger loan = BigInteger.valueOf(200).multiply(EXA);
- BigInteger collateralToSell = BigInteger.valueOf(300).multiply(EXA);
- BigInteger minimumReceiveAfterSell = BigInteger.valueOf(300).multiply(EXA);
- String expectedErrorMessage = "Reverted(0): " + TAG + "Minimum receive cannot be greater than your debt.";
-
- BigInteger rate = EXA.divide(BigInteger.TWO);
- mockSicxBnusdPrice(rate);
-
- takeLoanICX(account, "bnUSD", collateral, loan);
-
- // Assert & Act
- Executable sellTooMuchDebt = () -> loans.invoke(account, "sellCollateral", collateralToSell, "sICX",
- minimumReceiveAfterSell);
- expectErrorMessage(sellTooMuchDebt, expectedErrorMessage);
- }
-
- @Test
- void sellCollateral_TooMuchCollateralSell() {
- // Arrange
- Account account = sm.createAccount();
- BigInteger collateral = BigInteger.valueOf(1000).multiply(EXA);
- BigInteger loan = BigInteger.valueOf(200).multiply(EXA);
- BigInteger collateralToSell = BigInteger.valueOf(400).multiply(EXA);
- BigInteger minimumReceiveAfterSell = BigInteger.valueOf(100).multiply(EXA);
- String expectedErrorMessage = "Reverted(0): " + TAG + "Cannot sell collateral worth more than your debt.";
-
- BigInteger rate = EXA.divide(BigInteger.TWO);
- mockSicxBnusdPrice(rate);
- BigInteger expectedBnusdRepaidForSicx = collateralToSell.multiply(BigInteger.TWO);
- mockSwap(sicx, bnusd, collateralToSell, expectedBnusdRepaidForSicx);
-
- takeLoanICX(account, "bnUSD", collateral, loan);
-
- // Assert & Act
- Executable sellTooMuchCollateral = () -> loans.invoke(account, "sellCollateral", collateralToSell, "sICX",
- minimumReceiveAfterSell);
- expectErrorMessage(sellTooMuchCollateral, expectedErrorMessage);
- }
-
@Test
void withdrawCollateral() {
// Arrange
@@ -1830,6 +1679,27 @@ void redeemCollateral_redeemAboveMax() {
expectErrorMessage(redeemAboveMaxSize, expectedErrorMessage);
}
+ @Test
+ void redeemCollateral_exemptCollateral() {
+ // Arrange
+ Account account1 = sm.createAccount();
+ Account redeemer = sm.createAccount();
+ BigInteger collateral = BigInteger.valueOf(4000).multiply(EXA);
+ BigInteger loan = BigInteger.valueOf(400).multiply(EXA);
+
+ BigInteger sICXRate = EXA.divide(BigInteger.TWO);
+ mockOraclePrice("sICX", sICXRate);
+
+ // Act && Assert
+ loans.invoke(governance.account, "setRedemptionExemption", sicx.getAddress(), true);
+ takeLoanICX(account1, "bnUSD", collateral, loan);
+
+ String expectedErrorMessage = "bnUSD cannot be redeemed for this collateral";
+ Executable redeemExemptToken = () -> loans.invoke(redeemer, "redeemCollateral", sicx.getAddress(), BigInteger.ONE);
+ expectErrorMessage(redeemExemptToken, expectedErrorMessage);
+ }
+
+
@Test
void redeemCollateral_iETH() {
// Arrange
diff --git a/core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTestInterest.java b/core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTestInterest.java
index 3d8f5da97..c45ff2bb1 100644
--- a/core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTestInterest.java
+++ b/core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTestInterest.java
@@ -162,40 +162,6 @@ void returnAsset() {
verifyTotalDebt(BigInteger.ZERO);
}
- @Test
- void sellCollateral() {
- // Arrange
- Account account = sm.createAccount();
- BigInteger collateral = BigInteger.valueOf(1000000).multiply(EXA);
- BigInteger loan = BigInteger.valueOf(100000).multiply(EXA);
- BigInteger collateralToSell = BigInteger.valueOf(100).multiply(EXA);
- BigInteger minimumReceiveSicxCollateralSell = BigInteger.valueOf(10000).multiply(EXA);
- BigInteger expectedFee = calculateFee(loan);
- BigInteger expectedDebt = loan.add(expectedFee);
- BigInteger timePassed = BigInteger.valueOf(20000);
-
- takeLoanICX(account, "bnUSD", collateral, loan);
- sm.getBlock().increase(timePassed.longValue()/2);
- loans.invoke(mockBalanced.governance.account, "applyInterest");
- BigInteger interest = expectedDebt.multiply(SICX_INTEREST).multiply(timePassed.multiply(MICRO_SECONDS_IN_A_SECOND))
- .divide(YEAR_IN_MICRO_SECONDS.multiply(POINTS));
- BigInteger rate = EXA.divide(BigInteger.TWO);
- mockSicxBnusdPrice(rate);
-
- BigInteger expectedBnusdRepaidForSicx = collateralToSell.multiply(BigInteger.TWO);
- mockSwap(sicx, bnusd, collateralToSell, expectedBnusdRepaidForSicx);
-
- // Act
- loans.invoke(account, "sellCollateral", collateralToSell, "sICX", minimumReceiveSicxCollateralSell);
-
- // Assert
- assertTrue(interest.compareTo(EXA) > 0);
- BigInteger debt = getUserDebt(account, "sICX");
- verifyPosition(account.getAddress(), collateral.subtract(collateralToSell),
- debt, "sICX");
- assertRoundedEquals(expectedDebt.subtract(expectedBnusdRepaidForSicx).add(interest), debt);
- }
-
@Test
void claimInterest() {
// Arrange
diff --git a/core-contracts/Router/src/main/java/network/balanced/score/core/router/RouterImpl.java b/core-contracts/Router/src/main/java/network/balanced/score/core/router/RouterImpl.java
index 6f67d8f1b..a321f6f53 100644
--- a/core-contracts/Router/src/main/java/network/balanced/score/core/router/RouterImpl.java
+++ b/core-contracts/Router/src/main/java/network/balanced/score/core/router/RouterImpl.java
@@ -261,11 +261,8 @@ private void executeRoute(String _from, byte[] data) {
} else {
receiver = _from;
}
- byte[] _data = EMPTY_DATA;
- if(routeData.data!=null){
- _data = routeData.data;
- }
- route(receiver, fromToken, routeData.actions, minimumReceive, _data);
+
+ route(receiver, fromToken, routeData.actions, minimumReceive, EMPTY_DATA);
}
private void jsonRoute(String _from, byte[] data) {
@@ -311,11 +308,7 @@ private void jsonRoute(String _from, byte[] data) {
}
Address fromToken = Context.getCaller();
- byte[] _data = EMPTY_DATA;
- if(params.get("data")!=null){
- _data = params.get("data").asString().getBytes();
- }
- route(receiver, fromToken, actions, minimumReceive, _data);
+ route(receiver, fromToken, actions, minimumReceive, EMPTY_DATA);
}
@Payable
diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Dex.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Dex.java
index 78eb9979d..94b745cfc 100644
--- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Dex.java
+++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Dex.java
@@ -207,5 +207,10 @@ void xAdd(String from, String _baseToken, String _quoteToken, BigInteger _baseVa
@External
void addLpAddresses(BigInteger _poolId, Address[] _addresses);
+ @External
+ void governanceBorrow(Address token, BigInteger amount, Address recipient);
+
+ @External(readonly=true)
+ BigInteger getGovernanceDebt(Address token);
}
diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Loans.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Loans.java
index 6d94590f9..6e4af666d 100644
--- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Loans.java
+++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Loans.java
@@ -91,9 +91,6 @@ void depositAndBorrow(@Optional String _asset, @Optional BigInteger _amount, @Op
@External
void withdrawAndUnstake(BigInteger _value);
- @External
- void sellCollateral(BigInteger collateralAmountToSell, String collateralSymbol, BigInteger minimumDebtRepaid);
-
@External
void withdrawCollateral(BigInteger _value, @Optional String _collateralSymbol);
@@ -151,6 +148,12 @@ void depositAndBorrow(@Optional String _asset, @Optional BigInteger _amount, @Op
@External(readonly = true)
BigInteger getRedemptionDaoFee();
+ @External
+ void setRedemptionExemption(Address token, boolean exempt);
+
+ @External(readonly = true)
+ boolean getRedemptionExemption(Address token);
+
@External
void setNewLoanMinimum(BigInteger _minimum);
diff --git a/score-lib/src/main/java/network/balanced/score/lib/tokens/HubTokenImpl.java b/score-lib/src/main/java/network/balanced/score/lib/tokens/HubTokenImpl.java
index 0da49765b..56ce4d3a4 100644
--- a/score-lib/src/main/java/network/balanced/score/lib/tokens/HubTokenImpl.java
+++ b/score-lib/src/main/java/network/balanced/score/lib/tokens/HubTokenImpl.java
@@ -87,6 +87,11 @@ public void setSpokeLimit(String networkId, BigInteger limit) {
spokeLimits.set(networkId, limit);
}
+ @External(readonly = true)
+ public BigInteger getSpokeLmit(String networkId) {
+ return spokeLimits.getOrDefault(networkId, BigInteger.ZERO);
+ }
+
@External(readonly = true)
public BigInteger xSupply(String net) {
return crossChainSupply.getOrDefault(net, BigInteger.ZERO);