Skip to content

Commit

Permalink
Merge pull request #422 from balancednetwork/421-loans-add-loans-to-a…
Browse files Browse the repository at this point in the history
…nd-repay-to-functionallity

feat: Add option for user to take loan to a someone and repay another…
  • Loading branch information
AntonAndell authored Jun 17, 2024
2 parents a17e7fa + 36cd1e0 commit 63634eb
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ void blacklist() throws Throwable {
null);
Executable nonAllowedTransfer2 = () -> blacklistedUser2.bnUSD.transfer(owner.getAddress(), BigInteger.ONE,
null);
Executable nonAllowedBurn = () -> blacklistedUser1.loans.returnAsset("bnUSD", BigInteger.TEN.pow(18), "sICX");
Executable nonAllowedBurn = () -> blacklistedUser1.loans.returnAsset("bnUSD", BigInteger.TEN.pow(18), "sICX", "");
user3.bnUSD.transfer(owner.getAddress(), BigInteger.ONE, null);
assertThrows(Exception.class, nonAllowedTransfer1);
assertThrows(Exception.class, nonAllowedTransfer2);
Expand Down Expand Up @@ -472,7 +472,7 @@ void emergency_disable_enable() throws Throwable {
BigInteger.valueOf(200).multiply(BigInteger.TEN.pow(18)), null);
Executable dividendsStatusTest = () -> user.dividends.distribute((tx) -> {
});
Executable loansStatusTest = () -> user.loans.returnAsset("bnUSD", BigInteger.ONE, "sICX");
Executable loansStatusTest = () -> user.loans.returnAsset("bnUSD", BigInteger.ONE, "sICX", "");
Executable rewardsStatusTest = () -> user.rewards.distribute((tx) -> {
});
Executable stakingStatusTest = () -> user.staking.stakeICX(collateral.multiply(BigInteger.TWO), null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ void crossChainDepositAndBorrow() throws Exception {
// Deposit first then borrow
byte[] depositBSC = AssetManagerMessages.deposit(balanced.BSC_TOKEN_ADDRESS, bscUser.account().toString(), loansNetAddress, collateral, "{}".getBytes());
owner.xcall.sendCall(balanced.assetManager._address(), new NetworkAddress(balanced.BSC_NID, balanced.BSC_ASSET_MANAGER).toString(), depositBSC);
byte[] borrowBSC = LoansMessages.xBorrow(balanced.BSC_TOKEN_SYMBOL, loanAmount);
byte[] borrowBSC = LoansMessages.xBorrow(balanced.BSC_TOKEN_SYMBOL, loanAmount, "", new byte[0]);
owner.xcall.sendCall(balanced.loans._address(), bscUser.toString(), borrowBSC);

// Bridge collateral to hub wallet first then borrow
Expand Down Expand Up @@ -256,7 +256,7 @@ void crossChainRepayAndWithdraw() throws Exception {
owner.xcall.sendCall(balanced.bnusd._address(), bscHubUser.toString(), repayTransfer);

// Repay and withdraw with bnUSD on the ICON wallet.
nativeLoanTaker.loans.returnAsset("bnUSD", amountToRepay, balanced.BSC_TOKEN_SYMBOL);
nativeLoanTaker.loans.returnAsset("bnUSD", amountToRepay, balanced.BSC_TOKEN_SYMBOL, "");
nativeLoanTaker.loans.withdrawCollateral(amountToWithdraw, balanced.BSC_TOKEN_SYMBOL);

// Assert
Expand Down Expand Up @@ -316,17 +316,17 @@ void repayDebt() throws Exception {
loanTakerIETHFullRepay.depositAndBorrow(ethAddress, collateralETH, loanAmount);
loanTakerMultiPartialRepay.depositAndBorrow(ethAddress, collateralETH, loanAmount);

loanTakerPartialRepay.loans.returnAsset("bnUSD", debt.divide(BigInteger.TWO), "sICX");
loanTakerPartialRepay.loans.returnAsset("bnUSD", debt.divide(BigInteger.TWO), "sICX", "");
loanTakerPartialRepay.bnUSD.transfer(loanTakerFullRepay.getAddress(), fee, null);
loanTakerPartialRepay.bnUSD.transfer(loanTakerIETHFullRepay.getAddress(), fee, null);
loanTakerFullRepay.loans.returnAsset("bnUSD", debt, "sICX");
loanTakerFullRepay.loans.returnAsset("bnUSD", debt, "sICX", "");

assertThrows(UserRevertedException.class, () ->
loanTakerIETHFullRepay.loans.returnAsset("bnUSD", debt, "sICX"));
loanTakerIETHFullRepay.loans.returnAsset("bnUSD", debt, "sICX", ""));

loanTakerIETHFullRepay.loans.returnAsset("bnUSD", debt, "iETH");
loanTakerMultiPartialRepay.loans.returnAsset("bnUSD", debt.divide(BigInteger.TWO), "sICX");
loanTakerMultiPartialRepay.loans.returnAsset("bnUSD", debt.divide(BigInteger.TWO), "iETH");
loanTakerIETHFullRepay.loans.returnAsset("bnUSD", debt, "iETH", "");
loanTakerMultiPartialRepay.loans.returnAsset("bnUSD", debt.divide(BigInteger.TWO), "sICX", "");
loanTakerMultiPartialRepay.loans.returnAsset("bnUSD", debt.divide(BigInteger.TWO), "iETH", "");

BigInteger outstandingNewDebt = BigInteger.valueOf(3).multiply(debt.divide(BigInteger.TWO));

Expand Down Expand Up @@ -536,10 +536,10 @@ void withdrawCollateral() throws Exception {
loanTakerPartialWithdraw.bnUSD.transfer(loanTakerFullWithdraw.getAddress(), fee, null);
loanTakerPartialWithdraw.bnUSD.transfer(loanTakerETHFullWithdraw.getAddress(), fee, null);

loanTakerFullWithdraw.loans.returnAsset("bnUSD", debt, "sICX");
loanTakerFullWithdraw.loans.returnAsset("bnUSD", debt, "sICX", "");
loanTakerFullWithdraw.loans.withdrawCollateral(collateral, "sICX");

loanTakerETHFullWithdraw.loans.returnAsset("bnUSD", debt, "iETH");
loanTakerETHFullWithdraw.loans.returnAsset("bnUSD", debt, "iETH", "");
loanTakerETHFullWithdraw.loans.withdrawCollateral(collateralETH, "iETH");

BigInteger amountToWithdraw = BigInteger.TEN.pow(20);
Expand Down Expand Up @@ -607,14 +607,14 @@ void reOpenPosition() throws Exception {
loanTakerPartialRepay.bnUSD.transfer(loanTakerFullClose.getAddress(), fee, null);
loanTakerPartialRepay.bnUSD.transfer(loanTakerETHFullClose.getAddress(), fee, null);

loanTakerCloseLoanOnly.loans.returnAsset("bnUSD", debt, "sICX");
loanTakerFullClose.loans.returnAsset("bnUSD", debt, "sICX");
loanTakerETHFullClose.loans.returnAsset("bnUSD", debt, "iETH");
loanTakerCloseLoanOnly.loans.returnAsset("bnUSD", debt, "sICX", "");
loanTakerFullClose.loans.returnAsset("bnUSD", debt, "sICX", "");
loanTakerETHFullClose.loans.returnAsset("bnUSD", debt, "iETH", "");

BigInteger amountRepaid = BigInteger.TEN.pow(21);
BigInteger amountETHRepaid = BigInteger.TEN.pow(18);
loanTakerPartialRepay.loans.returnAsset("bnUSD", amountRepaid, "sICX");
loanTakerETHPartialRepay.loans.returnAsset("bnUSD", amountETHRepaid, "iETH");
loanTakerPartialRepay.loans.returnAsset("bnUSD", amountRepaid, "sICX", "");
loanTakerETHPartialRepay.loans.returnAsset("bnUSD", amountETHRepaid, "iETH", "");

loanTakerFullClose.loans.withdrawCollateral(loanTakerFullClose.getLoansCollateralPosition("sICX"), null);
loanTakerETHFullClose.loans.withdrawCollateral(loanTakerETHFullClose.getLoansCollateralPosition("iETH"),
Expand Down Expand Up @@ -688,7 +688,7 @@ void debtCeilings() throws Exception {
loanTaker1.stakeDepositAndBorrow(sICXCollateral, loanAmount1);
assertThrows(RevertedException.class, () -> loanTaker2.stakeDepositAndBorrow(sICXCollateral, loanAmount2));

loanTaker1.loans.returnAsset("bnUSD", debt2, "sICX");
loanTaker1.loans.returnAsset("bnUSD", debt2, "sICX", "");
loanTaker2.stakeDepositAndBorrow(sICXCollateral, loanAmount2);
assertThrows(UserRevertedException.class, () -> loanTaker1.borrowFrom("sICX", debt2));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import network.balanced.score.core.loans.debt.DebtDB;
import network.balanced.score.core.loans.positions.Position;
import network.balanced.score.core.loans.positions.PositionsDB;
import network.balanced.score.core.loans.utils.LoansConstants.Standings;
import network.balanced.score.core.loans.utils.PositionBatch;
import network.balanced.score.core.loans.utils.TokenUtils;
import network.balanced.score.lib.interfaces.Loans;
Expand All @@ -47,13 +48,15 @@
import java.util.List;
import java.util.Map;

import static network.balanced.score.core.loans.LoansVariables.loansOn;
import static network.balanced.score.core.loans.LoansVariables.*;
import static network.balanced.score.core.loans.utils.Checks.loansOn;
import static network.balanced.score.core.loans.utils.LoansConstants.*;
import static network.balanced.score.lib.utils.BalancedAddressManager.*;
import static network.balanced.score.lib.utils.Check.*;
import static network.balanced.score.lib.utils.Constants.EOA_ZERO;
import static network.balanced.score.lib.utils.Constants.EXA;
import static network.balanced.score.lib.utils.Constants.MICRO_SECONDS_IN_A_DAY;
import static network.balanced.score.lib.utils.Constants.POINTS;
import static network.balanced.score.lib.utils.Math.convertToNumber;
import static network.balanced.score.lib.utils.Math.pow;

Expand Down Expand Up @@ -267,10 +270,15 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) {
if (token.equals(getBnusd())) {
String collateralSymbol = json.get("_collateral").asString();
JsonValue withdrawAmount = json.get("_withdrawAmount");
String to = json.getString("_to", _from);
if (to.equals("")) {
to = _from;
}

BigInteger collateralToWithdraw = convertToNumber(withdrawAmount, BigInteger.ZERO);
TokenUtils.burnAsset(_value);
_returnAsset(_from, _value, collateralSymbol);
if (BigInteger.ZERO.compareTo(collateralToWithdraw) < 0) {
_returnAsset(to, _value, collateralSymbol);
if (BigInteger.ZERO.compareTo(collateralToWithdraw) < 0 && to.equals(_from)) {
xWithdraw(_from, collateralToWithdraw, collateralSymbol);
}
} else {
Expand All @@ -280,7 +288,7 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) {

depositCollateral(collateralSymbol, _value, _from);
if (BigInteger.ZERO.compareTo(requestedAmount) < 0) {
originateLoan(collateralSymbol, requestedAmount, _from);
originateLoan(collateralSymbol, requestedAmount, _from, null, new byte[0]);
}
}
}
Expand Down Expand Up @@ -317,7 +325,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) {

depositCollateral(collateralSymbol, _value, _from.toString());
if (BigInteger.ZERO.compareTo(requestedAmount) < 0) {
originateLoan(collateralSymbol, requestedAmount, _from.toString());
originateLoan(collateralSymbol, requestedAmount, _from.toString(), null, new byte[0]);
}
}

Expand All @@ -329,8 +337,8 @@ public void handleCallMessage(String _from, byte[] _data, @Optional String[] _pr
LoansXCall.process(this, _from, _data);
}

public void xBorrow(String from, String _collateralToBorrowAgainst, BigInteger _amountToBorrow) {
originateLoan(_collateralToBorrowAgainst, _amountToBorrow, from);
public void xBorrow(String from, String _collateralToBorrowAgainst, BigInteger _amountToBorrow, String _to, byte[] _data) {
originateLoan(_collateralToBorrowAgainst, _amountToBorrow, from, _to, _data);
}

public void xWithdraw(String from, BigInteger _value, String _collateralSymbol) {
Expand All @@ -351,13 +359,13 @@ private boolean canWithdraw(String net) {
}

@External
public void borrow(String _collateralToBorrowAgainst, String _assetToBorrow, BigInteger _amountToBorrow) {
public void borrow(String _collateralToBorrowAgainst, String _assetToBorrow, BigInteger _amountToBorrow, @Optional String _to, @Optional byte[] _data) {
checkStatus();
loansOn();
Context.require(_amountToBorrow.compareTo(BigInteger.ZERO) > 0, TAG + ": _amountToBorrow needs to be larger " +
"than 0");
Context.require(_assetToBorrow.equals(BNUSD_SYMBOL));
originateLoan(_collateralToBorrowAgainst, _amountToBorrow, Context.getCaller().toString());
originateLoan(_collateralToBorrowAgainst, _amountToBorrow, Context.getCaller().toString(), _to, _data);
}

@External
Expand All @@ -381,7 +389,7 @@ public void depositAndBorrow(@Optional String _asset, @Optional BigInteger _amou
return;
}

originateLoan(SICX_SYMBOL, _amount, depositor);
originateLoan(SICX_SYMBOL, _amount, depositor, null, new byte[0]);
}

@External
Expand Down Expand Up @@ -444,14 +452,18 @@ public void retireBadDebtForCollateral(String _symbol, BigInteger _value, String
}

@External
public void returnAsset(String _symbol, BigInteger _value, @Optional String _collateralSymbol) {
public void returnAsset(String _symbol, BigInteger _value, @Optional String _collateralSymbol, @Optional String to) {
Address from = Context.getCaller();
if (to == null || to.equals("") ){
to = from.toString();
}

Context.require(_symbol.equals(BNUSD_SYMBOL));
String collateralSymbol = optionalDefault(_collateralSymbol, SICX_SYMBOL);

Context.require(TokenUtils.balanceOf(getBnusd(), from).compareTo(_value) >= 0, TAG + ": Insufficient balance.");
TokenUtils.burnAssetFrom(from, _value);
_returnAsset(from.toString(), _value, collateralSymbol);
_returnAsset(to, _value, collateralSymbol);

}

Expand Down Expand Up @@ -755,7 +767,7 @@ private void removeCollateral(String from, BigInteger value, String collateralSy
}


private void originateLoan(String collateralSymbol, BigInteger amount, String from) {
private void originateLoan(String collateralSymbol, BigInteger amount, String from, String to, byte[] data) {
DebtDB.applyInterest(collateralSymbol);

Position position = PositionsDB.getPosition(from);
Expand Down Expand Up @@ -788,22 +800,30 @@ private void originateLoan(String collateralSymbol, BigInteger amount, String fr
position.setDebt(collateralSymbol, holdings.add(newDebt));
Context.call(getRewards(), "updateBalanceAndSupply", "Loans", DebtDB.getTotalDebt(), from.toString(), position.getTotalDebt());

originateBnUSD(from, amount, fee);
originateBnUSD(from, amount, fee, to, data);
}

private void originateBnUSD(String from, BigInteger amount, BigInteger fee) {
private void originateBnUSD(String from, BigInteger amount, BigInteger fee, String to, byte[] data) {
TokenUtils.mintAsset(amount);
if (from.contains("/")) {
String net = NetworkAddress.valueOf(from).net();
if (to == null || to.equals("")) {
to = from;
}

if (data == null) {
data = new byte[0];
}

if (to.contains("/")) {
String net = NetworkAddress.valueOf(to).net();
boolean canWithdraw = Context.call(Boolean.class, getDaofund(), "getXCallFeePermission", Context.getAddress(), net);
if (canWithdraw) {
BigInteger xCallFee = Context.call(BigInteger.class, getDaofund(), "claimXCallFee", net, true);
TokenUtils.crossTransfer(xCallFee, from, amount);
TokenUtils.crossTransfer(xCallFee, to, amount, data);
} else {
TokenUtils.hubTransfer(from, amount);
TokenUtils.hubTransfer(to, amount, data);
}
} else {
TokenUtils.transfer(Address.fromString(from), amount);
TokenUtils.transfer(Address.fromString(to), amount, data);
}
String logMessage = "Loan of " + amount + " " + BNUSD_SYMBOL + " from Balanced.";
OriginateLoan(from, BNUSD_SYMBOL, amount, logMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ public static void burnAssetFrom(Address from, BigInteger amount) {
Context.call(getBnusd(), "burnFrom", from, amount);
}

public static void crossTransfer(BigInteger fee, String to, BigInteger amount) {
Context.call(fee, getBnusd(), "crossTransfer", to, amount, new byte[0]);
public static void crossTransfer(BigInteger fee, String to, BigInteger amount, byte[] data) {
Context.call(fee, getBnusd(), "crossTransfer", to, amount, data);
}

public static void hubTransfer(String to, BigInteger amount) {
Context.call(getBnusd(), "hubTransfer", to, amount, new byte[0]);
public static void hubTransfer(String to, BigInteger amount, byte[] data) {
Context.call(getBnusd(), "hubTransfer", to, amount, data);
}

public static void transfer(Address to, BigInteger amount) {
Context.call(getBnusd(), "transfer", to, amount, new byte[0]);
public static void transfer(Address to, BigInteger amount, byte[] data) {
Context.call(getBnusd(), "transfer", to, amount, data);
}
}
Loading

0 comments on commit 63634eb

Please sign in to comment.