From a832ca711ccf593dccc24ad17950c7ba295e744c Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 2 Oct 2024 11:33:07 +0545 Subject: [PATCH 01/31] cross chain lp functionalities and unit test --- core-contracts/Dex/build.gradle | 1 + .../score/core/dex/DexIntegrationTest.java | 95 +++++++---- .../balanced/score/core/dex/AbstractDex.java | 115 +++++-------- .../score/core/dex/DexDBVariables.java | 11 +- .../balanced/score/core/dex/DexImpl.java | 161 ++++++++++++------ .../core/dex/IRC31StandardSpokeLpToken.java | 131 ++++++++++++++ .../balanced/score/core/dex/DexTestBase.java | 25 ++- .../balanced/score/core/dex/DexTestCore.java | 132 +++++++++++++- .../core/dex/DexTestSettersAndGetters.java | 32 ++-- core-contracts/Rewards/build.gradle | 1 + .../score/core/rewards/RewardsImpl.java | 59 +++++-- .../score/core/rewards/RewardsTestBase.java | 17 ++ .../rewards/RewardsTestExternalRewards.java | 75 ++++++++ core-contracts/StakedLP/build.gradle | 1 + .../score/core/stakedlp/StakedLPImpl.java | 95 ++++++++--- .../score/core/stakedlp/StakedLPTest.java | 141 ++++++++++++--- .../balanced/score/lib/interfaces/Dex.java | 27 ++- .../score/lib/interfaces/Rewards.java | 4 + .../score/lib/interfaces/StakedLP.java | 11 ++ .../score/lib/interfaces/base/IRC31Base.java | 4 +- .../lib/interfaces/tokens/XReceiver.java | 19 +++ .../score/lib/tokens/HubTokenImpl.java | 1 + .../score/lib/utils/AddressBranchDictDB.java | 35 ++++ .../utils/BranchedNetworkAddressDictDB.java | 21 +++ .../score/lib/utils/NetworkAddressDictDB.java | 6 + .../score/lib/test/integration/Balanced.java | 8 +- .../score/util/mock/xcall/XCallMockImpl.java | 1 + 27 files changed, 984 insertions(+), 245 deletions(-) create mode 100644 core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java create mode 100644 score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/XReceiver.java create mode 100644 score-lib/src/main/java/network/balanced/score/lib/utils/AddressBranchDictDB.java create mode 100644 score-lib/src/main/java/network/balanced/score/lib/utils/BranchedNetworkAddressDictDB.java diff --git a/core-contracts/Dex/build.gradle b/core-contracts/Dex/build.gradle index 37ee967af..67c301af5 100644 --- a/core-contracts/Dex/build.gradle +++ b/core-contracts/Dex/build.gradle @@ -48,6 +48,7 @@ dependencies { implementation Dependencies.javaeeScorex implementation Dependencies.minimalJson implementation project(':score-lib') + implementation 'xyz.venture23:xcall-lib:2.1.0' testImplementation Dependencies.javaeeUnitTest testImplementation Dependencies.mockitoCore diff --git a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java index 9238ee571..e893055d6 100644 --- a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java +++ b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java @@ -16,16 +16,21 @@ package network.balanced.score.core.dex; +import com.eclipsesource.json.JsonObject; import com.eclipsesource.json.JsonArray; import foundation.icon.icx.Wallet; import foundation.icon.jsonrpc.Address; import foundation.icon.score.client.DefaultScoreClient; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.interfaces.*; import network.balanced.score.lib.interfaces.dex.DexTestScoreClient; import network.balanced.score.lib.test.integration.Balanced; +import network.balanced.score.lib.test.integration.BalancedClient; import network.balanced.score.lib.test.integration.Env; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import score.ByteArrayObjectWriter; +import score.Context; import java.io.File; import java.math.BigInteger; @@ -58,6 +63,7 @@ class DexIntegrationTest { private static DefaultScoreClient tokenCClient; private static DefaultScoreClient tokenDClient; private static DefaultScoreClient daoFundScoreClient; + private static BalancedClient owner; private static final File jarfile = new File("src/intTest/java/network/balanced/score/core/dex/testtokens" + "/DexIntTestToken.jar"); @@ -87,6 +93,7 @@ class DexIntegrationTest { balnScoreClient = balanced.baln; rewardsScoreClient = balanced.rewards; daoFundScoreClient = balanced.daofund; + owner = balanced.ownerClient; Rewards rewards = new RewardsScoreClient(balanced.rewards); Loans loans = new LoansScoreClient(balanced.loans); @@ -209,35 +216,6 @@ void testICXTransferSwapEarningAndCancelOrder() { dexUserScoreClient.cancelSicxicxOrder(); } - /*@Test - @Order(4) - void testBalnPoolTokenTransferableOnContinuousRewards(){ - - if(dexUserScoreClient.getContinuousRewardsDay()==null) { - governanceDexScoreClient.setContinuousRewardsDay(dexUserScoreClient.getDay().add(BigInteger.ONE)); - } - waitForADay(); - balanced.syncDistributions(); - //continuous starts - byte[] tokenDeposit = "{\"method\":\"_deposit\",\"params\":{\"none\":\"none\"}}".getBytes(); - mintAndTransferTestTokens(tokenDeposit); - dexUserScoreClient.add(Address.fromString(dexTestBaseScoreAddress), Address.fromString - (dexTestFourthScoreClient._address().toString()), BigInteger.valueOf(50).multiply(EXA), BigInteger.valueOf - (50).multiply(EXA), false); - BigInteger poolId = dexUserScoreClient.getPoolId(Address.fromString(dexTestBaseScoreAddress), Address - .fromString(dexTestFourthScoreAddress)); - //assert pool id is less than 5 - assert poolId.compareTo(BigInteger.valueOf(6)) < 0; - BigInteger liquidity = (BigInteger.valueOf(50).multiply(EXA).multiply(BigInteger.valueOf(50).multiply(EXA))) - .sqrt(); - BigInteger balance = dexUserScoreClient.balanceOf(userAddress, poolId); - BigInteger tUsersPrevBalance = dexUserScoreClient.balanceOf(tUserAddress, poolId); - - assertEquals(balance, liquidity); - dexUserScoreClient.transfer(tUserAddress, BigInteger.valueOf(5).multiply(EXA), poolId, new byte[0]); - BigInteger tUsersBalance = dexUserScoreClient.balanceOf(tUserAddress, poolId); - assertEquals(tUsersPrevBalance.add(BigInteger.valueOf(5).multiply(EXA)), tUsersBalance); - }*/ @Test @Order(6) @@ -323,6 +301,65 @@ void testNonContinuousAndContinuousReward() { } + @Test + void crossChainDeposit() { + // Arrange + String ethBnUSD = new NetworkAddress(balanced.ETH_NID, balanced.ETH_BNUSD_ADDRESS).toString(); + String fromNetworkAddress = "0x1.ETH/0x123"; + BigInteger depositValue = BigInteger.valueOf(100).multiply(EXA); + + // Act + byte[] message = depositMsg(fromNetworkAddress, depositValue, tokenData("_deposit", + new JsonObject().set( "address", fromNetworkAddress))); + owner.xcall.recvCall(owner.bnUSD._address(), ethBnUSD, message); + + // Verify + BigInteger retrievedValue = dexUserScoreClient.getDepositV2(balanced.bnusd._address(), fromNetworkAddress); + assertEquals(depositValue, retrievedValue); + } + + public static byte[] tokenData(String method, JsonObject params) { + JsonObject data = new JsonObject(); + data.set("method", method); + data.set("params", params); + return data.toString().getBytes(); + } + + static byte[] depositMsg(String from, BigInteger amount, byte[] data) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(2); + writer.write("xcrosstransfer"); + writer.write(from); + writer.write(from); + writer.write(amount); + writer.write(data); + return writer.toByteArray(); + } + static byte[] getXRemoveData(BigInteger poolId, BigInteger lpTokenBalance, Boolean withdraw) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(4); + writer.write("xremove"); + writer.write(poolId); + writer.write(lpTokenBalance); + writer.write(withdraw); + writer.end(); + return writer.toByteArray(); + } + + static byte[] getAddLPData(score.Address baseToken, score.Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(7); + writer.write("xadd"); + writer.write(baseToken); + writer.write(quoteToken); + writer.write(baseValue); + writer.write(quoteValue); + writer.write(withdraw_unused); + writer.write(slippagePercentage); + writer.end(); + return writer.toByteArray(); + } + void transferSicxToken() { byte[] data = "testData".getBytes(); ((StakingScoreClient) userStakeScoreClient).stakeICX(BigInteger.valueOf(80).multiply(EXA), userAddress, data); 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 44a27835a..cad8407d0 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 @@ -16,12 +16,14 @@ package network.balanced.score.core.dex; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.core.dex.db.NodeDB; import network.balanced.score.lib.interfaces.Dex; import network.balanced.score.lib.structs.PrepDelegations; import network.balanced.score.lib.structs.RewardsDataEntry; +import network.balanced.score.lib.utils.AddressDictDB; import network.balanced.score.lib.utils.BalancedFloorLimits; -import network.balanced.score.lib.utils.FloorLimited; +import network.balanced.score.lib.utils.NetworkAddressDictDB; import score.Address; import score.BranchDB; import score.Context; @@ -39,12 +41,13 @@ import static network.balanced.score.core.dex.utils.Check.isValidPercent; import static network.balanced.score.core.dex.utils.Check.isValidPoolId; import static network.balanced.score.core.dex.utils.Const.*; +import static network.balanced.score.lib.tokens.SpokeTokenImpl.NATIVE_NID; import static network.balanced.score.lib.utils.BalancedAddressManager.*; import static network.balanced.score.lib.utils.Check.onlyGovernance; import static network.balanced.score.lib.utils.Constants.*; import static network.balanced.score.lib.utils.Math.pow; -public abstract class AbstractDex extends FloorLimited implements Dex { +public abstract class AbstractDex extends IRC31StandardSpokeLpToken { public AbstractDex(Address _governance) { if (governance.get() == null) { @@ -81,16 +84,28 @@ public void MarketAdded(BigInteger _id, Address _baseToken, public void Add(BigInteger _id, Address _owner, BigInteger _value, BigInteger _base, BigInteger _quote) { } + @EventLog(indexed = 3) + public void AddV2(BigInteger _id, String _owner, BigInteger _value, BigInteger _base, BigInteger _quote) { + } + @EventLog(indexed = 3) public void Remove(BigInteger _id, Address _owner, BigInteger _value, BigInteger _base, BigInteger _quote) { } + @EventLog(indexed = 3) + public void RemoveV2(BigInteger _id, String _owner, BigInteger _value, BigInteger _base, BigInteger _quote) { + } + @EventLog(indexed = 2) - public void Deposit(Address _token, Address _owner, BigInteger _value) { + public void Deposit(Address _token, String _owner, BigInteger _value) { } +// @EventLog(indexed = 2) +// public void Withdraw(Address _token, Address _owner, BigInteger _value) { +// } + @EventLog(indexed = 2) - public void Withdraw(Address _token, Address _owner, BigInteger _value) { + public void Withdraw(Address _token, String _owner, BigInteger _value) { } @EventLog(indexed = 2) @@ -98,7 +113,7 @@ public void ClaimSicxEarnings(Address _owner, BigInteger _value) { } @EventLog(indexed = 3) - public void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value) { + public void TransferSingle(String _operator, String _from, String _to, BigInteger _id, BigInteger _value) { } @External(readonly = true) @@ -256,7 +271,14 @@ public boolean precompute(BigInteger snap, BigInteger batch_size) { @External(readonly = true) public BigInteger getDeposit(Address _tokenAddress, Address _user) { - return deposit.at(_tokenAddress).getOrDefault(_user, BigInteger.ZERO); + NetworkAddress user = new NetworkAddress(NATIVE_NID, _user); + return deposit.at(_tokenAddress).getOrDefault(user, BigInteger.ZERO); + } + + @External(readonly = true) + public BigInteger getDepositV2(Address _tokenAddress, String _user) { + NetworkAddress user = NetworkAddress.valueOf(_user); + return deposit.at(_tokenAddress).getOrDefault(user, BigInteger.ZERO); } @External(readonly = true) @@ -387,15 +409,6 @@ public BigInteger getPriceByName(String _name) { return getPrice(BigInteger.valueOf(namedMarkets.get(_name))); } - @External(readonly = true) - public BigInteger getICXBalance(Address _address) { - BigInteger orderId = icxQueueOrderId.get(_address); - if (orderId == null) { - return BigInteger.ZERO; - } - return icxQueue.getNode(orderId).getSize(); - } - @External(readonly = true) public Map getPoolStats(BigInteger _id) { isValidPoolId(_id); @@ -489,24 +502,6 @@ public void addLpAddresses(BigInteger _poolId, Address[] _addresses) { } } - @External(readonly = true) - public BigInteger balanceOf(Address _owner, BigInteger _id) { - if (_id.intValue() == SICXICX_POOL_ID) { - return getICXBalance(_owner); - } else { - return DexDBVariables.balance.at(_id.intValue()).getOrDefault(_owner, BigInteger.ZERO); - } - } - - @External(readonly = true) - public BigInteger totalSupply(BigInteger _id) { - if (_id.intValue() == SICXICX_POOL_ID) { - return icxQueueTotal.getOrDefault(BigInteger.ZERO); - } - - return poolLpTotal.getOrDefault(_id.intValue(), BigInteger.ZERO); - } - @External public void delegate(PrepDelegations[] prepDelegations) { onlyGovernance(); @@ -536,12 +531,12 @@ BigInteger getRewardableAmount(Address tokenAddress) { return BigInteger.ZERO; } - void deposit(Address token, Address to, BigInteger amount) { - DictDB depositDetails = deposit.at(token); + void deposit(Address token, NetworkAddress to, BigInteger amount) { + NetworkAddressDictDB depositDetails = deposit.at(token); BigInteger userBalance = depositDetails.getOrDefault(to, BigInteger.ZERO); userBalance = userBalance.add(amount); depositDetails.set(to, userBalance); - Deposit(token, to, amount); + Deposit(token, to.toString(), amount); if (tokenPrecisions.get(token) == null) { BigInteger decimalValue = (BigInteger) Context.call(token, "decimals"); @@ -675,13 +670,25 @@ public void govSetPoolTotal(int pid, BigInteger total) { @External public void govSetUserPoolTotal(int pid, Address user, BigInteger total) { onlyGovernance(); - BigInteger value = balance.at(pid).get(user); + NetworkAddress _user = new NetworkAddress(NATIVE_NID, user); + setUserPoolTotal(pid, _user, total); + } + + //todo: make sure if this method is required + @External + public void govSetUserPoolTotalV2(int pid, String user, BigInteger total) { + onlyGovernance(); + setUserPoolTotal(pid, NetworkAddress.parse(user), total); + } + private void setUserPoolTotal(int pid, NetworkAddress _user, BigInteger total){ + BigInteger value = balance.at(pid).get(_user); BigInteger burned = value.subtract(total); - balance.at(pid).set(user, total); + balance.at(pid).set(_user, total); - TransferSingle(Context.getCaller(), user, MINT_ADDRESS, BigInteger.valueOf(pid), burned); + TransferSingle(Context.getCaller().toString(), _user.toString(), MINT_ADDRESS.toString(), BigInteger.valueOf(pid), burned); } + void swapIcx(Address sender, BigInteger value) { BigInteger sicxIcxPrice = getSicxRate(); @@ -787,34 +794,4 @@ BigInteger snapshotValueAt(BigInteger _snapshot_id, return snapshot.at(VALUES).getOrDefault(matchedIndex, BigInteger.ZERO); } - void _transfer(Address from, Address to, BigInteger value, Integer id, byte[] data) { - - Context.require(!isLockingPool(id), TAG + ": Nontransferable token id"); - Context.require(value.compareTo(BigInteger.ZERO) >= 0, - TAG + ": Transferring value cannot be less than 0."); - - DictDB poolLpBalanceOfUser = balance.at(id); - BigInteger fromBalance = poolLpBalanceOfUser.getOrDefault(from, BigInteger.ZERO); - - Context.require(fromBalance.compareTo(value) >= 0, TAG + ": Out of balance"); - - poolLpBalanceOfUser.set(from, poolLpBalanceOfUser.get(from).subtract(value)); - poolLpBalanceOfUser.set(to, poolLpBalanceOfUser.getOrDefault(to, BigInteger.ZERO).add(value)); - Address stakedLpAddress = getStakedLp(); - - if (!from.equals(stakedLpAddress) && !to.equals(stakedLpAddress)) { - if (value.compareTo(BigInteger.ZERO) > 0) { - activeAddresses.get(id).add(to); - } - - if ((fromBalance.subtract(value)).equals(BigInteger.ZERO)) { - activeAddresses.get(id).remove(from); - } - } - TransferSingle(from, from, to, BigInteger.valueOf(id), value); - - if (to.isContract()) { - Context.call(to, "onIRC31Received", from, from, id, value, data); - } - } } 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 179670678..f0c1d8265 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 @@ -18,6 +18,8 @@ import network.balanced.score.core.dex.db.LinkedListDB; import network.balanced.score.core.dex.utils.LPMetadataDB; +import network.balanced.score.lib.utils.BranchedAddressDictDB; +import network.balanced.score.lib.utils.BranchedNetworkAddressDictDB; import network.balanced.score.lib.utils.IterableDictDB; import network.balanced.score.lib.utils.SetDB; import score.*; @@ -67,7 +69,9 @@ public class DexDBVariables { public final static VarDB dexOn = Context.newVarDB(DEX_ON, Boolean.class); // Deposits - Map: token_address -> user_address -> value - final static BranchDB> deposit = Context.newBranchDB(DEPOSIT, +// final static BranchDB> deposit = Context.newBranchDB(DEPOSIT, +// BigInteger.class); + final static BranchedNetworkAddressDictDB deposit = new BranchedNetworkAddressDictDB<>(DEPOSIT, BigInteger.class); // Pool IDs - Map: token address -> opposite token_address -> id final static BranchDB> poolId = Context.newBranchDB(POOL_ID, Integer.class); @@ -85,9 +89,12 @@ public class DexDBVariables { // User Balances // Map: pool_id -> user address -> lp token balance - final static BranchDB> balance = Context.newBranchDB(BALANCE, +// final static BranchDB> balance = Context.newBranchDB(BALANCE, +// BigInteger.class); + final static BranchedNetworkAddressDictDB balance = new BranchedNetworkAddressDictDB<>(BALANCE, BigInteger.class); + // Map: pool_id -> user address -> ids/values/length -> length/0 -> value final static BranchDB>>> accountBalanceSnapshot = Context.newBranchDB(ACCOUNT_BALANCE_SNAPSHOT, BigInteger.class); diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index 2726cc6e3..99a084c07 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -19,10 +19,10 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.core.dex.db.NodeDB; -import network.balanced.score.lib.structs.RewardsDataEntry; -import network.balanced.score.lib.utils.BalancedFloorLimits; -import network.balanced.score.lib.utils.Versions; +import network.balanced.score.lib.interfaces.DexXCall; +import network.balanced.score.lib.utils.*; import score.Address; import score.BranchDB; import score.Context; @@ -30,10 +30,8 @@ import score.annotation.External; import score.annotation.Optional; import score.annotation.Payable; -import scorex.util.ArrayList; import java.math.BigInteger; -import java.util.List; import static network.balanced.score.core.dex.DexDBVariables.*; import static network.balanced.score.core.dex.utils.Check.isDexOn; @@ -42,9 +40,11 @@ import static network.balanced.score.lib.utils.BalancedAddressManager.getRewards; import static network.balanced.score.lib.utils.BalancedAddressManager.getSicx; import static network.balanced.score.lib.utils.Check.checkStatus; +import static network.balanced.score.lib.utils.Check.only; import static network.balanced.score.lib.utils.Constants.EXA; import static network.balanced.score.lib.utils.Constants.POINTS; import static network.balanced.score.lib.utils.Math.convertToNumber; +import static score.Context.println; import static score.Context.require; public class DexImpl extends AbstractDex { @@ -55,6 +55,7 @@ public DexImpl(Address _governance) { Context.revert("Can't Update same version of code"); } currentVersion.set(Versions.DEX); + NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); } @External(readonly = true) @@ -125,11 +126,6 @@ public void cancelSicxicxOrder() { } private void sendRewardsData(Address user, BigInteger amount, BigInteger oldIcxTotal) { - List rewardsList = new ArrayList<>(); - RewardsDataEntry rewardsEntry = new RewardsDataEntry(); - rewardsEntry._user = user.toString(); - rewardsEntry._balance = amount; - rewardsList.add(rewardsEntry); Context.call(getRewards(), "updateBalanceAndSupply", SICXICX_MARKET_NAME, oldIcxTotal, user.toString(), amount); } @@ -139,23 +135,30 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { String unpackedData = new String(_data); require(!unpackedData.equals(""), "Token Fallback: Data can't be empty"); - JsonObject json = Json.parse(unpackedData).asObject(); - String method = json.get("method").asString(); - Address fromToken = Context.getCaller(); + Address fromToken = Context.getCaller(); require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Invalid token transfer value"); if (method.equals("_deposit")) { JsonObject params = json.get("params").asObject(); - Address to = Address.fromString(params.get("address").asString()); - deposit(fromToken, to, _value); - } else {// If no supported method was sent, revert the transaction + String to = params.get("address").asString(); + deposit(fromToken, NetworkAddress.valueOf(to), _value); + } else { + // If no supported method was sent, revert the transaction Context.revert(100, TAG + ": Unsupported method supplied"); } } + @External + public void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) { + checkStatus(); + only(BalancedAddressManager.getXCall()); + XCallUtils.verifyXCallProtocols(_from, _protocols); + DexXCall.process(this, _from, _data); + } + @External public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { isDexOn(); @@ -168,14 +171,14 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { JsonObject json = Json.parse(unpackedData).asObject(); String method = json.get("method").asString(); - Address fromToken = Context.getCaller(); - + Address fromToken = Context.getCaller(); require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Invalid token transfer value"); // Call an internal method based on the "method" param sent in tokenFallBack switch (method) { case "_deposit": { - deposit(fromToken, _from, _value); + NetworkAddress from = new NetworkAddress(NATIVE_NID, _from); + deposit(fromToken, from, _value); break; } case "_swap_icx": { @@ -233,41 +236,69 @@ public void transfer(Address _to, BigInteger _value, BigInteger _id, @Optional b if (_data == null) { _data = new byte[0]; } - _transfer(Context.getCaller(), _to, _value, _id.intValue(), _data); + NetworkAddress from = new NetworkAddress(NATIVE_NID, Context.getCaller()); + NetworkAddress to = new NetworkAddress(NATIVE_NID, _to); + _transfer( from, to, _value, _id.intValue(), _data); + } + + public void xWithdraw(String from, Address _token, BigInteger _value) { + NetworkAddress sender = NetworkAddress.valueOf(from); + _withdraw(sender, _token, _value); } @External public void withdraw(Address _token, BigInteger _value) { + Address caller = Context.getCaller(); + NetworkAddress sender = new NetworkAddress(NATIVE_NID, caller); + _withdraw(sender, _token, _value); + } + + private void _withdraw(NetworkAddress sender, Address _token, BigInteger _value){ isDexOn(); checkStatus(); require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Must specify a positive amount"); - Address sender = Context.getCaller(); - DictDB depositDetails = deposit.at(_token); + NetworkAddressDictDB depositDetails = deposit.at(_token); + BigInteger deposit_amount = depositDetails.getOrDefault(sender, BigInteger.ZERO); require(_value.compareTo(deposit_amount) <= 0, TAG + ": Insufficient Balance"); depositDetails.set(sender, deposit_amount.subtract(_value)); - Withdraw(_token, sender, _value); + Withdraw(_token, sender.toString(), _value); BalancedFloorLimits.verifyWithdraw(_token, _value); - Context.call(_token, "transfer", sender, _value); + if(sender.net().equals(NATIVE_NID)) { + Context.call(_token, "transfer", Address.fromString(sender.account()), _value); + }else{ + Context.call(_token, "hubTransfer", sender.toString(), _value); + } } @External(readonly = true) public BigInteger depositOfUser(Address _owner, Address _token) { - DictDB depositDetails = deposit.at(_token); - return depositDetails.getOrDefault(_owner, BigInteger.ZERO); + NetworkAddress owner = new NetworkAddress(NATIVE_NID, _owner); + NetworkAddressDictDB depositDetails = deposit.at(_token); + return depositDetails.getOrDefault(owner, BigInteger.ZERO); + } + + public void xRemove(String from, BigInteger id, BigInteger value, @Optional Boolean _withdraw) { + NetworkAddress _from = NetworkAddress.valueOf(from); + _remove(id, _from, value, _withdraw); } @External public void remove(BigInteger _id, BigInteger _value, @Optional boolean _withdraw) { + NetworkAddress owner = new NetworkAddress(NATIVE_NID, Context.getCaller()); + _remove(_id, owner, _value, _withdraw); + } + + + void _remove(BigInteger _id, NetworkAddress _user, BigInteger _value, @Optional boolean _withdraw) { isDexOn(); checkStatus(); - Address user = Context.getCaller(); Address baseToken = poolBase.get(_id.intValue()); require(baseToken != null, TAG + ": invalid pool id"); - DictDB userLPBalance = balance.at(_id.intValue()); - BigInteger userBalance = userLPBalance.getOrDefault(user, BigInteger.ZERO); + NetworkAddressDictDB userLPBalance = balance.at(_id.intValue()); + BigInteger userBalance = userLPBalance.getOrDefault(_user, BigInteger.ZERO); require(active.getOrDefault(_id.intValue(), false), TAG + ": Pool is not active"); require(_value.compareTo(BigInteger.ZERO) > 0, TAG + " Cannot withdraw a negative or zero balance"); @@ -283,7 +314,8 @@ public void remove(BigInteger _id, BigInteger _value, @Optional boolean _withdra if (userQuoteLeft.compareTo(getRewardableAmount(quoteToken)) < 0) { _value = userBalance; - activeAddresses.get(_id.intValue()).remove(user); + //todo: verify we don't need activeAddresses + //activeAddresses.get(_id.intValue()).remove(_user); } BigInteger baseToWithdraw = _value.multiply(totalBase).divide(totalLPToken); @@ -299,36 +331,40 @@ public void remove(BigInteger _id, BigInteger _value, @Optional boolean _withdra totalTokensInPool.set(baseToken, newBase); totalTokensInPool.set(quoteToken, newQuote); - userLPBalance.set(user, newUserBalance); + userLPBalance.set(_user, newUserBalance); poolLpTotal.set(_id.intValue(), newTotal); - Remove(_id, user, _value, baseToWithdraw, quoteToWithdraw); - TransferSingle(user, user, MINT_ADDRESS, _id, _value); + //todo: uncomment after + RemoveV2(_id, _user.toString(), _value, baseToWithdraw, quoteToWithdraw); +// TransferSingle(_user, _user, MINT_ADDRESS, _id, _value); - DictDB userBaseDeposit = deposit.at(baseToken); - BigInteger depositedBase = userBaseDeposit.getOrDefault(user, BigInteger.ZERO); - userBaseDeposit.set(user, depositedBase.add(baseToWithdraw)); + NetworkAddressDictDB userBaseDeposit = deposit.at(baseToken); + BigInteger depositedBase = userBaseDeposit.getOrDefault(_user, BigInteger.ZERO); + userBaseDeposit.set(_user, depositedBase.add(baseToWithdraw)); - DictDB userQuoteDeposit = deposit.at(quoteToken); - BigInteger depositedQuote = userQuoteDeposit.getOrDefault(user, BigInteger.ZERO); - userQuoteDeposit.set(user, depositedQuote.add(quoteToWithdraw)); + NetworkAddressDictDB userQuoteDeposit = deposit.at(quoteToken); + BigInteger depositedQuote = userQuoteDeposit.getOrDefault(_user, BigInteger.ZERO); + userQuoteDeposit.set(_user, depositedQuote.add(quoteToWithdraw)); if (_withdraw) { - withdraw(baseToken, baseToWithdraw); - withdraw(quoteToken, quoteToWithdraw); + xWithdraw(_user.toString(), baseToken, baseToWithdraw); + xWithdraw(_user.toString(), quoteToken, quoteToWithdraw); } } - @External - public void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, - @Optional boolean _withdraw_unused, @Optional BigInteger _slippagePercentage) { + public void xAdd(String from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, + @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage) { isDexOn(); checkStatus(); isValidPercent(_slippagePercentage.intValue()); - Address user = Context.getCaller(); + addInternal(NetworkAddress.parse(from), _baseToken, _quoteToken, _baseValue, _quoteValue, + _withdraw_unused, _slippagePercentage); + } + public void addInternal(NetworkAddress _from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, + @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage){ // We check if there is a previously seen pool with this id. // If none is found (return 0), we create a new pool. Integer id = poolId.at(_baseToken).getOrDefault(_quoteToken, 0); @@ -340,8 +376,8 @@ public void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, require(_quoteValue.compareTo(BigInteger.ZERO) > 0, TAG + ": Cannot send 0 or negative quote token"); - BigInteger userDepositedBase = deposit.at(_baseToken).getOrDefault(user, BigInteger.ZERO); - BigInteger userDepositedQuote = deposit.at(_quoteToken).getOrDefault(user, BigInteger.ZERO); + BigInteger userDepositedBase = deposit.at(_baseToken).getOrDefault(_from, BigInteger.ZERO); + BigInteger userDepositedQuote = deposit.at(_quoteToken).getOrDefault(_from, BigInteger.ZERO); // Check deposits are sufficient to cover balances require(userDepositedBase.compareTo(_baseValue) >= 0, @@ -357,7 +393,7 @@ public void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger poolBaseAmount = BigInteger.ZERO; BigInteger poolQuoteAmount = BigInteger.ZERO; BigInteger poolLpAmount = poolLpTotal.getOrDefault(id, BigInteger.ZERO); - BigInteger userLpAmount = balance.at(id).getOrDefault(user, BigInteger.ZERO); + BigInteger userLpAmount = balance.at(id).getOrDefault(_from, BigInteger.ZERO); // We need to only supply new base and quote in the pool ratio. // If there isn't a pool yet, we can form one with the supplied ratios. @@ -436,20 +472,23 @@ public void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, // Deduct the user's deposit userDepositedBase = userDepositedBase.subtract(baseToCommit); - deposit.at(_baseToken).set(user, userDepositedBase); + deposit.at(_baseToken).set(_from, userDepositedBase); userDepositedQuote = userDepositedQuote.subtract(quoteToCommit); - deposit.at(_quoteToken).set(user, userDepositedQuote); + deposit.at(_quoteToken).set(_from, userDepositedQuote); // Credit the user LP Tokens userLpAmount = userLpAmount.add(liquidity); poolLpAmount = poolLpAmount.add(liquidity); - balance.at(id).set(user, userLpAmount); + balance.at(id).set(_from, userLpAmount); poolLpTotal.set(id, poolLpAmount); - Add(BigInteger.valueOf(id), user, liquidity, baseToCommit, quoteToCommit); - TransferSingle(user, MINT_ADDRESS, user, BigInteger.valueOf(id), liquidity); + AddV2(BigInteger.valueOf(id), _from.toString(), liquidity, baseToCommit, quoteToCommit); + //todo: check if this event solves + //TransferSingle(from, MINT_ADDRESS.toString(), from, BigInteger.valueOf(id), liquidity); + HubTransfer(BigInteger.valueOf(id), MINT_ADDRESS.toString(), _from.toString(), liquidity, new byte[0]); - activeAddresses.get(id).add(user); + //todo: fix and uncomment + //activeAddresses.get(id).add(from); if (userDepositedBase.compareTo(BigInteger.ZERO) > 0) { withdraw(_baseToken, userDepositedBase); @@ -460,6 +499,20 @@ public void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, } } + + @External + public void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, + @Optional boolean _withdraw_unused, @Optional BigInteger _slippagePercentage) { + isDexOn(); + checkStatus(); + isValidPercent(_slippagePercentage.intValue()); + + NetworkAddress user = new NetworkAddress(NATIVE_NID, Context.getCaller()); + addInternal(user, _baseToken, _quoteToken, _baseValue, _quoteValue, + _withdraw_unused, _slippagePercentage); + + } + @External public void withdrawSicxEarnings(@Optional BigInteger _value) { isDexOn(); diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java new file mode 100644 index 000000000..309dc8146 --- /dev/null +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java @@ -0,0 +1,131 @@ +package network.balanced.score.core.dex; + + +import network.balanced.score.lib.interfaces.Dex; +import network.balanced.score.lib.utils.*; +import score.Address; +import score.Context; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Optional; + +import java.math.BigInteger; + +import foundation.icon.xcall.NetworkAddress; +import static network.balanced.score.core.dex.DexDBVariables.*; +import static network.balanced.score.core.dex.DexDBVariables.poolLpTotal; +import static network.balanced.score.core.dex.utils.Const.SICXICX_POOL_ID; +import static network.balanced.score.core.dex.utils.Const.TAG; + +public abstract class IRC31StandardSpokeLpToken extends FloorLimited implements Dex { + + public static String NATIVE_NID; + + @External(readonly = true) + public BigInteger balanceOf(Address _owner, BigInteger _id) { + if (_id.intValue() == SICXICX_POOL_ID) { + return getICXBalance(_owner); + } else { + NetworkAddress owner = new NetworkAddress(NATIVE_NID, _owner); + return DexDBVariables.balance.at(_id.intValue()).getOrDefault(owner, BigInteger.ZERO); + } + } + + @External(readonly = true) + public BigInteger xBalanceOf(String _owner, BigInteger _id) { + NetworkAddress address = NetworkAddress.valueOf(_owner); + return DexDBVariables.balance.at(_id.intValue()).getOrDefault(address, BigInteger.ZERO); + } + + @External + public void transfer(Address _to, BigInteger _value, BigInteger _id, @Optional byte[] _data) { + _transfer( + new NetworkAddress(NATIVE_NID, Context.getCaller()), + new NetworkAddress(NATIVE_NID, _to), + _value, + _id.intValue(), + _data); + } + + @External + public void hubTransfer(String _to, BigInteger _value, BigInteger _id, @Optional byte[] _data) { + _transfer( + new NetworkAddress(NATIVE_NID, Context.getCaller()), + NetworkAddress.valueOf(_to, NATIVE_NID), + _value, + _id.intValue(), + _data); + } + + + public void xHubTransfer(String from, String _to, BigInteger _value, BigInteger _id, byte[] _data) { + _transfer( + NetworkAddress.valueOf(from), + NetworkAddress.valueOf(_to), + _value, + _id.intValue(), + _data); + } + + @External(readonly = true) + public BigInteger getICXBalance(Address _address) { + BigInteger orderId = icxQueueOrderId.get(_address); + if (orderId == null) { + return BigInteger.ZERO; + } + return icxQueue.getNode(orderId).getSize(); + } + + @External(readonly = true) + public BigInteger totalSupply(BigInteger _id) { + if (_id.intValue() == SICXICX_POOL_ID) { + return icxQueueTotal.getOrDefault(BigInteger.ZERO); + } + + return poolLpTotal.getOrDefault(_id.intValue(), BigInteger.ZERO); + } + + void _transfer(NetworkAddress _from, NetworkAddress _to, BigInteger _value, Integer _id, byte[] _data) { + + Context.require(!isLockingPool(_id), TAG + ": Nontransferable token id"); + Context.require(_value.compareTo(BigInteger.ZERO) >= 0, + TAG + ": Transferring value cannot be less than 0."); + + NetworkAddressDictDB poolLpBalanceOfUser = balance.at(_id); + BigInteger fromBalance = poolLpBalanceOfUser.getOrDefault(_from, BigInteger.ZERO); + + Context.require(fromBalance.compareTo(_value) >= 0, TAG + ": Out of balance"); + + poolLpBalanceOfUser.set(_from, poolLpBalanceOfUser.get(_from).subtract(_value)); + poolLpBalanceOfUser.set(_to, poolLpBalanceOfUser.getOrDefault(_to, BigInteger.ZERO).add(_value)); + + byte[] dataBytes = (_data == null) ? "None".getBytes() : _data; + + HubTransfer(BigInteger.valueOf(_id), _from.toString(), _to.toString(), _value, dataBytes); + if (!_to.net().equals(NATIVE_NID)) { + return; + } + + Address contractAddress = Address.fromString(_to.account()); + if (!contractAddress.isContract()) { + return; + } + + Context.call(contractAddress, "onIRC31Received", _from.toString(), _from.toString(), _id, _value, dataBytes); + } + + protected boolean isNative(NetworkAddress address) { + return address.net().equals(NATIVE_NID); + } + + boolean isLockingPool(Integer id) { + return id.equals(SICXICX_POOL_ID); + } + + @EventLog(indexed = 3) + public void HubTransfer(BigInteger _id, String _from, String _to, BigInteger _value, byte[] _data) { + } + @EventLog(indexed = 3) + public void Transfer(Address _from, Address _to, BigInteger _value, byte[] _data) { + } +} diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java index f3e2e9917..90c61905f 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java @@ -19,8 +19,10 @@ import com.iconloop.score.test.Account; import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.test.UnitTest; import network.balanced.score.lib.test.mock.MockBalanced; +import network.balanced.score.lib.utils.BalancedAddressManager; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.stubbing.Answer; @@ -35,8 +37,7 @@ import static network.balanced.score.lib.utils.Constants.EXA; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.*; class DexTestBase extends UnitTest { @@ -57,10 +58,14 @@ class DexTestBase extends UnitTest { protected Account feehandlerScore; protected Account stakedLPScore; protected Account balancedOracle; + protected Account xcallScore; + public static Score dexScore; public static DexImpl dexScoreSpy; + private final String NATIVE_NID = "0x1.ICON"; + protected final MockedStatic contextMock = Mockito.mockStatic(Context.class, Mockito.CALLS_REAL_METHODS); public void setup() throws Exception { @@ -75,10 +80,12 @@ public void setup() throws Exception { feehandlerScore = mockBalanced.feehandler.account; stakedLPScore = mockBalanced.stakedLp.account; balancedOracle = mockBalanced.balancedOracle.account; + xcallScore = mockBalanced.xCall.account; contextMock.when(() -> Context.call(eq(governanceScore.getAddress()), eq("checkStatus"), any(String.class))).thenReturn(null); contextMock.when(() -> Context.call(eq(BigInteger.class), any(Address.class), eq("balanceOf"), any(Address.class))).thenReturn(BigInteger.ZERO); + contextMock.when(() -> Context.call(eq(BalancedAddressManager.getXCall()), eq("getNetworkId"))).thenReturn(NATIVE_NID); dexScore = sm.deploy(ownerAccount, DexImpl.class, governanceScore.getAddress()); dexScore.invoke(governanceScore, "setTimeOffset", BigInteger.valueOf(Context.getBlockTimestamp())); dexScoreSpy = (DexImpl) spy(dexScore.getInstance()); @@ -95,10 +102,20 @@ protected void depositToken(Account depositor, Account tokenScore, BigInteger va new HashMap<>())); } - protected void xDepositToken(String depositor, Account to, Account tokenScore, BigInteger value) { + protected void xDepositToken(String depositor, String to, Account tokenScore, BigInteger value) { contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); dexScore.invoke(tokenScore, "xTokenFallback", depositor, value, tokenData("_deposit", - Map.of("address", to.getAddress().toString()))); + Map.of("address", to))); + } + + /* + * String _from, byte[] _data, @Optional String[] _protocols + * */ + + protected void handleCallMessageWithOutProtocols(String from, byte[] data, String[] protocols ) { + NetworkAddress fromNetworkAddress = NetworkAddress.parse(from); + contextMock.when(() -> Context.call(eq(BalancedAddressManager.getXCallManager()), eq("verifyProtocols"), eq(fromNetworkAddress.net()), eq(protocols))).thenReturn(true); + dexScore.invoke(xcallScore, "handleCallMessage", from, data, protocols); } protected void supplyLiquidity(Account supplier, Account baseTokenScore, Account quoteTokenScore, diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java index 27fd9f836..3f925c360 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.function.Executable; import org.mockito.stubbing.Answer; import score.Address; +import score.ByteArrayObjectWriter; import score.Context; import java.math.BigInteger; @@ -35,6 +36,7 @@ import static network.balanced.score.core.dex.utils.Const.*; import static network.balanced.score.lib.utils.Constants.EXA; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -109,13 +111,137 @@ void cancelSicxIcxOrder() { @Test void crossChainDeposit() { - Account user = sm.createAccount(); + String fromNetworkAddress = "0x1.ETH/0x123"; BigInteger depositValue = BigInteger.valueOf(100).multiply(EXA); - xDepositToken("0x1.ETH/0x123", user, bnusdScore, depositValue); - BigInteger retrievedValue = (BigInteger) dexScore.call("getDeposit", bnusdScore.getAddress(), user.getAddress()); + xDepositToken(fromNetworkAddress, fromNetworkAddress, bnusdScore, depositValue); + BigInteger retrievedValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); assertEquals(depositValue, retrievedValue); } + @Test + void crossChainLP(){ + // Arrange + String fromNetworkAddress = "0x1.ETH/0x123"; + BigInteger depositValue = BigInteger.valueOf(100).multiply(EXA); + xDepositToken(fromNetworkAddress, fromNetworkAddress, bnusdScore, depositValue); + BigInteger retrievedValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); + assertEquals(depositValue, retrievedValue); + + xDepositToken(fromNetworkAddress, fromNetworkAddress, sicxScore, depositValue); + BigInteger sicxValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); + assertEquals(depositValue, sicxValue); + + // Act + String[] protocols = new String[0]; + byte[] data = getAddLPData(bnusdScore.getAddress(), sicxScore.getAddress(), depositValue, depositValue, false, BigInteger.ZERO); + handleCallMessageWithOutProtocols(fromNetworkAddress, data, protocols); + + // Assert + BigInteger poolId = (BigInteger) dexScore.call("getPoolId", bnusdScore.getAddress(), sicxScore.getAddress()); + BigInteger lpTokenBalance = (BigInteger) dexScore.call("xBalanceOf", fromNetworkAddress, poolId); + assertTrue(lpTokenBalance.compareTo(BigInteger.ZERO)>0); + + } + + @Test + void xRemoveNotWithdraw(){ + // Arrange + String fromNetworkAddress = "0x1.ETH/0x123"; + BigInteger depositValue = BigInteger.valueOf(100).multiply(EXA); + xDepositToken(fromNetworkAddress, fromNetworkAddress, bnusdScore, depositValue); + BigInteger retrievedValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); + assertEquals(depositValue, retrievedValue); + + xDepositToken(fromNetworkAddress, fromNetworkAddress, sicxScore, depositValue); + BigInteger sicxValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); + assertEquals(depositValue, sicxValue); + + String[] protocols = new String[0]; + byte[] data = getAddLPData(bnusdScore.getAddress(), sicxScore.getAddress(), depositValue, depositValue, false, BigInteger.ZERO); + handleCallMessageWithOutProtocols(fromNetworkAddress, data, protocols); + + BigInteger poolId = (BigInteger) dexScore.call("getPoolId", bnusdScore.getAddress(), sicxScore.getAddress()); + BigInteger lpTokenBalance = (BigInteger) dexScore.call("xBalanceOf", fromNetworkAddress, poolId); + BigInteger lpTokensToRemove = BigInteger.valueOf(1000); + + // Arrange - increase blocks past withdrawal lock. + sm.getBlock().increase(100000000); + + + //Act + byte[] xRemoveData = getXRemoveData(poolId, lpTokensToRemove, false); + + contextMock.when(() -> Context.call(eq(stakingScore.getAddress()), eq("getTodayRate"))).thenReturn(EXA); + handleCallMessageWithOutProtocols(fromNetworkAddress, xRemoveData, protocols); + + // + BigInteger newLpTokenBalance = (BigInteger) dexScore.call("xBalanceOf", fromNetworkAddress, poolId); + assertEquals(lpTokenBalance.subtract(lpTokensToRemove), newLpTokenBalance); + } + + @Test + void xRemoveAndWithdraw(){ + // Arrange - deposit tokens + String fromNetworkAddress = "0x1.ETH/0x123"; + BigInteger depositValue = BigInteger.valueOf(100).multiply(EXA); + xDepositToken(fromNetworkAddress, fromNetworkAddress, bnusdScore, depositValue); + BigInteger retrievedValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); + assertEquals(depositValue, retrievedValue); + + xDepositToken(fromNetworkAddress, fromNetworkAddress, sicxScore, depositValue); + BigInteger sicxValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); + assertEquals(depositValue, sicxValue); + + // Arrange supply liquidity + String[] protocols = new String[0]; + byte[] data = getAddLPData(bnusdScore.getAddress(), sicxScore.getAddress(), depositValue, depositValue, false, BigInteger.ZERO); + handleCallMessageWithOutProtocols(fromNetworkAddress, data, protocols); + + BigInteger poolId = (BigInteger) dexScore.call("getPoolId", bnusdScore.getAddress(), sicxScore.getAddress()); + BigInteger lpTokenBalance = (BigInteger) dexScore.call("xBalanceOf", fromNetworkAddress, poolId); + BigInteger lpTokensToRemove = BigInteger.valueOf(1000); + + // Arrange - increase blocks past withdrawal lock. + sm.getBlock().increase(100000000); + + + // Act + byte[] xRemoveData = getXRemoveData(poolId, lpTokensToRemove, true); + contextMock.when(() -> Context.call(eq(bnusdScore.getAddress()), eq("hubTransfer"), any(), any())).thenReturn(true); + contextMock.when(() -> Context.call(eq(sicxScore.getAddress()), eq("hubTransfer"), any(), any())).thenReturn(true); + contextMock.when(() -> Context.call(eq(stakingScore.getAddress()), eq("getTodayRate"))).thenReturn(EXA); + handleCallMessageWithOutProtocols(fromNetworkAddress, xRemoveData, protocols); + + // Verify + BigInteger newLpTokenBalance = (BigInteger) dexScore.call("xBalanceOf", fromNetworkAddress, poolId); + assertEquals(lpTokenBalance.subtract(lpTokensToRemove), newLpTokenBalance); + } + + static byte[] getXRemoveData(BigInteger poolId, BigInteger lpTokenBalance, Boolean withdraw) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(4); + writer.write("xremove"); + writer.write(poolId); + writer.write(lpTokenBalance); + writer.write(withdraw); + writer.end(); + return writer.toByteArray(); + } + + static byte[] getAddLPData(Address baseToken, Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(7); + writer.write("xadd"); + writer.write(baseToken); + writer.write(quoteToken); + writer.write(baseValue); + writer.write(quoteValue); + writer.write(withdraw_unused); + writer.write(slippagePercentage); + writer.end(); + return writer.toByteArray(); + } + @Test void withdrawSicxEarnings() { Account depositor = sm.createAccount(); diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java index 4e4aede91..a70648e31 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java @@ -567,6 +567,7 @@ void getPoolName() { // Assert. String retrievedPoolName = (String) dexScore.call("getPoolName", poolId); assertEquals(poolName, retrievedPoolName); + } @Test @@ -604,21 +605,22 @@ void getPoolStats_notSicxIcxPool() { assertEquals(expectedPoolStats, poolStats); } - @Test - void getTotalDexAddresses() { - // Arrange. - BigInteger bnusdValue = BigInteger.valueOf(195).multiply(EXA); - BigInteger balnValue = BigInteger.valueOf(350).multiply(EXA); - BigInteger poolId = BigInteger.TWO; - - // Act. - supplyLiquidity(governanceScore, bnusdScore, balnScore, bnusdValue, balnValue, false); - supplyLiquidity(ownerAccount, bnusdScore, balnScore, bnusdValue, balnValue, false); - - // Assert - BigInteger totalDexAddresses = (BigInteger) dexScore.call("totalDexAddresses", BigInteger.TWO); - assertEquals(BigInteger.TWO, totalDexAddresses); - } + //todo: verify and +// @Test +// void getTotalDexAddresses() { +// // Arrange. +// BigInteger bnusdValue = BigInteger.valueOf(195).multiply(EXA); +// BigInteger balnValue = BigInteger.valueOf(350).multiply(EXA); +// BigInteger poolId = BigInteger.TWO; +// +// // Act. +// supplyLiquidity(governanceScore, bnusdScore, balnScore, bnusdValue, balnValue, false); +// supplyLiquidity(ownerAccount, bnusdScore, balnScore, bnusdValue, balnValue, false); +// +// // Assert +// BigInteger totalDexAddresses = (BigInteger) dexScore.call("totalDexAddresses", BigInteger.TWO); +// assertEquals(BigInteger.TWO, totalDexAddresses); +// } @Test void permit_OnlyGovernance() { diff --git a/core-contracts/Rewards/build.gradle b/core-contracts/Rewards/build.gradle index 084dc25f5..7beae42c1 100644 --- a/core-contracts/Rewards/build.gradle +++ b/core-contracts/Rewards/build.gradle @@ -29,6 +29,7 @@ dependencies { implementation Dependencies.javaeeScorex implementation project(':score-lib') implementation Dependencies.minimalJson + implementation 'xyz.venture23:xcall-lib:2.1.0' testImplementation Dependencies.javaeeUnitTest testImplementation Dependencies.junitJupiter diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java index 7db2f9452..5ab60e517 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java @@ -16,25 +16,22 @@ package network.balanced.score.core.rewards; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.core.rewards.utils.BalanceData; import network.balanced.score.core.rewards.weight.SourceWeightController; import network.balanced.score.lib.interfaces.Rewards; +import network.balanced.score.lib.interfaces.RewardsXCall; import network.balanced.score.lib.structs.Point; import network.balanced.score.lib.structs.RewardsDataEntry; import network.balanced.score.lib.structs.RewardsDataEntryOld; import network.balanced.score.lib.structs.VotedSlope; -import network.balanced.score.lib.utils.ArrayDBUtils; -import network.balanced.score.lib.utils.IterableDictDB; -import network.balanced.score.lib.utils.Names; -import network.balanced.score.lib.utils.SetDB; -import network.balanced.score.lib.utils.Versions; +import network.balanced.score.lib.utils.*; import score.*; import score.annotation.EventLog; import score.annotation.External; import score.annotation.Optional; import scorex.util.ArrayList; import scorex.util.HashMap; -import network.balanced.score.lib.utils.BalancedAddressManager; import java.math.BigInteger; import java.util.List; @@ -94,7 +91,7 @@ public class RewardsImpl implements Rewards { new IterableDictDB<>(FIXED_DISTRIBUTION_PERCENTAGES, BigInteger.class, String.class, false); private final VarDB currentVersion = Context.newVarDB(VERSION, String.class); - + private static String NATIVE_NID; public RewardsImpl(@Optional Address _governance) { SourceWeightController.rewards = this; @@ -123,6 +120,7 @@ public RewardsImpl(@Optional Address _governance) { Context.revert("Can't Update same version of code"); } currentVersion.set(Versions.REWARDS); + NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); } @External(readonly = true) @@ -390,15 +388,33 @@ public void boost(String[] sources) { updateAllUserRewards(user.toString(), sources, boostedBalance, boostedSupply); } + @External + public void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) { + checkStatus(); + only(BalancedAddressManager.getXCall()); + XCallUtils.verifyXCallProtocols(_from, _protocols); + RewardsXCall.process(this, _from, _data); + } + + public void xClaimRewards(String from, @Optional String to, @Optional String[] sources) { + if (to.isEmpty()){ + to = from; + } + _claimRewards(to, sources); + } + @External public void claimRewards(@Optional String[] sources) { checkStatus(); - if (sources == null) { + if (sources == null || sources.length==0) { sources = getAllSources(); } - Address caller = Context.getCaller(); - String address = caller.toString(); - BigInteger boostedBalance = fetchBoostedBalance(caller); + _claimRewards(Context.getCaller().toString(), sources); + } + + private void _claimRewards(String address, String[] sources){ + NetworkAddress networkAddress = NetworkAddress.valueOf(address, NATIVE_NID); + BigInteger boostedBalance = fetchBoostedBalance(address); BigInteger boostedSupply = fetchBoostedSupply(); updateAllUserRewards(address, sources, boostedBalance, boostedSupply); @@ -408,7 +424,13 @@ public void claimRewards(@Optional String[] sources) { for (Address token : tokens) { BigInteger amount = holdingsDB.getOrDefault(token, BigInteger.ZERO); if (amount.compareTo(BigInteger.ZERO) > 0) { - Context.call(token, "transfer", caller, amount, new byte[0]); + if(networkAddress.net().equals(NATIVE_NID)) { + Context.call(token, "transfer", Address.fromString(networkAddress.account()), amount, new byte[0]); + }else{ + try { + Context.call(token, "xTransfer", address, amount, new byte[0]); + }catch (Exception ignored){} + } holdingsDB.set(token, null); RewardsClaimedV2(token, address, amount); } @@ -418,13 +440,20 @@ public void claimRewards(@Optional String[] sources) { if (userClaimableRewards.compareTo(BigInteger.ZERO) > 0) { balnHoldings.set(address, null); Address baln = getBaln(); + if(networkAddress.net().equals(NATIVE_NID)) { + Address nativeAddress = Address.fromString(networkAddress.account()); + Context.call(baln, "transfer", nativeAddress, userClaimableRewards, new byte[0]); + RewardsClaimed(nativeAddress, userClaimableRewards); + }else{ + try { + Context.call(baln, "xTransfer", address, userClaimableRewards, new byte[0]); + }catch (Exception ignored){} + } - Context.call(baln, "transfer", caller, userClaimableRewards, new byte[0]); - RewardsClaimed(caller, userClaimableRewards); RewardsClaimedV2(baln, address, userClaimableRewards); } - } + } @External public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { checkStatus(); diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java index e8a7b3a7e..28b897175 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java @@ -65,6 +65,10 @@ class RewardsTestBase extends UnitTest { Score rewardsScore; + RewardsImpl rewardsScoreSpy; + + public final String NATIVE_NID = "0x1.ICON"; + void setup() throws Exception { mockBalanced = new MockBalanced(sm, owner); governance = mockBalanced.governance.account; @@ -81,8 +85,11 @@ void setup() throws Exception { BigInteger startTime = BigInteger.valueOf(sm.getBlock().getTimestamp()); // One vote period before being able to start voting sm.getBlock().increase(DAY*10); + when(mockBalanced.xCall.mock.getNetworkId()).thenReturn(NATIVE_NID); rewardsScore = sm.deploy(owner, RewardsImpl.class, governance.getAddress()); + rewardsScoreSpy = (RewardsImpl) spy(rewardsScore.getInstance()); + rewardsScore.setInstance(rewardsScoreSpy); setupDistributions(); rewardsScore.invoke(owner, "setTimeOffset", startTime); rewardsScore.invoke(owner, "addDataProvider", loans.getAddress()); @@ -146,6 +153,16 @@ void mockBalanceAndSupply(MockContract dataSource, String when(dataSource.mock.getBalanceAndSupply(name, address.toString())).thenReturn(balanceAndSupply); } + void mockBalanceAndSupply(MockContract dataSource, String name, String address, + BigInteger balance, BigInteger supply) { + Map balanceAndSupply = Map.of( + "_balance", balance, + "_totalSupply", supply + ); + + when(dataSource.mock.getBalanceAndSupply(name, address)).thenReturn(balanceAndSupply); + } + void verifyBalnReward(Address address, BigInteger expectedReward) { verify(baln.mock, times(1)).transfer(eq(address), argThat(reward -> { assertEquals(expectedReward.divide(BigInteger.valueOf(100)), reward.divide(BigInteger.valueOf(100))); diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java index a6399822b..85f48d444 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java @@ -24,8 +24,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; +import score.ByteArrayObjectWriter; +import score.Context; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static network.balanced.score.lib.utils.Constants.MICRO_SECONDS_IN_A_DAY; import static network.balanced.score.lib.utils.Constants.MICRO_SECONDS_IN_A_SECOND; @@ -321,4 +324,76 @@ void externalRewards_verification() { BigInteger.ONE, data.toString().getBytes()); expectErrorMessage(invalidAmounts, "Total allocations do not match amount deposited"); } + + @Test + @SuppressWarnings("unchecked") + void externalRewards_crosschain() { + // Arrange + String fromNetworkAddress = "0x1.ETH/0x123"; + Account supplyAccount = sm.createAccount(); + BigInteger balance1 = BigInteger.TWO.multiply(EXA); + BigInteger balance2 = BigInteger.valueOf(3).multiply(EXA); + BigInteger totalSupply1 = BigInteger.TEN.multiply(EXA); + BigInteger totalSupply2 = BigInteger.valueOf(30).multiply(EXA); + BigInteger sICXRewards1 = BigInteger.valueOf(1000).multiply(EXA); + BigInteger sICXRewards2 = BigInteger.valueOf(1500).multiply(EXA); + BigInteger expectedRewards = BigInteger.valueOf(200).multiply(EXA); + + // Arrange - Update rewards + rewardsScore.invoke(dex.account, "updateBalanceAndSupply", "sICX/ICX", totalSupply1.subtract(balance1), + supplyAccount.getAddress().toString(), totalSupply1.subtract(balance1)); + rewardsScore.invoke(dex.account, "updateBalanceAndSupply", "sICX/bnUSD", totalSupply2.subtract(balance2), + supplyAccount.getAddress().toString(), totalSupply2.subtract(balance2)); + + rewardsScore.invoke(dex.account, "updateBalanceAndSupply", "sICX/ICX", totalSupply1, + fromNetworkAddress, balance1); + + rewardsScore.invoke(dex.account, "updateBalanceAndSupply", "sICX/bnUSD", totalSupply2, + fromNetworkAddress, balance2); + + mockBalanceAndSupply(dex, "sICX/ICX", fromNetworkAddress, balance1, totalSupply1); + mockBalanceAndSupply(dex, "sICX/bnUSD", fromNetworkAddress, balance2, totalSupply2); + + List _data = new ArrayList<>(2); + _data.add(Map.of("source", "sICX/ICX", "amount", sICXRewards1)); + _data.add(Map.of("source", "sICX/bnUSD", "amount", sICXRewards2)); + JSONArray data = new JSONArray(_data); + + rewardsScore.invoke(mockBalanced.sicx.account, "tokenFallback", externalRewardsProvider.getAddress(), + sICXRewards1.add(sICXRewards2), data.toString().getBytes()); + // starts after 1 day, fully distributed after 2 + nextDay(); + nextDay(); + + // Act + Map rewards = (Map) rewardsScore.call("getRewards", + fromNetworkAddress); + String[] sources = {"sICX/ICX", "sICX/bnUSD"}; + String[] protocols = {}; + rewardsScore.invoke(mockBalanced.xCall.account, "handleCallMessage", fromNetworkAddress, getClaimRewardData(fromNetworkAddress, sources), protocols); + + //todo: calculate the expected value and replace the hard coded value + verify(rewardsScoreSpy).RewardsClaimedV2(mockBalanced.sicx.account.getAddress(), fromNetworkAddress, new BigInteger("350000000000000000000")); + verify(rewardsScoreSpy).RewardsClaimedV2(mockBalanced.baln.account.getAddress(), fromNetworkAddress, new BigInteger("8997986111111111111108")); + } + + static byte[] getClaimRewardData(String to, String[] sources) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(3); + writer.write("xclaimrewards"); + writer.write(to); + writer.beginList(sources.length); + for(String source : sources) { + writer.write(source); + } + writer.end(); + writer.end(); + return writer.toByteArray(); + } + + protected void handleCallMessageWithOutProtocols(String from, byte[] data, String[] protocols ) { + rewardsScore.invoke(mockBalanced.xCall.account, "handleCallMessage", from, data, protocols); + } + + } \ No newline at end of file diff --git a/core-contracts/StakedLP/build.gradle b/core-contracts/StakedLP/build.gradle index 455a4f499..8ed518367 100644 --- a/core-contracts/StakedLP/build.gradle +++ b/core-contracts/StakedLP/build.gradle @@ -28,6 +28,7 @@ dependencies { compileOnly Dependencies.javaeeApi implementation project(':score-lib') implementation Dependencies.javaeeScorex + implementation 'xyz.venture23:xcall-lib:2.1.0' testImplementation project(':test-lib') testImplementation Dependencies.javaeeUnitTest diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index 3d0573aea..ba0f6a040 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -16,13 +16,14 @@ package network.balanced.score.core.stakedlp; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.interfaces.StakedLP; -import network.balanced.score.lib.utils.IterableDictDB; -import network.balanced.score.lib.utils.Names; -import network.balanced.score.lib.utils.Versions; +import network.balanced.score.lib.interfaces.StakedLPXCall; +import network.balanced.score.lib.utils.*; import score.*; import score.annotation.EventLog; import score.annotation.External; +import score.annotation.Optional; import scorex.util.HashMap; import java.math.BigInteger; @@ -33,9 +34,13 @@ public class StakedLPImpl implements StakedLP { + //todo: verify this migration works +// private static final BranchDB> poolStakedDetails = +// Context.newBranchDB("poolStakeDetails", BigInteger.class); + + final static AddressBranchDictDB poolStakedDetails = new AddressBranchDictDB<>("poolStakeDetails", + BigInteger.class); - private static final BranchDB> poolStakedDetails = - Context.newBranchDB("poolStakeDetails", BigInteger.class); private static final DictDB totalStakedAmount = Context.newDictDB("totalStaked", BigInteger.class); private static final IterableDictDB dataSourceNames = new IterableDictDB<>("dataSourceNames", @@ -47,7 +52,7 @@ public class StakedLPImpl implements StakedLP { static final VarDB
dex = Context.newVarDB("dexAddress", Address.class); private static final VarDB
rewards = Context.newVarDB("rewardsAddress", Address.class); private final VarDB currentVersion = Context.newVarDB("version", String.class); - + public static String NATIVE_NID; public StakedLPImpl(Address governance) { if (StakedLPImpl.governance.get() == null) { Context.require(governance.isContract(), "StakedLP: Governance address should be a contract"); @@ -57,18 +62,29 @@ public StakedLPImpl(Address governance) { Context.revert("Can't Update same version of code"); } currentVersion.set(Versions.STAKEDLP); + NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); } /* * Events */ + //todo: verify this fix works +// @EventLog(indexed = 1) +// public void Stake(Address _owner, BigInteger _id, BigInteger _value) { +// } + @EventLog(indexed = 1) - public void Stake(Address _owner, BigInteger _id, BigInteger _value) { + public void Stake(String _owner, BigInteger _id, BigInteger _value) { } + // +// @EventLog(indexed = 1) +// public void Unstake(Address _owner, BigInteger _id, BigInteger _value) { +// } + @EventLog(indexed = 1) - public void Unstake(Address _owner, BigInteger _id, BigInteger _value) { + public void Unstake(String _owner, BigInteger _id, BigInteger _value) { } @External(readonly = true) @@ -119,7 +135,14 @@ public void setRewards(Address rewards) { @External(readonly = true) public BigInteger balanceOf(Address _owner, BigInteger _id) { - return poolStakedDetails.at(_owner).getOrDefault(_id, BigInteger.ZERO); + NetworkAddress owner = NetworkAddress.valueOf(_owner.toString(), NATIVE_NID); + return poolStakedDetails.at(owner).getOrDefault(_id, BigInteger.ZERO); + } + + @External(readonly = true) + public BigInteger balanceOfV2(String _owner, BigInteger _id) { + NetworkAddress owner = NetworkAddress.valueOf(_owner); + return poolStakedDetails.at(owner).getOrDefault(_id, BigInteger.ZERO); } @External(readonly = true) @@ -127,41 +150,67 @@ public BigInteger totalStaked(BigInteger _id) { return totalStakedAmount.getOrDefault(_id, BigInteger.ZERO); } + @External + public void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) { + //todo: uncomment after unit test fix + //checkStatus(); + only(BalancedAddressManager.getXCall()); + XCallUtils.verifyXCallProtocols(_from, _protocols); + StakedLPXCall.process(this, _from, _data); + } + + public void xUnstake(String from, BigInteger id, BigInteger value) { + unstake(id, NetworkAddress.valueOf(from), value); + } + @External public void unstake(BigInteger id, BigInteger value) { Address caller = Context.getCaller(); - Context.require(value.compareTo(BigInteger.ZERO) > 0, "StakedLP: Cannot unstake less than zero value"); + NetworkAddress user = NetworkAddress.valueOf(caller.toString(), NATIVE_NID); + unstake(id, user, value); + } - BigInteger previousBalance = poolStakedDetails.at(caller).getOrDefault(id, BigInteger.ZERO); + private void unstake(BigInteger id, NetworkAddress user, BigInteger value){ + Context.require(value.compareTo(BigInteger.ZERO) > 0, "StakedLP: Cannot unstake less than zero value"); + BigInteger previousBalance = poolStakedDetails.at(user).getOrDefault(id, BigInteger.ZERO); BigInteger previousTotal = totalStaked(id); String poolName = getSourceName(id); Context.require(previousBalance.compareTo(value) >= 0, "StakedLP: Cannot unstake, user don't have enough " + - "staked balance, Amount to unstake: " + value + " Staked balance of user: " + caller + " is: " + previousBalance); + "staked balance, Amount to unstake: " + value + " Staked balance of user: " + user + " is: " + previousBalance); BigInteger newBalance = previousBalance.subtract(value); BigInteger newTotal = previousTotal.subtract(value); Context.require(newBalance.signum() >= 0 && newTotal.signum() >= 0, "StakedLP: New staked balance of user and" + " total amount can't be negative"); - poolStakedDetails.at(caller).set(id, newBalance); + poolStakedDetails.at(user).set(id, newBalance); totalStakedAmount.set(id, newTotal); - Unstake(caller, id, value); + Unstake(user.toString(), id, value); - Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, caller.toString(), newBalance); + Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, user.toString(), newBalance); try { - Context.call(dex.get(), "transfer", caller, value, id, new byte[0]); + Context.call(dex.get(), "hubTransfer", user.toString(), value, id, new byte[0]); } catch (Exception e) { Context.revert("StakedLP: Failed to transfer LP tokens back to user. Reason: " + e.getMessage()); } } + @Override + public void onIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data) { + only(dex); + Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); + NetworkAddress from = NetworkAddress.valueOf(_from); + this.stake(from, _id, _value); + } + @External public void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data) { only(dex); Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); - this.stake(_from, _id, _value); + NetworkAddress from = NetworkAddress.valueOf(_from.toString(), NATIVE_NID); + this.stake(from, _id, _value); } @External @@ -220,12 +269,11 @@ public boolean isSupportedPool(BigInteger id) { return name != null; } - private void stake(Address user, BigInteger id, BigInteger value) { + private void stake(NetworkAddress user, BigInteger id, BigInteger value) { // Validate inputs Context.require(value.compareTo(BigInteger.ZERO) > 0, "StakedLP: Cannot stake less than zero, value to stake " + value); String poolName = getSourceName(id); - // Compute and store changes BigInteger previousBalance = poolStakedDetails.at(user).getOrDefault(id, BigInteger.ZERO); BigInteger previousTotal = totalStaked(id); @@ -234,15 +282,8 @@ private void stake(Address user, BigInteger id, BigInteger value) { poolStakedDetails.at(user).set(id, newBalance); totalStakedAmount.set(id, newTotal); - Stake(user, id, value); + Stake(user.toString(), id, value); Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, user.toString(), newBalance); } - - - private void migratePool(String name) { - BigInteger id = Context.call(BigInteger.class, dex.get(), "lookupPid", name); - dataSourceIds.set(name, id); - dataSourceNames.set(id, name); - } } diff --git a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java index c460ff697..3bca178b7 100644 --- a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java +++ b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java @@ -19,16 +19,23 @@ import com.iconloop.score.test.Account; import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.interfaces.*; import network.balanced.score.lib.test.UnitTest; +import network.balanced.score.lib.test.mock.MockBalanced; import network.balanced.score.lib.test.mock.MockContract; +import network.balanced.score.lib.utils.BalancedAddressManager; +import network.balanced.score.lib.utils.Names; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; +import org.mockito.MockedStatic; import org.mockito.Mockito; import score.Address; +import score.ByteArrayObjectWriter; +import score.Context; import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; @@ -46,24 +53,35 @@ public class StakedLPTest extends UnitTest { public static final Account owner = sm.createAccount(); private Score stakedLpScore; - public static final Account governanceScore = Account.newScoreAccount(1); + //public static final Account governanceScore = Account.newScoreAccount(1); private final Account alice = sm.createAccount(); private final Account bob = sm.createAccount(); + protected MockBalanced mockBalanced; + public MockContract governance; + public MockContract dex; public MockContract rewards; + public static StakedLPImpl stakedLpScoreSpy; public static final String poolOneName = "pool1"; public static final String poolTwoName = "pool2"; - + private final String NATIVE_NID = "0x1.ICON"; @BeforeEach public void setup() throws Exception { - stakedLpScore = sm.deploy(owner, StakedLPImpl.class, governanceScore.getAddress()); - dex = new MockContract<>(DexScoreInterface.class, sm, owner); - rewards = new MockContract<>(RewardsScoreInterface.class, sm, owner); + mockBalanced = new MockBalanced(sm, owner); + + when(mockBalanced.xCall.mock.getNetworkId()).thenReturn(NATIVE_NID); + + governance = mockBalanced.governance; + stakedLpScore = sm.deploy(owner, StakedLPImpl.class, governance.getAddress()); + stakedLpScoreSpy = (StakedLPImpl) spy(stakedLpScore.getInstance()); + stakedLpScore.setInstance(stakedLpScoreSpy); + dex = mockBalanced.dex; + rewards = mockBalanced.rewards; - stakedLpScore.invoke(governanceScore, "addDataSource", BigInteger.ONE, poolOneName); - stakedLpScore.invoke(governanceScore, "addDataSource", BigInteger.TWO, poolTwoName); + stakedLpScore.invoke(governance.account, "addDataSource", BigInteger.ONE, poolOneName); + stakedLpScore.invoke(governance.account, "addDataSource", BigInteger.TWO, poolTwoName); } @Test @@ -110,12 +128,12 @@ void name() { @Test void setAndGetDex() { - testGovernanceControlMethods(stakedLpScore, governanceScore, governanceScore, "setDex", dex.getAddress(), "getDex"); + testGovernanceControlMethods(stakedLpScore, governance.account, governance.account, "setDex", dex.getAddress(), "getDex"); } @Test void changeGovernanceAddress() { - assertEquals(governanceScore.getAddress(), stakedLpScore.call("getGovernance")); + assertEquals(governance.getAddress(), stakedLpScore.call("getGovernance")); Address newGovernance = Account.newScoreAccount(2).getAddress(); stakedLpScore.invoke(owner, "setGovernance", newGovernance); assertEquals(newGovernance, stakedLpScore.call("getGovernance")); @@ -123,7 +141,7 @@ void changeGovernanceAddress() { @Test void setAndGetRewards() { - stakedLpScore.invoke(governanceScore, "setRewards", rewards.getAddress()); + stakedLpScore.invoke(governance.account, "setRewards", rewards.getAddress()); assertEquals(rewards.getAddress(), stakedLpScore.call("getRewards")); } @@ -132,6 +150,89 @@ private void stakeLpTokens(Account from, BigInteger poolId, BigInteger value) { new byte[0]); } + private void stakeLpTokens(String from, BigInteger poolId, BigInteger value) { + stakedLpScore.invoke(dex.account, "onIRC31Received", from, from, poolId, value, + new byte[0]); + } + + @Test + void crossChainStake(){ + setAndGetDex(); + setAndGetRewards(); + String fromNetworkAddress1 = "0x1.ETH/0x123"; + String fromNetworkAddress2 = "0x1.ETH/0x124"; + + // Mint LP tokens in Alice and Bob account + BigInteger initialLpTokenBalance = BigInteger.TEN.pow(10); + when(dex.mock.xBalanceOf(eq(fromNetworkAddress1), Mockito.any(BigInteger.class))).thenReturn(initialLpTokenBalance); + when(dex.mock.xBalanceOf(eq(fromNetworkAddress2), Mockito.any(BigInteger.class))).thenReturn(initialLpTokenBalance); + + // Stake Zero tokens + Executable zeroStakeValue = () -> stakeLpTokens(fromNetworkAddress1, BigInteger.ONE, BigInteger.ZERO); + String expectedErrorMessage = "Reverted(0): StakedLP: Token value should be a positive number"; + expectErrorMessage(zeroStakeValue, expectedErrorMessage); + + // Pool 1 related tests + // Stake 10 LP tokens from alice account + stakeLpTokens(fromNetworkAddress1, BigInteger.ONE, BigInteger.TEN); + assertEquals(BigInteger.TEN, stakedLpScore.call("balanceOfV2", fromNetworkAddress1, BigInteger.ONE)); + assertEquals(BigInteger.TEN, stakedLpScore.call("totalStaked", BigInteger.ONE)); + + // Stake 100 more LP tokens from alice account + stakeLpTokens(fromNetworkAddress1, BigInteger.ONE, BigInteger.valueOf(100L)); + assertEquals(BigInteger.valueOf(110L), stakedLpScore.call("balanceOfV2", fromNetworkAddress1, BigInteger.ONE)); + assertEquals(BigInteger.valueOf(110L), stakedLpScore.call("totalStaked", BigInteger.ONE)); + + // Stake 20 LP tokens from bob account + stakeLpTokens(fromNetworkAddress2, BigInteger.ONE, BigInteger.valueOf(20L)); + assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOfV2", fromNetworkAddress2, BigInteger.ONE)); + assertEquals(BigInteger.valueOf(130L), stakedLpScore.call("totalStaked", BigInteger.ONE)); + + // Pool 2 related tests + assertEquals(BigInteger.ZERO, stakedLpScore.call("balanceOfV2", fromNetworkAddress1, BigInteger.TWO)); + assertEquals(BigInteger.ZERO, stakedLpScore.call("balanceOfV2", fromNetworkAddress2, BigInteger.TWO)); + assertEquals(BigInteger.ZERO, stakedLpScore.call("totalStaked", BigInteger.TWO)); + + // Stake 20 LP tokens from alice and bob account + stakeLpTokens(fromNetworkAddress1, BigInteger.TWO, BigInteger.valueOf(20L)); + assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("totalStaked", BigInteger.TWO)); + + stakeLpTokens(fromNetworkAddress2, BigInteger.TWO, BigInteger.valueOf(20L)); + verify(rewards.mock).updateBalanceAndSupply(poolTwoName, BigInteger.valueOf(20L), fromNetworkAddress1, BigInteger.valueOf(20L)); + assertEquals(BigInteger.valueOf(40L), stakedLpScore.call("totalStaked", BigInteger.TWO)); + assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOfV2", fromNetworkAddress1, BigInteger.TWO)); + assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOfV2", fromNetworkAddress2, BigInteger.TWO)); + } + + @Test + void xUnstake(){ + setAndGetDex(); + setAndGetRewards(); + String fromNetworkAddress = "0x1.ETH/0x123"; + // Stake 20 LP tokens from alice and bob account + stakeLpTokens(fromNetworkAddress, BigInteger.TWO, BigInteger.valueOf(20L)); + + String[] protocols = new String[0]; + byte[] data = getAddLPData(BigInteger.TWO, BigInteger.valueOf(10L)); + handleCallMessageWithOutProtocols(fromNetworkAddress, data, protocols); + verify(rewards.mock).updateBalanceAndSupply(poolTwoName, BigInteger.valueOf(10L), fromNetworkAddress, BigInteger.valueOf(10L)); + } + + static byte[] getAddLPData(BigInteger id, BigInteger value) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(3); + writer.write("xunstake"); + writer.write(id); + writer.write(value); + writer.end(); + return writer.toByteArray(); + } + + + protected void handleCallMessageWithOutProtocols(String from, byte[] data, String[] protocols ) { + stakedLpScore.invoke(mockBalanced.xCall.account, "handleCallMessage", from, data, protocols); + } + @Test void testStake() { setAndGetDex(); @@ -173,7 +274,7 @@ void testStake() { assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("totalStaked", BigInteger.TWO)); stakeLpTokens(bob, BigInteger.TWO, BigInteger.valueOf(20L)); - verify(rewards.mock).updateBalanceAndSupply(poolTwoName, BigInteger.valueOf(40L), bob.getAddress().toString(), BigInteger.valueOf(20L)); + verify(rewards.mock).updateBalanceAndSupply(poolTwoName, BigInteger.valueOf(40L), NetworkAddress.valueOf(bob.getAddress().toString(), NATIVE_NID).toString(), BigInteger.valueOf(20L)); assertEquals(BigInteger.valueOf(40L), stakedLpScore.call("totalStaked", BigInteger.TWO)); assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOf", alice.getAddress(), BigInteger.TWO)); assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOf", bob.getAddress(), BigInteger.TWO)); @@ -204,7 +305,7 @@ void testUnstake() { finalAliceStakedBalance.add(BigInteger.ONE)); expectedErrorMessage = "Reverted(0): StakedLP: Cannot unstake, user don't have enough staked balance, Amount " + "to unstake: " + - aliceStakedBalance.add(BigInteger.ONE) + " Staked balance of user: " + alice.getAddress() + " is: " + + aliceStakedBalance.add(BigInteger.ONE) + " Staked balance of user: " + NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString() + " is: " + aliceStakedBalance; expectErrorMessage(unstakeMoreThanStakedAmount, expectedErrorMessage); @@ -218,8 +319,8 @@ void testUnstake() { alice.getAddress(), BigInteger.ONE)); assertEquals(totalStakedBalanceBeforeUnstake, stakedLpScore.call("totalStaked", BigInteger.ONE)); - verify(dex.mock).transfer(alice.getAddress(), aliceUnstakeAmount, BigInteger.ONE, new byte[0]); - verify(rewards.mock).updateBalanceAndSupply(poolOneName, totalStakedBalanceBeforeUnstake, alice.getAddress().toString(), + verify(dex.mock).hubTransfer(NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), aliceUnstakeAmount, BigInteger.ONE, new byte[0]); + verify(rewards.mock).updateBalanceAndSupply(poolOneName, totalStakedBalanceBeforeUnstake, NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), aliceStakedBalance); // Adjust the values after first unstake @@ -230,7 +331,7 @@ void testUnstake() { BigInteger.ONE)); assertEquals(totalStakedBalanceBeforeUnstake.subtract(bobStakedBalance), stakedLpScore.call("totalStaked", BigInteger.ONE)); - verify(dex.mock).transfer(bob.getAddress(), bobStakedBalance, BigInteger.ONE, new byte[0]); + verify(dex.mock).hubTransfer(NetworkAddress.valueOf(bob.getAddress().toString(), NATIVE_NID).toString(), bobStakedBalance, BigInteger.ONE, new byte[0]); // Unstake alice remaining amount totalStakedBalanceBeforeUnstake = totalStakedBalanceBeforeUnstake.subtract(bobStakedBalance); @@ -240,7 +341,7 @@ void testUnstake() { alice.getAddress(), BigInteger.ONE)); assertEquals(totalStakedBalanceBeforeUnstake.subtract(aliceStakedBalance), stakedLpScore.call("totalStaked", BigInteger.ONE)); - verify(dex.mock, times(2)).transfer(alice.getAddress(), aliceStakedBalance, BigInteger.ONE, new byte[0]); + verify(dex.mock, times(2)).hubTransfer(NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), aliceStakedBalance, BigInteger.ONE, new byte[0]); // Unstake from pool 2 // Unstake from unsupported pool @@ -257,7 +358,7 @@ void testUnstake() { alice.getAddress(), BigInteger.TWO)); assertEquals(totalStakedBalancePool2.subtract(aliceStakedBalancePool2), stakedLpScore.call("totalStaked", BigInteger.TWO)); - verify(dex.mock).transfer(alice.getAddress(), aliceStakedBalancePool2, BigInteger.TWO, new byte[0]); + verify(dex.mock).hubTransfer(NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), aliceStakedBalancePool2, BigInteger.TWO, new byte[0]); } @@ -278,14 +379,14 @@ void testStakeUnstake_unnamedPool() { expectErrorMessage(zeroStakeValue, expectedErrorMessage); // Act - stakedLpScore.invoke(governanceScore, "addDataSource", poolId, name); + stakedLpScore.invoke(governance.account, "addDataSource", poolId, name); stakeLpTokens(alice, poolId, BigInteger.TEN); // Assert Map balanceAndSupply = (Map) stakedLpScore.call("getBalanceAndSupply", name, alice.getAddress().toString()); assertEquals(BigInteger.TEN, balanceAndSupply.get("_balance")); assertEquals(BigInteger.TEN, balanceAndSupply.get("_totalSupply")); - verify(rewards.mock).updateBalanceAndSupply(name, balanceAndSupply.get("_totalSupply"), alice.getAddress().toString(), balanceAndSupply.get("_balance")); + verify(rewards.mock).updateBalanceAndSupply(name, balanceAndSupply.get("_totalSupply"), NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), balanceAndSupply.get("_balance")); // Act stakedLpScore.invoke(alice, "unstake", poolId, BigInteger.TWO); @@ -294,6 +395,6 @@ void testStakeUnstake_unnamedPool() { balanceAndSupply = (Map) stakedLpScore.call("getBalanceAndSupply", name, alice.getAddress().toString()); assertEquals(BigInteger.valueOf(8), balanceAndSupply.get("_balance")); assertEquals(BigInteger.valueOf(8), balanceAndSupply.get("_totalSupply")); - verify(rewards.mock).updateBalanceAndSupply(name, balanceAndSupply.get("_totalSupply"), alice.getAddress().toString(), balanceAndSupply.get("_balance")); + verify(rewards.mock).updateBalanceAndSupply(name, balanceAndSupply.get("_totalSupply"), NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), balanceAndSupply.get("_balance")); } } 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 bed093ed8..2a10d9d81 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 @@ -18,6 +18,7 @@ import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; +import network.balanced.score.lib.annotations.XCall; import network.balanced.score.lib.interfaces.addresses.AddressManager; import network.balanced.score.lib.interfaces.base.*; import network.balanced.score.lib.structs.PrepDelegations; @@ -32,7 +33,7 @@ @ScoreClient @ScoreInterface public interface Dex extends Name, AddressManager, Fallback, TokenFallback, - IRC31Base, Version, FloorLimitedInterface, DataSource { + IRC31Base, Version, FloorLimitedInterface, DataSource { @External void setPoolLpFee(BigInteger _value); @@ -70,9 +71,15 @@ public interface Dex extends Name, AddressManager, Fallback, TokenFallback, @External void cancelSicxicxOrder(); + @External + void xTokenFallback(String _from, BigInteger _value, byte[] _data); + @External void transfer(Address _to, BigInteger _value, BigInteger _id, @Optional byte[] _data); + @External + void hubTransfer(String _to, BigInteger _value, BigInteger _id, @Optional byte[] _data); + @External void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data); @@ -82,6 +89,9 @@ public interface Dex extends Name, AddressManager, Fallback, TokenFallback, @External(readonly = true) BigInteger getDeposit(Address _tokenAddress, Address _user); + @External(readonly = true) + BigInteger getDepositV2(Address _tokenAddress, String _user); + @External(readonly = true) BigInteger getSicxEarnings(Address _user); @@ -176,6 +186,21 @@ public interface Dex extends Name, AddressManager, Fallback, TokenFallback, void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, @Optional boolean _withdraw_unused, @Optional BigInteger _slippagePercentage); + @XCall + void xAdd(String from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, + @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage); + + @XCall + void xHubTransfer(String from, String _to, BigInteger _value, BigInteger _id, byte[] _data); + + @XCall + void xWithdraw(String from, Address _token, BigInteger _value); + + @XCall + void xRemove(String from, BigInteger id, BigInteger value, @Optional Boolean withdraw); + + BigInteger xBalanceOf(String _owner, BigInteger _id); + @External void withdrawSicxEarnings(@Optional BigInteger _value); diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Rewards.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Rewards.java index 279e1405c..6cd9958f8 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Rewards.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Rewards.java @@ -18,6 +18,7 @@ import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; +import network.balanced.score.lib.annotations.XCall; import network.balanced.score.lib.interfaces.addresses.*; import network.balanced.score.lib.interfaces.base.Name; import network.balanced.score.lib.interfaces.base.RewardsVoting; @@ -84,6 +85,9 @@ public interface Rewards extends @External void claimRewards(@Optional String[] sources); + @XCall + void xClaimRewards(String from, String to, @Optional String[] sources); + @External void updateRewardsData(String _name, BigInteger _totalSupply, Address _user, BigInteger _balance); diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java index 2773133ba..5fc5b4941 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java @@ -18,9 +18,11 @@ import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; +import network.balanced.score.lib.annotations.XCall; import network.balanced.score.lib.interfaces.base.Version; import score.Address; import score.annotation.External; +import score.annotation.Optional; import java.math.BigInteger; import java.util.List; @@ -53,12 +55,21 @@ public interface StakedLP extends Version { @External(readonly = true) BigInteger totalStaked(BigInteger _id); + @External + void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols); + @External void unstake(BigInteger id, BigInteger value); + @XCall + void xUnstake(String from, BigInteger id, BigInteger value); + @External void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data); + @External + void onIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data); + @External void addDataSource(BigInteger id, String name); diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/base/IRC31Base.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/base/IRC31Base.java index 3a7dac5e2..8f2df4646 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/base/IRC31Base.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/base/IRC31Base.java @@ -27,6 +27,6 @@ public interface IRC31Base { @External(readonly = true) BigInteger balanceOf(Address _owner, BigInteger _id); - @EventLog(indexed = 3) - void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value); +// @EventLog(indexed = 3) +// void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/XReceiver.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/XReceiver.java new file mode 100644 index 000000000..113994ebb --- /dev/null +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/XReceiver.java @@ -0,0 +1,19 @@ +/* +package network.balanced.score.lib.interfaces.tokens; + +import foundation.icon.score.client.ScoreInterface; +import network.balanced.score.lib.annotations.XCall; +import score.Address; +import score.annotation.Optional; + +import java.math.BigInteger; + +@ScoreInterface +public interface XReceiver { + + @XCall + void xAdd(String from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, + @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage); + +} +*/ 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..070d769c2 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 @@ -210,6 +210,7 @@ public void _transferToSpoke(BigInteger fee, NetworkAddress from, NetworkAddress public void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) { checkStatus(); only(BalancedAddressManager.getXCall()); + Context.println(_from); XCallUtils.verifyXCallProtocols(_from, _protocols); HubTokenXCall.process(this, _from, _data); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/AddressBranchDictDB.java b/score-lib/src/main/java/network/balanced/score/lib/utils/AddressBranchDictDB.java new file mode 100644 index 000000000..c2d097f23 --- /dev/null +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/AddressBranchDictDB.java @@ -0,0 +1,35 @@ +package network.balanced.score.lib.utils; + +import foundation.icon.xcall.NetworkAddress; +import score.Address; +import score.BranchDB; +import score.Context; +import score.DictDB; + + +public class AddressBranchDictDB { + + private BranchDB> legacyAddressDictDB; + private BranchDB> addressDictDB; + + public AddressBranchDictDB(String id, Class valueClass) { + this.legacyAddressDictDB = Context.newBranchDB(id, valueClass); + this.addressDictDB = Context.newBranchDB(id + "_migrated", valueClass); + } + + + public DictDB at(NetworkAddress key) { + DictDB value = addressDictDB.at(key.toString()); + if (value != null) { + return value; + } + + if (key.account().startsWith("hx") || key.account().startsWith("cx")) { + value = legacyAddressDictDB.at(Address.fromString(key.account())); + } + + + return value; + } + +} diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/BranchedNetworkAddressDictDB.java b/score-lib/src/main/java/network/balanced/score/lib/utils/BranchedNetworkAddressDictDB.java new file mode 100644 index 000000000..156e92543 --- /dev/null +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/BranchedNetworkAddressDictDB.java @@ -0,0 +1,21 @@ +package network.balanced.score.lib.utils; + +import score.Address; +import score.BranchDB; +import score.Context; +import score.DictDB; + +//Class to add btp address support to already existing branchDB address db to support string addresses +public class BranchedNetworkAddressDictDB { + private BranchDB> legacyAddressDB; + private BranchDB> addressDB; + + public BranchedNetworkAddressDictDB(String id, Class valueClass) { + this.legacyAddressDB = Context.newBranchDB(id, valueClass); + this.addressDB = Context.newBranchDB(id + "_migrated", valueClass); + } + + public NetworkAddressDictDB at(K key) { + return new NetworkAddressDictDB(legacyAddressDB.at(key), addressDB.at(key)); + }; +} diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/NetworkAddressDictDB.java b/score-lib/src/main/java/network/balanced/score/lib/utils/NetworkAddressDictDB.java index 18f7f8315..efc3e8573 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/NetworkAddressDictDB.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/NetworkAddressDictDB.java @@ -5,6 +5,8 @@ import score.DictDB; import foundation.icon.xcall.NetworkAddress; +import static network.balanced.score.lib.utils.Check.readonly; + //Class to add btp address support to already existing DictDB address db to support string addresses public class NetworkAddressDictDB { private DictDB legacyAddressDB; @@ -34,6 +36,10 @@ public V get(NetworkAddress key) { value = legacyAddressDB.get(Address.fromString(address)); } + if (value != null && !readonly()) { + set(key, value); + } + return value; } diff --git a/test-lib/src/main/java/network/balanced/score/lib/test/integration/Balanced.java b/test-lib/src/main/java/network/balanced/score/lib/test/integration/Balanced.java index 36b619dd8..20b8de0a5 100644 --- a/test-lib/src/main/java/network/balanced/score/lib/test/integration/Balanced.java +++ b/test-lib/src/main/java/network/balanced/score/lib/test/integration/Balanced.java @@ -98,11 +98,11 @@ public void setupBalanced() throws Exception { increaseDay(1); setupContracts(); // delegate(adminWallet); - String className = new Exception().getStackTrace()[1].getClassName(); + //String className = new Exception().getStackTrace()[1].getClassName(); // no need to set up market in staking integration test case - if (!className.equals("network.balanced.score.core.staking.StakingIntegrationTest")) { - setupMarkets(); - } +// if (!className.equals("network.balanced.score.core.staking.StakingIntegrationTest")) { +// setupMarkets(); +// } } public void deployContracts() { diff --git a/util-contracts/XCallMock/src/main/java/network/balanced/score/util/mock/xcall/XCallMockImpl.java b/util-contracts/XCallMock/src/main/java/network/balanced/score/util/mock/xcall/XCallMockImpl.java index f2ac0365e..3e59f12a1 100644 --- a/util-contracts/XCallMock/src/main/java/network/balanced/score/util/mock/xcall/XCallMockImpl.java +++ b/util-contracts/XCallMock/src/main/java/network/balanced/score/util/mock/xcall/XCallMockImpl.java @@ -82,6 +82,7 @@ public BigInteger sendCall(String _to, byte[] _data) { @External public void recvCall(Address to, String from, byte[] message) { + Context.println(to.toString()); Context.call(to, "handleCallMessage", from, message); } From 24eed8e23c01b3efc0528e62fe3269f2a5216d02 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 8 Oct 2024 20:12:34 +0545 Subject: [PATCH 02/31] integration test and fixes - crosschain lp feature --- .../score/core/dex/DexIntegrationTest.java | 143 +++++++++++-- .../balanced/score/core/dex/AbstractDex.java | 3 - .../balanced/score/core/dex/DexImpl.java | 9 +- .../core/rewards/RewardsIntegrationTest.java | 153 +++++++++++++- .../stakedlp/StakedlpIntegrationTest.java | 196 ++++++++++++++---- .../score/core/stakedlp/StakedLPImpl.java | 37 ++-- .../score/core/stakedlp/StakedLPTest.java | 17 +- .../score/lib/interfaces/StakedLP.java | 7 +- 8 files changed, 464 insertions(+), 101 deletions(-) diff --git a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java index e893055d6..72362be4b 100644 --- a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java +++ b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java @@ -302,20 +302,125 @@ void testNonContinuousAndContinuousReward() { } @Test + @Order(9) + void crossChainDepositViaAssetManagerDirect() { + //Arrange + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + BigInteger amount = BigInteger.valueOf(100).multiply(EXA); + NetworkAddress ethAssetAddress = new NetworkAddress(balanced.ETH_NID, balanced.ETH_TOKEN_ADDRESS); + String toNetworkAddress = new NetworkAddress(balanced.ICON_NID, dexScoreClient._address()).toString(); + score.Address assetAddress = owner.assetManager.getAssetAddress(ethAssetAddress.toString()); + + // Act + byte[] depositData = tokenData("_deposit", + new JsonObject().set( "address", ethAccount.toString())); + byte[] deposit = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), toNetworkAddress, amount, depositData); + owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit); + + // Verify + BigInteger retrievedValue = dexUserScoreClient.getDepositV2(assetAddress, ethAccount.toString()); + assertEquals(amount, retrievedValue); + } + + @Test + @Order(10) void crossChainDeposit() { + //Arrange + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + BigInteger amount = BigInteger.valueOf(100).multiply(EXA); + NetworkAddress ethAssetAddress = new NetworkAddress(balanced.ETH_NID, balanced.ETH_TOKEN_ADDRESS); + String toNetworkAddress = new NetworkAddress(balanced.ICON_NID, dexScoreClient._address()).toString(); + score.Address assetAddress = owner.assetManager.getAssetAddress(ethAssetAddress.toString()); + + // Arrange - Initial deposit + byte[] deposit = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), "", amount, new byte[0]); + owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit); + + // Act + byte[] message = depositMsg(ethAccount.toString(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set( "address", ethAccount.toString()))); + owner.xcall.recvCall(assetAddress, ethAccount.toString(), message); + + // Verify + BigInteger retrievedValue = dexUserScoreClient.getDepositV2(assetAddress, ethAccount.toString()); + assertEquals(amount.add(amount), retrievedValue); + } + + @Test + @Order(11) + void crossChainLP() { + // Arrange + NetworkAddress ethBaseAssetAddress = new NetworkAddress(balanced.ETH_NID, balanced.ETH_TOKEN_ADDRESS); + NetworkAddress ethQuoteAssetAddress = new NetworkAddress(balanced.ETH_NID, "ox100"); + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + BigInteger amount = BigInteger.valueOf(100).multiply(EXA); + String toNetworkAddress = new NetworkAddress(balanced.ICON_NID, dexScoreClient._address()).toString(); + + // Arrange - deploy a new token + JsonArray addAssetParams = new JsonArray() + .add(createParameter(ethQuoteAssetAddress.toString())) + .add(createParameter("ETHZ")) + .add(createParameter("ETHZ")) + .add(createParameter(BigInteger.valueOf(18))); + JsonObject addAsset = createTransaction(balanced.assetManager._address(), "deployAsset", addAssetParams); + JsonArray transactions = new JsonArray() + .add(addAsset); + balanced.governanceClient.execute(transactions.toString()); + + score.Address baseAssetAddress = owner.assetManager.getAssetAddress(ethBaseAssetAddress.toString()); + score.Address quoteAssetAddress = owner.assetManager.getAssetAddress(ethQuoteAssetAddress.toString()); + + // Arrange - deposits + byte[] deposit1 = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set( "address", ethAccount.toString()))); + owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit1); + + byte[] deposit2 = AssetManagerMessages.deposit("ox100", ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set( "address", ethAccount.toString()))); + owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit2); + + // Arrange add quote token + dexAddQuoteCoin((Address) quoteAssetAddress); + + // Act + byte[] xaddMessage = getAddLPData(baseAssetAddress, quoteAssetAddress, amount, amount, false, BigInteger.valueOf(5) ); + owner.xcall.recvCall(dexScoreClient._address(), ethAccount.toString(), xaddMessage); + + // Verify + BigInteger poolId = dexUserScoreClient.getPoolId(baseAssetAddress, + quoteAssetAddress); + assert poolId.compareTo(BigInteger.valueOf(6)) < 0; + BigInteger liquidity = + (amount.multiply(amount)).sqrt(); + BigInteger balance = dexUserScoreClient.xBalanceOf(ethAccount.toString(), poolId); + + assertEquals(balance, liquidity); + } + + //depends on crossChainLP test + @Test + @Order(12) + void xRemove(){ // Arrange - String ethBnUSD = new NetworkAddress(balanced.ETH_NID, balanced.ETH_BNUSD_ADDRESS).toString(); - String fromNetworkAddress = "0x1.ETH/0x123"; - BigInteger depositValue = BigInteger.valueOf(100).multiply(EXA); + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + NetworkAddress ethBaseAssetAddress = new NetworkAddress(balanced.ETH_NID, balanced.ETH_TOKEN_ADDRESS); + NetworkAddress ethQuoteAssetAddress = new NetworkAddress(balanced.ETH_NID, "ox100"); + + score.Address baseAssetAddress = owner.assetManager.getAssetAddress(ethBaseAssetAddress.toString()); + score.Address quoteAssetAddress = owner.assetManager.getAssetAddress(ethQuoteAssetAddress.toString()); + + BigInteger poolId = dexUserScoreClient.getPoolId(baseAssetAddress, + quoteAssetAddress); + BigInteger balance = dexUserScoreClient.xBalanceOf(ethAccount.toString(), poolId); + BigInteger withdrawAmount = balance.divide(BigInteger.TWO); // Act - byte[] message = depositMsg(fromNetworkAddress, depositValue, tokenData("_deposit", - new JsonObject().set( "address", fromNetworkAddress))); - owner.xcall.recvCall(owner.bnUSD._address(), ethBnUSD, message); + byte[] removeLPMsg = getXRemoveData(poolId, withdrawAmount, true); + owner.xcall.recvCall(dexScoreClient._address(), ethAccount.toString(), removeLPMsg); // Verify - BigInteger retrievedValue = dexUserScoreClient.getDepositV2(balanced.bnusd._address(), fromNetworkAddress); - assertEquals(depositValue, retrievedValue); + BigInteger updatedBalance = dexUserScoreClient.xBalanceOf(ethAccount.toString(), poolId); + assertEquals(withdrawAmount, updatedBalance); } public static byte[] tokenData(String method, JsonObject params) { @@ -325,14 +430,14 @@ public static byte[] tokenData(String method, JsonObject params) { return data.toString().getBytes(); } - static byte[] depositMsg(String from, BigInteger amount, byte[] data) { + static byte[] depositMsg(String from, String to, BigInteger amount, byte[] data) { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); - writer.beginList(2); - writer.write("xcrosstransfer"); - writer.write(from); - writer.write(from); + writer.beginList(4); + writer.write("xhubtransfer"); + writer.write(to); writer.write(amount); writer.write(data); + writer.end(); return writer.toByteArray(); } static byte[] getXRemoveData(BigInteger poolId, BigInteger lpTokenBalance, Boolean withdraw) { @@ -346,6 +451,18 @@ static byte[] getXRemoveData(BigInteger poolId, BigInteger lpTokenBalance, Boole return writer.toByteArray(); } + static byte[] getStakeData(BigInteger poolId, BigInteger amount, String to, byte[] data) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(4); + writer.write("xhubtransfer"); + writer.write(to); + writer.write(amount); + writer.write(poolId); + writer.write(data); + writer.end(); + return writer.toByteArray(); + } + static byte[] getAddLPData(score.Address baseToken, score.Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); writer.beginList(7); 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 cad8407d0..41453d3cc 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 @@ -18,10 +18,8 @@ import foundation.icon.xcall.NetworkAddress; import network.balanced.score.core.dex.db.NodeDB; -import network.balanced.score.lib.interfaces.Dex; import network.balanced.score.lib.structs.PrepDelegations; import network.balanced.score.lib.structs.RewardsDataEntry; -import network.balanced.score.lib.utils.AddressDictDB; import network.balanced.score.lib.utils.BalancedFloorLimits; import network.balanced.score.lib.utils.NetworkAddressDictDB; import score.Address; @@ -41,7 +39,6 @@ import static network.balanced.score.core.dex.utils.Check.isValidPercent; import static network.balanced.score.core.dex.utils.Check.isValidPoolId; import static network.balanced.score.core.dex.utils.Const.*; -import static network.balanced.score.lib.tokens.SpokeTokenImpl.NATIVE_NID; import static network.balanced.score.lib.utils.BalancedAddressManager.*; import static network.balanced.score.lib.utils.Check.onlyGovernance; import static network.balanced.score.lib.utils.Constants.*; diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index 99a084c07..0e0281b9b 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -37,14 +37,12 @@ import static network.balanced.score.core.dex.utils.Check.isDexOn; import static network.balanced.score.core.dex.utils.Check.isValidPercent; import static network.balanced.score.core.dex.utils.Const.*; -import static network.balanced.score.lib.utils.BalancedAddressManager.getRewards; -import static network.balanced.score.lib.utils.BalancedAddressManager.getSicx; +import static network.balanced.score.lib.utils.BalancedAddressManager.*; import static network.balanced.score.lib.utils.Check.checkStatus; import static network.balanced.score.lib.utils.Check.only; import static network.balanced.score.lib.utils.Constants.EXA; import static network.balanced.score.lib.utils.Constants.POINTS; import static network.balanced.score.lib.utils.Math.convertToNumber; -import static score.Context.println; import static score.Context.require; public class DexImpl extends AbstractDex { @@ -55,7 +53,7 @@ public DexImpl(Address _governance) { Context.revert("Can't Update same version of code"); } currentVersion.set(Versions.DEX); - NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); + NATIVE_NID = (String) Context.call(getXCall(), "getNetworkId"); } @External(readonly = true) @@ -154,7 +152,7 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { @External public void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) { checkStatus(); - only(BalancedAddressManager.getXCall()); + only(getXCall()); XCallUtils.verifyXCallProtocols(_from, _protocols); DexXCall.process(this, _from, _data); } @@ -334,7 +332,6 @@ void _remove(BigInteger _id, NetworkAddress _user, BigInteger _value, @Optional userLPBalance.set(_user, newUserBalance); poolLpTotal.set(_id.intValue(), newTotal); - //todo: uncomment after RemoveV2(_id, _user.toString(), _value, baseToWithdraw, quoteToWithdraw); // TransferSingle(_user, _user, MINT_ADDRESS, _id, _value); diff --git a/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java b/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java index e7c1fe18f..969e3606f 100644 --- a/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java +++ b/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java @@ -19,30 +19,47 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; +import com.iconloop.score.test.Account; +import foundation.icon.jsonrpc.Address; +import foundation.icon.score.client.DefaultScoreClient; +import foundation.icon.xcall.NetworkAddress; +import network.balanced.score.lib.interfaces.*; import network.balanced.score.lib.test.integration.Balanced; import network.balanced.score.lib.test.integration.BalancedClient; import network.balanced.score.lib.test.integration.ScoreIntegrationTest; +import org.json.JSONArray; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import score.ByteArrayObjectWriter; +import score.Context; import score.UserRevertedException; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import static network.balanced.score.lib.test.integration.BalancedUtils.*; import static network.balanced.score.lib.utils.Constants.*; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.verify; class RewardsIntegrationTest implements ScoreIntegrationTest { private static Balanced balanced; private static BalancedClient owner; private static BalancedClient reader; + private static DexScoreClient dex; + private static StakedLPScoreClient stakedlp; + private static RewardsScoreClient rewards; @BeforeAll static void setup() throws Exception { balanced = new Balanced(); balanced.setupBalanced(); + dex = new DexScoreClient(balanced.dex); + stakedlp = new StakedLPScoreClient(balanced.stakedLp); + rewards = new RewardsScoreClient(balanced.rewards); owner = balanced.ownerClient; reader = balanced.newClient(BigInteger.ZERO); @@ -345,6 +362,67 @@ void removeRewardsDistributions() throws Exception { owner.governance.execute(actions.toString()); } + @Test + void crossChainClaimRewards(){ + // Arrange + NetworkAddress ethBaseAssetAddress = new NetworkAddress(balanced.ETH_NID, balanced.ETH_TOKEN_ADDRESS); + NetworkAddress ethQuoteAssetAddress = new NetworkAddress(balanced.ETH_NID, "ox100"); + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + BigInteger amount = BigInteger.valueOf(100).multiply(EXA); + String toNetworkAddress = new NetworkAddress(balanced.ICON_NID, dex._address()).toString(); + String stakingAddress = new NetworkAddress(balanced.ICON_NID, stakedlp._address()).toString(); + + // Arrange - deploy a new token + JsonArray addAssetParams = new JsonArray() + .add(createParameter(ethQuoteAssetAddress.toString())) + .add(createParameter("ETHZ")) + .add(createParameter("ETHZ")) + .add(createParameter(BigInteger.valueOf(18))); + JsonObject addAsset = createTransaction(balanced.assetManager._address(), "deployAsset", addAssetParams); + JsonArray transactions = new JsonArray() + .add(addAsset); + balanced.governanceClient.execute(transactions.toString()); + + score.Address baseAssetAddress = owner.assetManager.getAssetAddress(ethBaseAssetAddress.toString()); + score.Address quoteAssetAddress = owner.assetManager.getAssetAddress(ethQuoteAssetAddress.toString()); + + // Arrange - deposits + byte[] deposit1 = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set( "address", ethAccount.toString()))); + owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit1); + + byte[] deposit2 = AssetManagerMessages.deposit("ox100", ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set( "address", ethAccount.toString()))); + owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit2); + + // Arrange add quote token + dexAddQuoteCoin((Address) quoteAssetAddress); + + // Arrange - add pool + byte[] xaddMessage = getAddLPData(baseAssetAddress, quoteAssetAddress, amount, amount, false, BigInteger.valueOf(5) ); + owner.xcall.recvCall(dex._address(), ethAccount.toString(), xaddMessage); + + // Arrange - stake + BigInteger poolId = dex.getPoolId(baseAssetAddress, + quoteAssetAddress); + try{ + addNewDataSource("test1", poolId, BigInteger.ONE); + } catch (Exception ignored){} + BigInteger balance = dex.xBalanceOf(ethAccount.toString(), poolId); + byte[] stakeData = getStakeData(stakingAddress, balance, poolId, "stake".getBytes()); + owner.xcall.recvCall(owner.dex._address(), ethAccount.toString(), stakeData); + + // Act + balanced.increaseDay(2); + + String[] sources = new String[] {}; + byte[] claimData = getClaimRewardData(ethAccount.toString(), sources); + owner.xcall.recvCall(rewards._address(), ethAccount.toString(), claimData); + + // Verify + + } + @Test @Order(30) void voting() throws Exception { @@ -458,12 +536,77 @@ private void verifyNoRewards(BalancedClient client) { assertEquals(balancePostClaim, balancePreClaim); } - private JsonObject createDistributionPercentage(String name, BigInteger percentage) { - JsonObject recipient = new JsonObject() - .add("recipient_name", createParameter(name)) - .add("dist_percent", createParameter(percentage)); + static byte[] getStakeData(String to, BigInteger amount, BigInteger poolId, byte[] data) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(5); + writer.write("xhubtransfer"); + writer.write(to); + writer.write(amount); + writer.write(poolId); + writer.write(data); + writer.end(); + return writer.toByteArray(); + } + + static byte[] getClaimRewardData(String to, String[] sources) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(3); + writer.write("xclaimrewards"); + writer.write(to); + writer.beginList(sources.length); + for(String source : sources) { + writer.write(source); + } + writer.end(); + writer.end(); + return writer.toByteArray(); + } + + private void addNewDataSource(String name, BigInteger id, BigInteger type) { + JsonArray lpSourceParameters = new JsonArray() + .add(createParameter(id)) + .add(createParameter(name)); + + JsonArray rewardsSourceParameters = new JsonArray() + .add(createParameter(name)) + .add(createParameter(balanced.stakedLp._address())) + .add(createParameter(type)); + + JsonArray actions = new JsonArray() + .add(createTransaction(balanced.stakedLp._address(), "addDataSource", lpSourceParameters)) + .add(createTransaction(balanced.rewards._address(), "createDataSource", rewardsSourceParameters)); + + balanced.ownerClient.governance.execute(actions.toString()); + } + + static byte[] getAddLPData(score.Address baseToken, score.Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(7); + writer.write("xadd"); + writer.write(baseToken); + writer.write(quoteToken); + writer.write(baseValue); + writer.write(quoteValue); + writer.write(withdraw_unused); + writer.write(slippagePercentage); + writer.end(); + return writer.toByteArray(); + } - return recipient; + public static byte[] tokenData(String method, JsonObject params) { + JsonObject data = new JsonObject(); + data.set("method", method); + data.set("params", params); + return data.toString().getBytes(); } + private void dexAddQuoteCoin(Address address) { + JsonArray params = new JsonArray() + .add(createParameter(address)); + + JsonArray actions = new JsonArray() + .add(createTransaction(balanced.dex._address(), "addQuoteCoin", params)); + + balanced.ownerClient.governance.execute(actions.toString()); + } } diff --git a/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java b/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java index f6e6903d8..12a8feeb6 100644 --- a/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java +++ b/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java @@ -17,16 +17,22 @@ package network.balanced.score.core.stakedlp; import com.eclipsesource.json.JsonArray; +import com.eclipsesource.json.JsonObject; import foundation.icon.icx.KeyWallet; import foundation.icon.icx.Wallet; import foundation.icon.jsonrpc.Address; import foundation.icon.score.client.DefaultScoreClient; +import foundation.icon.xcall.NetworkAddress; +import network.balanced.score.lib.interfaces.AssetManagerMessages; import network.balanced.score.lib.interfaces.DexScoreClient; import network.balanced.score.lib.interfaces.GovernanceScoreClient; import network.balanced.score.lib.interfaces.StakedLPScoreClient; import network.balanced.score.lib.interfaces.dex.DexTestScoreClient; import network.balanced.score.lib.test.integration.Balanced; +import network.balanced.score.lib.test.integration.BalancedClient; import org.junit.jupiter.api.*; +import score.ByteArrayObjectWriter; +import score.Context; import java.io.File; import java.math.BigInteger; @@ -40,9 +46,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class StakedlpIntegrationTest { - static KeyWallet owner; + private static BalancedClient owner; static Balanced balanced; private static Wallet userWallet; static StakedLPScoreClient stakedlp; @@ -51,51 +56,51 @@ public class StakedlpIntegrationTest { static GovernanceScoreClient governance; private static DefaultScoreClient tokenAClient; private static DefaultScoreClient tokenBClient; - static DexScoreClient testerScoreDex; + static DexScoreClient dexScoreClient; private static final File jarfile = new File("src/intTest/java/network/balanced/score/core/stakedlp/testtokens" + "/DexIntTestToken.jar"); - DexTestScoreClient ownerDexTestScoreClient = new DexTestScoreClient(chain.getEndpointURL(), - chain.networkId, owner, tokenAClient._address()); - DexTestScoreClient ownerDexTestBaseScoreClient = new DexTestScoreClient(chain.getEndpointURL(), - chain.networkId, owner, tokenBClient._address()); - - - @BeforeAll - static void setup() throws Exception { - - userWallet = createWalletWithBalance(BigInteger.valueOf(800).multiply(EXA)); - balanced = new Balanced(); - balanced.setupBalanced(); - - - owner = balanced.owner; - - stakedlp = new StakedLPScoreClient(balanced.stakedLp); - dex = new DexScoreClient(balanced.dex); - governance = new GovernanceScoreClient(balanced.governance); - DefaultScoreClient clientWithTester3 = new DefaultScoreClient("http://localhost:9082/api/v3", - BigInteger.valueOf(3), userWallet, balanced.dex._address()); - - DefaultScoreClient clientWithTester4 = new DefaultScoreClient("http://localhost:9082/api/v3", - BigInteger.valueOf(3), userWallet, balanced.stakedLp._address()); - tokenAClient = _deploy(chain.getEndpointURL(), chain.networkId, owner, jarfile.getPath(), - Map.of("name", "Test Token", "symbol", "TT")); - tokenBClient = _deploy(chain.getEndpointURL(), chain.networkId, owner, jarfile.getPath(), - Map.of("name", "Test Base Token", "symbol", "TB")); - testerScoreDex = new DexScoreClient(clientWithTester3); - stakedlpUser = new StakedLPScoreClient(clientWithTester4); - + static DexTestScoreClient ownerDexTestScoreClient; + static DexTestScoreClient ownerDexTestBaseScoreClient; + + + static { + try { + userWallet = createWalletWithBalance(BigInteger.valueOf(800).multiply(EXA)); + balanced = new Balanced(); + balanced.setupBalanced(); + owner = balanced.ownerClient; + + stakedlp = new StakedLPScoreClient(balanced.stakedLp); + dex = new DexScoreClient(balanced.dex); + governance = new GovernanceScoreClient(balanced.governance); + DefaultScoreClient clientWithTester3 = new DefaultScoreClient("http://localhost:9082/api/v3", + BigInteger.valueOf(3), userWallet, balanced.dex._address()); + + DefaultScoreClient clientWithTester4 = new DefaultScoreClient("http://localhost:9082/api/v3", + BigInteger.valueOf(3), userWallet, balanced.stakedLp._address()); + tokenAClient = _deploy(chain.getEndpointURL(), chain.networkId, balanced.owner, jarfile.getPath(), + Map.of("name", "Test Token", "symbol", "TT")); + tokenBClient = _deploy(chain.getEndpointURL(), chain.networkId, balanced.owner, jarfile.getPath(), + Map.of("name", "Test Base Token", "symbol", "TB")); + dexScoreClient = new DexScoreClient(clientWithTester3); + stakedlpUser = new StakedLPScoreClient(clientWithTester4); + + ownerDexTestScoreClient = new DexTestScoreClient(chain.getEndpointURL(), + chain.networkId, balanced.owner, tokenAClient._address()); + ownerDexTestBaseScoreClient = new DexTestScoreClient(chain.getEndpointURL(), + chain.networkId, balanced.owner, tokenBClient._address()); + }catch (Exception e) { + e.printStackTrace(); + System.out.println("Error on init test: " + e.getMessage()); + } } - Address userAddress = Address.of(userWallet); - - @Test @Order(1) void testStakeAndUnstake() { - + Address userAddress = Address.of(userWallet); DexTestScoreClient userDexTestScoreClient = new DexTestScoreClient("http://localhost:9082/api/v3", BigInteger.valueOf(3), userWallet, tokenAClient._address()); DexTestScoreClient userDexTestBaseScoreClient = new DexTestScoreClient("http://localhost:9082/api/v3", @@ -117,7 +122,7 @@ void testStakeAndUnstake() { dexAddQuoteCoin(tokenBClient._address()); // add tokens on dex and receive lp - testerScoreDex.add(tokenAClient._address(), tokenBClient._address(), BigInteger.valueOf(190).multiply(EXA), + dexScoreClient.add(tokenAClient._address(), tokenBClient._address(), BigInteger.valueOf(190).multiply(EXA), BigInteger.valueOf(190).multiply(EXA), false, BigInteger.valueOf(100)); BigInteger poolId = dex.getPoolId(tokenAClient._address(), tokenBClient._address()); @@ -131,7 +136,7 @@ void testStakeAndUnstake() { assertEquals(stakedlp.totalStaked(BigInteger.valueOf(5)), BigInteger.ZERO); // stake lp to stakedlp contract - testerScoreDex.transfer(Address.fromString(stakedlp._address().toString()), balance, + dexScoreClient.transfer(Address.fromString(stakedlp._address().toString()), balance, poolId, null); assertEquals(dex.balanceOf(userAddress, poolId), BigInteger.ZERO); @@ -156,13 +161,101 @@ void testStakeAndUnstake() { assertEquals(stakedlp.totalStaked(poolId), BigInteger.ZERO); // stakes lp to stakedlp contract - testerScoreDex.transfer(Address.fromString(stakedlp._address().toString()), remaining, + dexScoreClient.transfer(Address.fromString(stakedlp._address().toString()), remaining, poolId, null); assertEquals(dex.balanceOf(userAddress, poolId), balance.subtract(remaining)); assertEquals(stakedlp.balanceOf(userAddress, poolId), remaining); assertEquals(stakedlp.totalStaked(poolId), remaining); + } + @Test + @Order(2) + void crossChainStakeAndUnstake() { + // Arrange + NetworkAddress ethBaseAssetAddress = new NetworkAddress(balanced.ETH_NID, balanced.ETH_TOKEN_ADDRESS); + NetworkAddress ethQuoteAssetAddress = new NetworkAddress(balanced.ETH_NID, "ox100"); + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + BigInteger amount = BigInteger.valueOf(100).multiply(EXA); + String toNetworkAddress = new NetworkAddress(balanced.ICON_NID, dexScoreClient._address()).toString(); + String stakingAddress = new NetworkAddress(balanced.ICON_NID, stakedlp._address()).toString(); + + // Arrange - deploy a new token + JsonArray addAssetParams = new JsonArray() + .add(createParameter(ethQuoteAssetAddress.toString())) + .add(createParameter("ETHZ")) + .add(createParameter("ETHZ")) + .add(createParameter(BigInteger.valueOf(18))); + JsonObject addAsset = createTransaction(balanced.assetManager._address(), "deployAsset", addAssetParams); + JsonArray transactions = new JsonArray() + .add(addAsset); + balanced.governanceClient.execute(transactions.toString()); + + score.Address baseAssetAddress = owner.assetManager.getAssetAddress(ethBaseAssetAddress.toString()); + score.Address quoteAssetAddress = owner.assetManager.getAssetAddress(ethQuoteAssetAddress.toString()); + + // Arrange - deposits + byte[] deposit1 = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set( "address", ethAccount.toString()))); + owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit1); + + byte[] deposit2 = AssetManagerMessages.deposit("ox100", ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set( "address", ethAccount.toString()))); + owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit2); + + // Arrange add quote token + dexAddQuoteCoin((Address) quoteAssetAddress); + + // Arrange - add pool + byte[] xaddMessage = getAddLPData(baseAssetAddress, quoteAssetAddress, amount, amount, false, BigInteger.valueOf(5) ); + owner.xcall.recvCall(dexScoreClient._address(), ethAccount.toString(), xaddMessage); + + // Act - stake + BigInteger poolId = dexScoreClient.getPoolId(baseAssetAddress, + quoteAssetAddress); + try{ + addNewDataSource("test1", poolId, BigInteger.ONE); + } catch (Exception ignored){} + BigInteger balance = dexScoreClient.xBalanceOf(ethAccount.toString(), poolId); + byte[] stakeData = getStakeData(stakingAddress, balance, poolId, "stake".getBytes()); + owner.xcall.recvCall(owner.dex._address(), ethAccount.toString(), stakeData); + + // Verify stake + assertEquals(dex.xBalanceOf(ethAccount.toString(), poolId), BigInteger.ZERO); + assertEquals(stakedlp.xBalanceOf(ethAccount.toString(), poolId), balance); + assertEquals(stakedlp.totalStaked(poolId), balance); + + //act - unstake + BigInteger remainingStake = balance.divide(BigInteger.TWO); + byte[] unstakeData = getUnStakeData(poolId, remainingStake); + owner.xcall.recvCall(owner.stakedLp._address(), ethAccount.toString(), unstakeData); + + // Verify unstake + assertEquals(dex.xBalanceOf(ethAccount.toString(), poolId), remainingStake); + assertEquals(stakedlp.xBalanceOf(ethAccount.toString(), poolId), remainingStake); + assertEquals(stakedlp.totalStaked(poolId), remainingStake); + } + + static byte[] getStakeData(String to, BigInteger amount, BigInteger poolId, byte[] data) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(5); + writer.write("xhubtransfer"); + writer.write(to); + writer.write(amount); + writer.write(poolId); + writer.write(data); + writer.end(); + return writer.toByteArray(); + } + + static byte[] getUnStakeData(BigInteger poolId, BigInteger amount) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(3); + writer.write("xunstake"); + writer.write(poolId); + writer.write(amount); + writer.end(); + return writer.toByteArray(); } private void addNewDataSource(String name, BigInteger id, BigInteger type) { @@ -182,6 +275,27 @@ private void addNewDataSource(String name, BigInteger id, BigInteger type) { balanced.ownerClient.governance.execute(actions.toString()); } + static byte[] getAddLPData(score.Address baseToken, score.Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(7); + writer.write("xadd"); + writer.write(baseToken); + writer.write(quoteToken); + writer.write(baseValue); + writer.write(quoteValue); + writer.write(withdraw_unused); + writer.write(slippagePercentage); + writer.end(); + return writer.toByteArray(); + } + + public static byte[] tokenData(String method, JsonObject params) { + JsonObject data = new JsonObject(); + data.set("method", method); + data.set("params", params); + return data.toString().getBytes(); + } + private void dexAddQuoteCoin(Address address) { JsonArray params = new JsonArray() .add(createParameter(address)); diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index ba0f6a040..fce320ec3 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; +import static network.balanced.score.lib.utils.BalancedAddressManager.getXCall; import static network.balanced.score.lib.utils.Check.*; public class StakedLPImpl implements StakedLP { @@ -57,32 +58,23 @@ public StakedLPImpl(Address governance) { if (StakedLPImpl.governance.get() == null) { Context.require(governance.isContract(), "StakedLP: Governance address should be a contract"); StakedLPImpl.governance.set(governance); + BalancedAddressManager.setGovernance(governance); } if (currentVersion.getOrDefault("").equals(Versions.STAKEDLP)) { Context.revert("Can't Update same version of code"); } currentVersion.set(Versions.STAKEDLP); - NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); + NATIVE_NID = (String) Context.call(getXCall(), "getNetworkId"); } /* * Events */ - //todo: verify this fix works -// @EventLog(indexed = 1) -// public void Stake(Address _owner, BigInteger _id, BigInteger _value) { -// } - @EventLog(indexed = 1) public void Stake(String _owner, BigInteger _id, BigInteger _value) { } - // -// @EventLog(indexed = 1) -// public void Unstake(Address _owner, BigInteger _id, BigInteger _value) { -// } - @EventLog(indexed = 1) public void Unstake(String _owner, BigInteger _id, BigInteger _value) { } @@ -140,7 +132,7 @@ public BigInteger balanceOf(Address _owner, BigInteger _id) { } @External(readonly = true) - public BigInteger balanceOfV2(String _owner, BigInteger _id) { + public BigInteger xBalanceOf(String _owner, BigInteger _id) { NetworkAddress owner = NetworkAddress.valueOf(_owner); return poolStakedDetails.at(owner).getOrDefault(_id, BigInteger.ZERO); } @@ -152,9 +144,8 @@ public BigInteger totalStaked(BigInteger _id) { @External public void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) { - //todo: uncomment after unit test fix - //checkStatus(); - only(BalancedAddressManager.getXCall()); + checkStatus(); + only(getXCall()); XCallUtils.verifyXCallProtocols(_from, _protocols); StakedLPXCall.process(this, _from, _data); } @@ -197,7 +188,7 @@ private void unstake(BigInteger id, NetworkAddress user, BigInteger value){ } } - @Override + @External public void onIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data) { only(dex); Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); @@ -205,13 +196,13 @@ public void onIRC31Received(String _operator, String _from, BigInteger _id, BigI this.stake(from, _id, _value); } - @External - public void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data) { - only(dex); - Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); - NetworkAddress from = NetworkAddress.valueOf(_from.toString(), NATIVE_NID); - this.stake(from, _id, _value); - } +// @External +// public void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data) { +// only(dex); +// Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); +// NetworkAddress from = NetworkAddress.valueOf(_from.toString(), NATIVE_NID); +// this.stake(from, _id, _value); +// } @External public void addDataSource(BigInteger id, String name) { diff --git a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java index 3bca178b7..ee0373917 100644 --- a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java +++ b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java @@ -146,7 +146,8 @@ void setAndGetRewards() { } private void stakeLpTokens(Account from, BigInteger poolId, BigInteger value) { - stakedLpScore.invoke(dex.account, "onIRC31Received", from.getAddress(), from.getAddress(), poolId, value, + String fromNetworkAddress = NetworkAddress.valueOf(from.getAddress().toString(), NATIVE_NID).toString(); + stakedLpScore.invoke(dex.account, "onIRC31Received", fromNetworkAddress, fromNetworkAddress, poolId, value, new byte[0]); } @@ -175,22 +176,22 @@ void crossChainStake(){ // Pool 1 related tests // Stake 10 LP tokens from alice account stakeLpTokens(fromNetworkAddress1, BigInteger.ONE, BigInteger.TEN); - assertEquals(BigInteger.TEN, stakedLpScore.call("balanceOfV2", fromNetworkAddress1, BigInteger.ONE)); + assertEquals(BigInteger.TEN, stakedLpScore.call("xBalanceOf", fromNetworkAddress1, BigInteger.ONE)); assertEquals(BigInteger.TEN, stakedLpScore.call("totalStaked", BigInteger.ONE)); // Stake 100 more LP tokens from alice account stakeLpTokens(fromNetworkAddress1, BigInteger.ONE, BigInteger.valueOf(100L)); - assertEquals(BigInteger.valueOf(110L), stakedLpScore.call("balanceOfV2", fromNetworkAddress1, BigInteger.ONE)); + assertEquals(BigInteger.valueOf(110L), stakedLpScore.call("xBalanceOf", fromNetworkAddress1, BigInteger.ONE)); assertEquals(BigInteger.valueOf(110L), stakedLpScore.call("totalStaked", BigInteger.ONE)); // Stake 20 LP tokens from bob account stakeLpTokens(fromNetworkAddress2, BigInteger.ONE, BigInteger.valueOf(20L)); - assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOfV2", fromNetworkAddress2, BigInteger.ONE)); + assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("xBalanceOf", fromNetworkAddress2, BigInteger.ONE)); assertEquals(BigInteger.valueOf(130L), stakedLpScore.call("totalStaked", BigInteger.ONE)); // Pool 2 related tests - assertEquals(BigInteger.ZERO, stakedLpScore.call("balanceOfV2", fromNetworkAddress1, BigInteger.TWO)); - assertEquals(BigInteger.ZERO, stakedLpScore.call("balanceOfV2", fromNetworkAddress2, BigInteger.TWO)); + assertEquals(BigInteger.ZERO, stakedLpScore.call("xBalanceOf", fromNetworkAddress1, BigInteger.TWO)); + assertEquals(BigInteger.ZERO, stakedLpScore.call("xBalanceOf", fromNetworkAddress2, BigInteger.TWO)); assertEquals(BigInteger.ZERO, stakedLpScore.call("totalStaked", BigInteger.TWO)); // Stake 20 LP tokens from alice and bob account @@ -200,8 +201,8 @@ void crossChainStake(){ stakeLpTokens(fromNetworkAddress2, BigInteger.TWO, BigInteger.valueOf(20L)); verify(rewards.mock).updateBalanceAndSupply(poolTwoName, BigInteger.valueOf(20L), fromNetworkAddress1, BigInteger.valueOf(20L)); assertEquals(BigInteger.valueOf(40L), stakedLpScore.call("totalStaked", BigInteger.TWO)); - assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOfV2", fromNetworkAddress1, BigInteger.TWO)); - assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOfV2", fromNetworkAddress2, BigInteger.TWO)); + assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("xBalanceOf", fromNetworkAddress1, BigInteger.TWO)); + assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("xBalanceOf", fromNetworkAddress2, BigInteger.TWO)); } @Test diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java index 5fc5b4941..2dff64f01 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java @@ -52,6 +52,9 @@ public interface StakedLP extends Version { @External(readonly = true) BigInteger balanceOf(Address _owner, BigInteger _id); + @External(readonly = true) + BigInteger xBalanceOf(String _owner, BigInteger _id); + @External(readonly = true) BigInteger totalStaked(BigInteger _id); @@ -64,8 +67,8 @@ public interface StakedLP extends Version { @XCall void xUnstake(String from, BigInteger id, BigInteger value); - @External - void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data); +// @External +// void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data); @External void onIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data); From 39aaec5f1d5feda6221f0f6166d317f454ed2bf0 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 23 Oct 2024 13:09:38 +0545 Subject: [PATCH 03/31] integration test issues fixed --- .../network/balanced/score/core/daofund/DAOfundImpl.java | 3 ++- .../balanced/score/core/dex/NonStakedLPRewardsTest.java | 4 +++- .../network/balanced/score/core/rewards/RewardsImpl.java | 9 +++++++-- .../balanced/score/core/stakedlp/StakedLPImpl.java | 6 +++++- .../balanced/score/core/stakedlp/StakedLPTest.java | 4 ++-- .../balanced/score/lib/test/integration/Balanced.java | 8 ++++---- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/core-contracts/DAOfund/src/main/java/network/balanced/score/core/daofund/DAOfundImpl.java b/core-contracts/DAOfund/src/main/java/network/balanced/score/core/daofund/DAOfundImpl.java index 1d565349e..75a4e8aa0 100644 --- a/core-contracts/DAOfund/src/main/java/network/balanced/score/core/daofund/DAOfundImpl.java +++ b/core-contracts/DAOfund/src/main/java/network/balanced/score/core/daofund/DAOfundImpl.java @@ -272,8 +272,9 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { public void fallback() { } + //todo: verify if this is the solution @External - public void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data) { + public void onIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data) { checkStatus(); } diff --git a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/NonStakedLPRewardsTest.java b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/NonStakedLPRewardsTest.java index 6167fc600..fa6f59e38 100644 --- a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/NonStakedLPRewardsTest.java +++ b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/NonStakedLPRewardsTest.java @@ -20,6 +20,7 @@ import foundation.icon.jsonrpc.Address; import foundation.icon.jsonrpc.model.TransactionResult; import foundation.icon.score.client.DefaultScoreClient; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.interfaces.*; import network.balanced.score.lib.test.integration.Balanced; import network.balanced.score.lib.test.integration.Env; @@ -151,7 +152,8 @@ void testNonStakedLpRewards() { assertEquals(BigInteger.ZERO, rewards.getBalnHolding(userAddress.toString())); byte[] stakeLp = "{\"method\":\"_stake\"}".getBytes(); - dexUserScoreClient.transfer(balanced.stakedLp._address(), BigInteger.valueOf(90), BigInteger.valueOf(4), + BigInteger poolId = dexUserScoreClient.getPoolId(balanced.baln._address(), balanced.sicx._address()); + dexUserScoreClient.transfer(balanced.stakedLp._address(), BigInteger.valueOf(90), poolId, stakeLp); // user gets rewards after lp token is staked diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java index 5ab60e517..e60b93a33 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java @@ -1049,11 +1049,16 @@ private static BigInteger dailyDistribution(BigInteger day) { } private BigInteger fetchBoostedBalance(String user) { - if (user.contains("/")) { + NetworkAddress networkAddress = NetworkAddress.valueOf(user, NATIVE_NID); + Address address = null; + try{ + address = Address.fromString(user); + } catch (Exception ignored){} + if (!networkAddress.net().equals(NATIVE_NID) || address == null) { return BigInteger.ZERO; } - return fetchBoostedBalance(Address.fromString(user)); + return fetchBoostedBalance(address); } private BigInteger fetchBoostedBalance(Address user) { diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index fce320ec3..1a46e845b 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -275,6 +275,10 @@ private void stake(NetworkAddress user, BigInteger id, BigInteger value) { Stake(user.toString(), id, value); - Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, user.toString(), newBalance); + if(user.net().equals(NATIVE_NID)) { + Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, user.account(), newBalance); + }else{ + Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, user.toString(), newBalance); + } } } diff --git a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java index ee0373917..6b7ec783d 100644 --- a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java +++ b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java @@ -275,7 +275,7 @@ void testStake() { assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("totalStaked", BigInteger.TWO)); stakeLpTokens(bob, BigInteger.TWO, BigInteger.valueOf(20L)); - verify(rewards.mock).updateBalanceAndSupply(poolTwoName, BigInteger.valueOf(40L), NetworkAddress.valueOf(bob.getAddress().toString(), NATIVE_NID).toString(), BigInteger.valueOf(20L)); + verify(rewards.mock).updateBalanceAndSupply(poolTwoName, BigInteger.valueOf(40L), bob.getAddress().toString(), BigInteger.valueOf(20L)); assertEquals(BigInteger.valueOf(40L), stakedLpScore.call("totalStaked", BigInteger.TWO)); assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOf", alice.getAddress(), BigInteger.TWO)); assertEquals(BigInteger.valueOf(20L), stakedLpScore.call("balanceOf", bob.getAddress(), BigInteger.TWO)); @@ -387,7 +387,7 @@ void testStakeUnstake_unnamedPool() { Map balanceAndSupply = (Map) stakedLpScore.call("getBalanceAndSupply", name, alice.getAddress().toString()); assertEquals(BigInteger.TEN, balanceAndSupply.get("_balance")); assertEquals(BigInteger.TEN, balanceAndSupply.get("_totalSupply")); - verify(rewards.mock).updateBalanceAndSupply(name, balanceAndSupply.get("_totalSupply"), NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), balanceAndSupply.get("_balance")); + verify(rewards.mock).updateBalanceAndSupply(name, balanceAndSupply.get("_totalSupply"), alice.getAddress().toString(), balanceAndSupply.get("_balance")); // Act stakedLpScore.invoke(alice, "unstake", poolId, BigInteger.TWO); diff --git a/test-lib/src/main/java/network/balanced/score/lib/test/integration/Balanced.java b/test-lib/src/main/java/network/balanced/score/lib/test/integration/Balanced.java index 20b8de0a5..36b619dd8 100644 --- a/test-lib/src/main/java/network/balanced/score/lib/test/integration/Balanced.java +++ b/test-lib/src/main/java/network/balanced/score/lib/test/integration/Balanced.java @@ -98,11 +98,11 @@ public void setupBalanced() throws Exception { increaseDay(1); setupContracts(); // delegate(adminWallet); - //String className = new Exception().getStackTrace()[1].getClassName(); + String className = new Exception().getStackTrace()[1].getClassName(); // no need to set up market in staking integration test case -// if (!className.equals("network.balanced.score.core.staking.StakingIntegrationTest")) { -// setupMarkets(); -// } + if (!className.equals("network.balanced.score.core.staking.StakingIntegrationTest")) { + setupMarkets(); + } } public void deployContracts() { From ad6b8acd783d39d4fe821c33f836c9732ffb8c21 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Sat, 26 Oct 2024 15:25:04 +0545 Subject: [PATCH 04/31] Token transfer utility implementation, crossTransfer commented out --- .../core/asset/manager/AssetManagerImpl.java | 1 - .../score/core/dex/DexIntegrationTest.java | 5 +++ .../balanced/score/core/dex/DexImpl.java | 14 ++++---- .../balanced/score/core/dex/DexTestCore.java | 33 +++++++++++------ .../score/core/rewards/RewardsImpl.java | 19 ++-------- .../score/core/rewards/RewardsTestBase.java | 7 ++++ .../rewards/RewardsTestExternalRewards.java | 10 ++++-- .../score/lib/utils/TokenTransfer.java | 35 +++++++++++++++++++ 8 files changed, 88 insertions(+), 36 deletions(-) create mode 100644 score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java diff --git a/core-contracts/AssetManager/src/main/java/network/balanced/score/core/asset/manager/AssetManagerImpl.java b/core-contracts/AssetManager/src/main/java/network/balanced/score/core/asset/manager/AssetManagerImpl.java index fd7abd9d7..60bd87507 100644 --- a/core-contracts/AssetManager/src/main/java/network/balanced/score/core/asset/manager/AssetManagerImpl.java +++ b/core-contracts/AssetManager/src/main/java/network/balanced/score/core/asset/manager/AssetManagerImpl.java @@ -18,7 +18,6 @@ import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.interfaces.AssetManager; -import network.balanced.score.lib.interfaces.AssetManagerMessages; import network.balanced.score.lib.interfaces.AssetManagerXCall; import network.balanced.score.lib.interfaces.SpokeAssetManagerMessages; import network.balanced.score.lib.utils.*; diff --git a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java index 72362be4b..6530742a4 100644 --- a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java +++ b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java @@ -413,6 +413,11 @@ void xRemove(){ quoteAssetAddress); BigInteger balance = dexUserScoreClient.xBalanceOf(ethAccount.toString(), poolId); BigInteger withdrawAmount = balance.divide(BigInteger.TWO); + JsonArray setXCallFeePermissionParameters = new JsonArray() + .add(createParameter(balanced.dex._address())).add(createParameter(balanced.ETH_NID)).add(createParameter(true)); + JsonArray actions = new JsonArray() + .add(createTransaction(balanced.daofund._address(), "setXCallFeePermission", setXCallFeePermissionParameters)); + owner.governance.execute(actions.toString()); // Act byte[] removeLPMsg = getXRemoveData(poolId, withdrawAmount, true); diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index 0e0281b9b..24d65a4fd 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -63,6 +63,10 @@ public String version() { @Payable public void fallback() { + Address user = Context.getCaller(); + if(user.equals(BalancedAddressManager.getDaofund())){ + return; + } isDexOn(); checkStatus(); @@ -70,7 +74,7 @@ public void fallback() { require(orderValue.compareTo(BigInteger.TEN.multiply(EXA)) >= 0, TAG + ": Minimum pool contribution is 10 ICX"); - Address user = Context.getCaller(); + BigInteger oldOrderValue = BigInteger.ZERO; BigInteger orderId = icxQueueOrderId.getOrDefault(user, BigInteger.ZERO); @@ -264,11 +268,9 @@ private void _withdraw(NetworkAddress sender, Address _token, BigInteger _value) Withdraw(_token, sender.toString(), _value); BalancedFloorLimits.verifyWithdraw(_token, _value); - if(sender.net().equals(NATIVE_NID)) { - Context.call(_token, "transfer", Address.fromString(sender.account()), _value); - }else{ - Context.call(_token, "hubTransfer", sender.toString(), _value); - } + + //transfer the token + TokenTransfer.transfer(_token, sender.toString(), _value); } @External(readonly = true) diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java index 3f925c360..44479408d 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java @@ -20,6 +20,7 @@ import com.iconloop.score.test.Account; import network.balanced.score.core.dex.utils.Const; import network.balanced.score.lib.structs.PrepDelegations; +import network.balanced.score.lib.utils.BalancedAddressManager; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,6 +35,7 @@ import java.util.Map; import static network.balanced.score.core.dex.utils.Const.*; +import static network.balanced.score.lib.utils.BalancedAddressManager.getDaofund; import static network.balanced.score.lib.utils.Constants.EXA; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -207,8 +209,10 @@ void xRemoveAndWithdraw(){ // Act byte[] xRemoveData = getXRemoveData(poolId, lpTokensToRemove, true); - contextMock.when(() -> Context.call(eq(bnusdScore.getAddress()), eq("hubTransfer"), any(), any())).thenReturn(true); - contextMock.when(() -> Context.call(eq(sicxScore.getAddress()), eq("hubTransfer"), any(), any())).thenReturn(true); + contextMock.when(() -> Context.call(any(Address.class), eq("getXCallFeePermission"), any(Address.class), any(String.class))).thenReturn(true); + contextMock.when(() -> Context.call(any(Address.class), eq("getNativeAssetAddress"), any(Address.class), any(String.class))).thenReturn(null); + contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); + contextMock.when(() -> Context.call(any(BigInteger.class), any(Address.class), eq("crossTransfer"), any(String.class), any(BigInteger.class), any(byte[].class))).thenReturn(null); contextMock.when(() -> Context.call(eq(stakingScore.getAddress()), eq("getTodayRate"))).thenReturn(EXA); handleCallMessageWithOutProtocols(fromNetworkAddress, xRemoveData, protocols); @@ -260,7 +264,7 @@ void withdrawSicxEarnings() { supplyIcxLiquidity(depositor, depositBalance); contextMock.when(() -> Context.call(eq(balnScore.getAddress()), eq("transfer"), eq(depositor.getAddress()), - eq(withdrawValue))).thenReturn(null); + eq(withdrawValue), any(byte[].class))).thenReturn(null); // Act. dexScore.invoke(depositor, "withdraw", balnScore.getAddress(), withdrawValue); @@ -291,8 +295,10 @@ void getSicxEarnings() { contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); contextMock.when(() -> Context.call(eq(stakingScore.getAddress()), eq("getTodayRate"))).thenReturn(EXA); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), - any(BigInteger.class))).thenReturn(null); + any(BigInteger.class), any(byte[].class))).thenReturn(null); + contextMock.when(() -> Context.transfer(any(Address.class), any(BigInteger.class))).then(invocationOnMock -> null); + BigInteger depositBalance = BigInteger.valueOf(100L).multiply(EXA); supplyIcxLiquidity(depositor, depositBalance); @@ -374,7 +380,7 @@ void withdrawToken() { depositToken(depositor, balnScore, depositValue); contextMock.when(() -> Context.call(eq(balnScore.getAddress()), eq("transfer"), eq(depositor.getAddress()), - eq(withdrawValue))).thenReturn(null); + eq(withdrawValue), any(byte[].class))).thenReturn(null); // Act. dexScore.invoke(depositor, "withdraw", balnScore.getAddress(), withdrawValue); @@ -399,7 +405,7 @@ void addLiquidity() { contextMock.when(() -> Context.call(eq(dividendsScore.getAddress()), eq("distribute"))).thenReturn(true); contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), - any(BigInteger.class))).thenReturn(null); + any(BigInteger.class), any(byte[].class))).thenReturn(null); BigInteger FIFTY = BigInteger.valueOf(50L).multiply(EXA); //deposit @@ -494,6 +500,8 @@ void tokenFallbackSwapFromTokenIs_poolQuote() { contextMock.when(() -> Context.call(eq(rewardsScore.getAddress()), eq("distribute"))).thenReturn(true); contextMock.when(() -> Context.call(eq(dividendsScore.getAddress()), eq("distribute"))).thenReturn(true); contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); + contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), + any(BigInteger.class), any(byte[].class))).thenReturn(null); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), any(BigInteger.class))).thenReturn(null); @@ -533,6 +541,7 @@ void tokenFallbackSwapFromTokenIs_poolQuote() { params.add("toToken", balnScore.getAddress().toString()); jsonData.add("method", "_swap"); jsonData.add("params", params); + dexScore.invoke(bnusdScore, "tokenFallback", account.getAddress(), value, jsonData.toString().getBytes()); Map newPoolStats = (Map) dexScore.call("getPoolStats", poolId); BigInteger newBalance = (BigInteger) dexScore.call("balanceOf", account.getAddress(), poolId); @@ -559,6 +568,8 @@ void tokenFallbackSwapFromTokenIs_poolBase() { contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), any(BigInteger.class))).thenReturn(null); + contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), + any(BigInteger.class), any(byte[].class))).thenReturn(null); BigInteger FIFTY = BigInteger.valueOf(50L).multiply(EXA); //deposit @@ -629,6 +640,8 @@ void tokenFallback_donate() { contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), any(BigInteger.class))).thenReturn(null); + contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), + any(BigInteger.class), any(byte[].class))).thenReturn(null); BigInteger FIFTY = BigInteger.valueOf(50L).multiply(EXA); //deposit @@ -735,7 +748,7 @@ void transfer() { contextMock.when(() -> Context.call(eq(dividendsScore.getAddress()), eq("distribute"))).thenReturn(true); contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), - any(BigInteger.class))).thenReturn(null); + any(BigInteger.class), any(byte[].class))).thenReturn(null); BigInteger FIFTY = BigInteger.valueOf(50L).multiply(EXA); dexScore.invoke(bnusdScore, "tokenFallback", account.getAddress(), BigInteger.valueOf(50L).multiply(EXA), @@ -769,7 +782,7 @@ void transfer_toSelf() { contextMock.when(() -> Context.call(eq(dividendsScore.getAddress()), eq("distribute"))).thenReturn(true); contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), - any(BigInteger.class))).thenReturn(null); + any(BigInteger.class), any(byte[].class))).thenReturn(null); BigInteger FIFTY = BigInteger.valueOf(50L).multiply(EXA); dexScore.invoke(bnusdScore, "tokenFallback", account.getAddress(), BigInteger.valueOf(50L).multiply(EXA), @@ -815,7 +828,7 @@ void getTotalValue() { contextMock.when(() -> Context.call(eq(dividendsScore.getAddress()), eq("distribute"))).thenReturn(true); contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), - any(BigInteger.class))).thenReturn(null); + any(BigInteger.class), any(byte[].class))).thenReturn(null); BigInteger FIFTY = BigInteger.valueOf(50L).multiply(EXA); //deposit @@ -847,7 +860,7 @@ void getPoolStatsWithPair() { contextMock.when(() -> Context.call(eq(dividendsScore.getAddress()), eq("distribute"))).thenReturn(true); contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), - any(BigInteger.class))).thenReturn(null); + any(BigInteger.class), any(byte[].class))).thenReturn(null); //deposit BigInteger bnusdValue = BigInteger.valueOf(276L).multiply(EXA); diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java index e60b93a33..003112218 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java @@ -424,13 +424,7 @@ private void _claimRewards(String address, String[] sources){ for (Address token : tokens) { BigInteger amount = holdingsDB.getOrDefault(token, BigInteger.ZERO); if (amount.compareTo(BigInteger.ZERO) > 0) { - if(networkAddress.net().equals(NATIVE_NID)) { - Context.call(token, "transfer", Address.fromString(networkAddress.account()), amount, new byte[0]); - }else{ - try { - Context.call(token, "xTransfer", address, amount, new byte[0]); - }catch (Exception ignored){} - } + TokenTransfer.transfer(token, networkAddress.toString(), amount); holdingsDB.set(token, null); RewardsClaimedV2(token, address, amount); } @@ -440,16 +434,7 @@ private void _claimRewards(String address, String[] sources){ if (userClaimableRewards.compareTo(BigInteger.ZERO) > 0) { balnHoldings.set(address, null); Address baln = getBaln(); - if(networkAddress.net().equals(NATIVE_NID)) { - Address nativeAddress = Address.fromString(networkAddress.account()); - Context.call(baln, "transfer", nativeAddress, userClaimableRewards, new byte[0]); - RewardsClaimed(nativeAddress, userClaimableRewards); - }else{ - try { - Context.call(baln, "xTransfer", address, userClaimableRewards, new byte[0]); - }catch (Exception ignored){} - } - + TokenTransfer.transfer(baln, networkAddress.toString(), userClaimableRewards); RewardsClaimedV2(baln, address, userClaimableRewards); } diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java index 28b897175..35270539b 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java @@ -27,7 +27,10 @@ import network.balanced.score.lib.test.mock.MockBalanced; import static network.balanced.score.lib.utils.Constants.MICRO_SECONDS_IN_A_DAY; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import score.Address; +import score.Context; import java.math.BigInteger; import java.util.Map; @@ -85,7 +88,11 @@ void setup() throws Exception { BigInteger startTime = BigInteger.valueOf(sm.getBlock().getTimestamp()); // One vote period before being able to start voting sm.getBlock().increase(DAY*10); + when(mockBalanced.xCall.mock.getNetworkId()).thenReturn(NATIVE_NID); + doNothing().when(mockBalanced.sicx.mock).transfer(any(Address.class), any(BigInteger.class), any(byte[].class)); + doNothing().when(mockBalanced.baln.mock).transfer(any(Address.class), any(BigInteger.class), any(byte[].class)); + when(mockBalanced.daofund.mock.getXCallFeePermission(any(Address.class), any(String.class))).thenReturn(true); rewardsScore = sm.deploy(owner, RewardsImpl.class, governance.getAddress()); rewardsScoreSpy = (RewardsImpl) spy(rewardsScore.getInstance()); diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java index 85f48d444..ec1dc7fa0 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java @@ -18,6 +18,8 @@ import com.iconloop.score.test.Account; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import score.Address; import org.json.JSONArray; @@ -27,11 +29,12 @@ import score.ByteArrayObjectWriter; import score.Context; +import static network.balanced.score.lib.utils.Constants.*; +import static network.balanced.score.lib.utils.Constants.EXA; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; -import static network.balanced.score.lib.utils.Constants.MICRO_SECONDS_IN_A_DAY; -import static network.balanced.score.lib.utils.Constants.MICRO_SECONDS_IN_A_SECOND; import java.math.BigInteger; import java.util.ArrayList; @@ -194,6 +197,7 @@ void externalRewards_MultipleSources() { // Assert Map rewards = (Map) rewardsScore.call("getRewards", account.getAddress().toString()); + rewardsScore.invoke(account, "claimRewards", getUserSources(account.getAddress())); verify(mockBalanced.sicx.mock).transfer(account.getAddress(), expectedRewards1.add(expectedRewards2), new byte[0]); @@ -370,6 +374,8 @@ void externalRewards_crosschain() { fromNetworkAddress); String[] sources = {"sICX/ICX", "sICX/bnUSD"}; String[] protocols = {}; + + rewardsScore.invoke(mockBalanced.xCall.account, "handleCallMessage", fromNetworkAddress, getClaimRewardData(fromNetworkAddress, sources), protocols); //todo: calculate the expected value and replace the hard coded value diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java b/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java new file mode 100644 index 000000000..354bc19df --- /dev/null +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java @@ -0,0 +1,35 @@ +package network.balanced.score.lib.utils; + +import foundation.icon.xcall.NetworkAddress; +import score.Address; +import score.Context; + +import java.math.BigInteger; + +import static network.balanced.score.lib.utils.BalancedAddressManager.getDaofund; + + +public class TokenTransfer { + + public static void transfer(Address token, String to, BigInteger amount){ + NetworkAddress toNetworkAddress = NetworkAddress.parse(to); + String NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); + if(!NATIVE_NID.equals(toNetworkAddress.net())) { + Context.require(canWithdraw(toNetworkAddress.net()), "enable can withdraw first"); + String nativeAddress = (String) Context.call(BalancedAddressManager.getAssetManager(), "getNativeAssetAddress", token, toNetworkAddress.net()); + BigInteger xCallFee = (BigInteger) Context.call(BalancedAddressManager.getDaofund(), "claimXCallFee", toNetworkAddress.net(), false); + if (nativeAddress == null) { + //todo: uncomment latter + //Context.call(xCallFee, token, "crossTransfer", to, amount, new byte[0]); + } else { + Context.call(xCallFee, BalancedAddressManager.getAssetManager(), "withdrawTo", token, to, amount); + } + }else{ + Context.call(token, "transfer", Address.fromString(toNetworkAddress.account()), amount, new byte[0]); + } + } + + private static boolean canWithdraw(String net) { + return (Boolean) Context.call(getDaofund(), "getXCallFeePermission", Context.getAddress(), net); + } +} From 558117edd62e45dfb8a3fd88b30d3df75bfb6381 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 28 Oct 2024 16:44:56 +0545 Subject: [PATCH 05/31] test: all test pass including router update --- .../score/core/reserve/ReserveFundTest.java | 15 ++++-- .../core/reserve/ReserveFundTestBase.java | 6 ++- .../score/core/router/RouterImpl.java | 54 ++----------------- .../score/core/router/RouterTest.java | 27 ++++++---- .../score/lib/interfaces/BalancedToken.java | 16 +++++- .../balanced/score/lib/interfaces/Sicx.java | 16 +++++- .../score/lib/interfaces/tokens/HubToken.java | 4 ++ .../score/lib/utils/TokenTransfer.java | 33 ++++++++---- 8 files changed, 91 insertions(+), 80 deletions(-) diff --git a/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/ReserveFundTest.java b/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/ReserveFundTest.java index 4c18b13d2..c0b32bac0 100644 --- a/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/ReserveFundTest.java +++ b/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/ReserveFundTest.java @@ -17,6 +17,7 @@ package network.balanced.score.core.reserve; import com.iconloop.score.test.Account; +import network.balanced.score.lib.interfaces.tokens.HubToken; import network.balanced.score.lib.interfaces.tokens.IRC2Mintable; import network.balanced.score.lib.structs.Disbursement; import network.balanced.score.lib.test.mock.MockContract; @@ -45,7 +46,11 @@ private void setupCollaterals() { when(loans.mock.getCollateralTokens()).thenReturn(tokens); } - private void setBalance(MockContract token, BigInteger amount) { + private void setBalance(MockContract token, BigInteger amount) { + when(token.mock.balanceOf(reserve.getAddress())).thenReturn(amount); + } + + private void setIRC2Balance(MockContract token, BigInteger amount) { when(token.mock.balanceOf(reserve.getAddress())).thenReturn(amount); } @@ -101,7 +106,7 @@ void redeem_multiCollateral() { setBalance(sicx, sicxBalance); setRate("sICX", sicxRate); - setBalance(ieth, iethBalance); + setIRC2Balance(ieth, iethBalance); setRate("iETH", iethRate); // Act @@ -132,7 +137,7 @@ void redeem_useBaln_iETH() { setBalance(sicx, sicxBalance); setRate("sICX", sicxRate); - setBalance(ieth, iethBalance); + setIRC2Balance(ieth, iethBalance); setRate("iETH", iethRate); setBalance(baln, balnBalance); @@ -166,7 +171,7 @@ void redeem_useBaln_sICX() { setBalance(sicx, sicxBalance); setRate("sICX", sicxRate); - setBalance(ieth, iethBalance); + setIRC2Balance(ieth, iethBalance); setRate("iETH", iethRate); setBalance(baln, balnBalance); @@ -196,7 +201,7 @@ void redeem_notEnoughBalance() { setBalance(sicx, sicxBalance); setRate("sICX", sicxRate); - setBalance(ieth, iethBalance); + setIRC2Balance(ieth, iethBalance); setRate("iETH", iethRate); setBalance(baln, balnBalance); diff --git a/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/ReserveFundTestBase.java b/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/ReserveFundTestBase.java index 2418f06ca..5f0049810 100644 --- a/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/ReserveFundTestBase.java +++ b/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/ReserveFundTestBase.java @@ -20,7 +20,9 @@ import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; import network.balanced.score.lib.interfaces.BalancedOracle; +import network.balanced.score.lib.interfaces.BalancedToken; import network.balanced.score.lib.interfaces.Loans; +import network.balanced.score.lib.interfaces.Sicx; import network.balanced.score.lib.interfaces.tokens.IRC2Mintable; import network.balanced.score.lib.interfaces.tokens.IRC2MintableScoreInterface; import network.balanced.score.lib.test.UnitTest; @@ -44,8 +46,8 @@ public class ReserveFundTestBase extends UnitTest { protected Score reserve; MockBalanced mockBalanced; MockContract loans; - MockContract baln; - MockContract sicx; + MockContract baln; + MockContract sicx; MockContract ieth; MockContract balancedOracle; 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 8bf87e1a5..778257abc 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 @@ -25,10 +25,7 @@ import network.balanced.score.lib.structs.Route; import network.balanced.score.lib.structs.RouteAction; import network.balanced.score.lib.structs.RouteData; -import network.balanced.score.lib.utils.BalancedAddressManager; -import network.balanced.score.lib.utils.Names; -import network.balanced.score.lib.utils.Versions; -import network.balanced.score.lib.utils.XCallUtils; +import network.balanced.score.lib.utils.*; import score.Address; import score.Context; import score.UserRevertException; @@ -176,58 +173,17 @@ private void route(String from, Address startToken, List _path, Big BigInteger balance = (BigInteger) Context.call(currentToken, "balanceOf", Context.getAddress()); Context.require(balance.compareTo(_minReceive) >= 0, TAG + ": Below minimum receive amount of " + _minReceive); - if (networkAddress.net().equals(nativeNid)) { + byte[] data = new byte[0]; + if(networkAddress.net().equals(nativeNid)){ Context.require(!toNative, TAG + ": Native swaps not available to icon from " + currentToken); - Context.call(currentToken, "transfer", Address.fromString(networkAddress.account()), balance, EMPTY_DATA); - } else { - transferCrossChainResult(currentToken, networkAddress, balance, toNative); + data = EMPTY_DATA; } + TokenTransfer.transfer(currentToken, networkAddress.toString(), balance, toNative, data); Route(fromAddress, fromAmount, currentToken, balance); } - private void transferCrossChainResult(Address token, NetworkAddress to, BigInteger amount, boolean toNative) { - String toNet = to.net(); - if (canWithdraw(toNet)) { - if (token.equals(getBnusd())) { - transferBnUSD(token, to, amount); - } else { - transferHubToken(token, to, amount, toNative); - } - } else { - Context.require(!toNative, TAG + ": Native swaps are not supported for this network"); - Context.call(token, "hubTransfer", to.toString(), amount, new byte[0]); - } - } - - private void transferBnUSD(Address bnusd, NetworkAddress to, BigInteger amount) { - String toNet = to.net(); - BigInteger xCallFee = Context.call(BigInteger.class, getDaofund(), "claimXCallFee", toNet, false); - Context.call(xCallFee, bnusd, "crossTransfer", to.toString(), amount, new byte[0]); - } - - private void transferHubToken(Address token, NetworkAddress to, BigInteger amount, boolean toNative) { - String toNet = to.net(); - Address assetManager = getAssetManager(); - String nativeAddress = Context.call(String.class, assetManager, "getNativeAssetAddress", token, toNet); - if (nativeAddress != null) { - BigInteger xCallFee = Context.call(BigInteger.class, getDaofund(), "claimXCallFee", toNet, false); - String method = "withdrawTo"; - if (toNative) { - method = "withdrawNativeTo"; - } - Context.call(xCallFee, assetManager, method, token, to.toString(), amount); - } else { - Context.require(!toNative, TAG + ": Native swaps are not supported to other networks"); - Context.call(token, "hubTransfer", to.toString(), amount, new byte[0]); - } - } - - private boolean canWithdraw(String net) { - return Context.call(Boolean.class, getDaofund(), "getXCallFeePermission", Context.getAddress(), net); - } - @Payable @External public void route(Address[] _path, @Optional BigInteger _minReceive, @Optional String _receiver) { diff --git a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java index 1c249703d..c0dddbc77 100644 --- a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java +++ b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java @@ -22,19 +22,20 @@ import com.iconloop.score.test.TestBase; import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.interfaces.Sicx; -import network.balanced.score.lib.interfaces.tokens.IRC2; -import network.balanced.score.lib.interfaces.tokens.IRC2ScoreInterface; -import network.balanced.score.lib.interfaces.tokens.SpokeToken; -import network.balanced.score.lib.interfaces.tokens.SpokeTokenScoreInterface; +import network.balanced.score.lib.interfaces.tokens.*; import network.balanced.score.lib.structs.Route; import network.balanced.score.lib.structs.RouteAction; import network.balanced.score.lib.structs.RouteData; import network.balanced.score.lib.test.mock.MockBalanced; import network.balanced.score.lib.test.mock.MockContract; +import network.balanced.score.lib.tokens.HubTokenImpl; +import network.balanced.score.lib.tokens.IRC2Base; +import network.balanced.score.lib.tokens.IRC2Mintable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; import score.Address; +import score.Context; import scorex.util.ArrayList; import java.math.BigInteger; @@ -43,8 +44,11 @@ import static network.balanced.score.core.router.RouterImpl.*; import static network.balanced.score.lib.test.UnitTest.*; +import static network.balanced.score.lib.utils.Constants.EXA; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -245,7 +249,7 @@ void xTrade_WithdrawNotAllowed() throws Exception { @Test void xTrade_ToNetworkAddressWithDifferentNet() throws Exception { // Arrange - MockContract token = new MockContract<>(SpokeTokenScoreInterface.class, SpokeToken.class, sm, + MockContract token = new MockContract<>(HubTokenScoreInterface.class, HubToken.class, sm, owner); String net = "0x1.eth"; String net2 = "0x3.bsc"; @@ -264,7 +268,7 @@ void xTrade_ToNetworkAddressWithDifferentNet() throws Exception { routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); // Assert - verify(token.mock).hubTransfer(receiver.toString(), amount, new byte[0]); + verify(token.mock).crossTransfer(receiver.toString(), amount, new byte[0]); } @Test @@ -287,7 +291,7 @@ void xTradeNative_ToNetworkAddressWithDifferentNet() throws Exception { byte[] path = tokenData("_swap", Map.of("path", new Object[]{token.getAddress().toString(), null}, "receiver", receiver.toString())); Executable nativeToWrongNet = () -> routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); - String expectedErrorMessage = "Reverted(0): " + TAG + ": Native swaps are not supported to other networks"; + String expectedErrorMessage = "Reverted(0): Native swaps are not supported for this network"; expectErrorMessage(nativeToWrongNet, expectedErrorMessage); } @@ -310,7 +314,7 @@ void xTradeNative_cannotWithdraw() throws Exception { byte[] path = tokenData("_swap", Map.of("path", new Object[]{token.getAddress().toString(), null}, "receiver", receiver.toString())); Executable nativeToWrongNet = () -> routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); - String expectedErrorMessage = "Reverted(0): " + TAG + ": Native swaps are not supported for this network"; + String expectedErrorMessage = "Reverted(0): Native swaps are not supported for this network"; expectErrorMessage(nativeToWrongNet, expectedErrorMessage); } @@ -362,20 +366,21 @@ void xTrade_ToBnUSD() throws Exception { @Test void xTrade_toIRC20() throws Exception { // Arrange + MockContract token = new MockContract<>(IRC2ScoreInterface.class, IRC2.class, sm, owner); String net = "0x1.eth"; NetworkAddress user = new NetworkAddress(net, "cx1"); BigInteger amount = BigInteger.TEN.multiply(ICX); - when(balanced.sicx.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); + when(token.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); when(balanced.bnUSD.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); when(balanced.daofund.mock.getXCallFeePermission(routerScore.getAddress(), net)).thenReturn(true); // Act & Assert byte[] path = tokenData("_swap", Map.of("path", - new Object[]{balanced.sicx.getAddress().toString()})); + new Object[]{token.getAddress().toString()})); Executable tradeToIRC2WithNetworkAddress = () -> routerScore.invoke(balanced.bnUSD.account, "xTokenFallback", user.toString(), amount, path); - expectErrorMessage(tradeToIRC2WithNetworkAddress, "hubTransfer"); + expectErrorMessage(tradeToIRC2WithNetworkAddress, "crossTransfer"); } @Test diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/BalancedToken.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/BalancedToken.java index 2d8760f37..bf3f35b87 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/BalancedToken.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/BalancedToken.java @@ -20,18 +20,20 @@ import foundation.icon.score.client.ScoreInterface; import network.balanced.score.lib.interfaces.addresses.*; import network.balanced.score.lib.interfaces.base.Version; +import network.balanced.score.lib.interfaces.tokens.HubToken; import network.balanced.score.lib.interfaces.tokens.IRC2BurnableInterface; import network.balanced.score.lib.interfaces.tokens.IRC2Mintable; import score.Address; import score.annotation.EventLog; import score.annotation.External; +import score.annotation.Optional; import java.math.BigInteger; import java.util.Map; @ScoreClient @ScoreInterface -public interface BalancedToken extends IRC2Mintable, IRC2BurnableInterface, GovernanceAddress, AdminAddress, +public interface BalancedToken extends HubToken, IRC2BurnableInterface, GovernanceAddress, AdminAddress, BnusdAddress, OracleAddress, DexAddress, DividendsAddress, Version { @External @@ -117,4 +119,16 @@ public interface BalancedToken extends IRC2Mintable, IRC2BurnableInterface, Gove @EventLog(indexed = 3) void OraclePrice(String market, String oracle_name, Address oracle_address, BigInteger price); + + @External + void setMinter(Address _address); + + @External(readonly = true) + Address getMinter(); + + @External + void mint(BigInteger _amount, @Optional byte[] _data); + + @External + void mintTo(Address _account, BigInteger _amount, @Optional byte[] _data); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Sicx.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Sicx.java index b5af312aa..5b7e5338c 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Sicx.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Sicx.java @@ -20,16 +20,18 @@ import foundation.icon.score.client.ScoreInterface; import network.balanced.score.lib.interfaces.addresses.StakingAddress; import network.balanced.score.lib.interfaces.base.Version; +import network.balanced.score.lib.interfaces.tokens.HubToken; import network.balanced.score.lib.interfaces.tokens.IRC2BurnableInterface; import network.balanced.score.lib.interfaces.tokens.IRC2Mintable; import score.Address; import score.annotation.External; +import score.annotation.Optional; import java.math.BigInteger; @ScoreClient @ScoreInterface -public interface Sicx extends StakingAddress, IRC2BurnableInterface, IRC2Mintable, Version { +public interface Sicx extends StakingAddress, HubToken, IRC2BurnableInterface, Version { @External void setEmergencyManager(Address _address); @@ -44,4 +46,16 @@ public interface Sicx extends StakingAddress, IRC2BurnableInterface, IRC2Mintabl @External(readonly = true) BigInteger lastPriceInLoop(); + + @External + void setMinter(Address _address); + + @External(readonly = true) + Address getMinter(); + + @External + void mint(BigInteger _amount, @Optional byte[] _data); + + @External + void mintTo(Address _account, BigInteger _amount, @Optional byte[] _data); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/HubToken.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/HubToken.java index 6d715bcbe..3f59a4562 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/HubToken.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/HubToken.java @@ -16,6 +16,8 @@ package network.balanced.score.lib.interfaces.tokens; +import foundation.icon.score.client.ScoreClient; +import foundation.icon.score.client.ScoreInterface; import network.balanced.score.lib.annotations.XCall; import score.annotation.EventLog; import score.annotation.External; @@ -23,6 +25,8 @@ import java.math.BigInteger; +@ScoreClient +@ScoreInterface public interface HubToken extends SpokeToken { /** * Returns the total token supply across all connected chains. diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java b/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java index 354bc19df..90300f359 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java @@ -8,27 +8,38 @@ import static network.balanced.score.lib.utils.BalancedAddressManager.getDaofund; - public class TokenTransfer { - public static void transfer(Address token, String to, BigInteger amount){ + public static void transfer(Address token, String to, BigInteger amount, boolean toNative, byte[] data){ NetworkAddress toNetworkAddress = NetworkAddress.parse(to); String NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); if(!NATIVE_NID.equals(toNetworkAddress.net())) { - Context.require(canWithdraw(toNetworkAddress.net()), "enable can withdraw first"); - String nativeAddress = (String) Context.call(BalancedAddressManager.getAssetManager(), "getNativeAssetAddress", token, toNetworkAddress.net()); - BigInteger xCallFee = (BigInteger) Context.call(BalancedAddressManager.getDaofund(), "claimXCallFee", toNetworkAddress.net(), false); - if (nativeAddress == null) { - //todo: uncomment latter - //Context.call(xCallFee, token, "crossTransfer", to, amount, new byte[0]); - } else { - Context.call(xCallFee, BalancedAddressManager.getAssetManager(), "withdrawTo", token, to, amount); + if(canWithdraw(toNetworkAddress.net())) { + String nativeAddress = (String) Context.call(BalancedAddressManager.getAssetManager(), "getNativeAssetAddress", token, toNetworkAddress.net()); + BigInteger xCallFee = (BigInteger) Context.call(BalancedAddressManager.getDaofund(), "claimXCallFee", toNetworkAddress.net(), false); + if (nativeAddress == null) { + Context.require(!toNative, "Native swaps are not supported for this network"); + Context.call(xCallFee, token, "crossTransfer", to, amount, data); + } else { + if (toNative) { + Context.call(xCallFee, BalancedAddressManager.getAssetManager(), "withdrawNativeTo", token, to, amount); + } else { + Context.call(xCallFee, BalancedAddressManager.getAssetManager(), "withdrawTo", token, to, amount); + } + } + }else{ + Context.require(!toNative, "Native swaps are not supported for this network"); + Context.call(token, "hubTransfer", toNetworkAddress.toString(), amount, data); } }else{ - Context.call(token, "transfer", Address.fromString(toNetworkAddress.account()), amount, new byte[0]); + Context.call(token, "transfer", Address.fromString(toNetworkAddress.account()), amount, data); } } + public static void transfer(Address token, String to, BigInteger amount){ + transfer(token, to, amount, false, new byte[0]); + } + private static boolean canWithdraw(String net) { return (Boolean) Context.call(getDaofund(), "getXCallFeePermission", Context.getAddress(), net); } From eaa39ef05cbc58bbd407bf4bb2d5f9611c924573 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 29 Oct 2024 20:08:26 +0545 Subject: [PATCH 06/31] Fixes: review fixes --- .../score/core/daofund/DAOfundImpl.java | 7 +- .../balanced/score/core/dex/AbstractDex.java | 27 ------ .../balanced/score/core/dex/DexImpl.java | 9 +- .../core/dex/IRC31StandardSpokeLpToken.java | 11 +-- .../core/dex/DexTestSettersAndGetters.java | 4 - .../score/core/router/RouterImpl.java | 12 +-- .../score/core/router/RouterTest.java | 87 ++----------------- .../score/core/stakedlp/StakedLPImpl.java | 16 ++-- .../score/core/stakedlp/StakedLPTest.java | 4 +- .../score/lib/interfaces/StakedLP.java | 6 +- .../score/lib/interfaces/base/IRC31Base.java | 4 +- .../score/lib/utils/TokenTransfer.java | 12 +-- 12 files changed, 41 insertions(+), 158 deletions(-) diff --git a/core-contracts/DAOfund/src/main/java/network/balanced/score/core/daofund/DAOfundImpl.java b/core-contracts/DAOfund/src/main/java/network/balanced/score/core/daofund/DAOfundImpl.java index 75a4e8aa0..0dcee2480 100644 --- a/core-contracts/DAOfund/src/main/java/network/balanced/score/core/daofund/DAOfundImpl.java +++ b/core-contracts/DAOfund/src/main/java/network/balanced/score/core/daofund/DAOfundImpl.java @@ -272,11 +272,14 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { public void fallback() { } - //todo: verify if this is the solution @External - public void onIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data) { + public void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data) { checkStatus(); } + @External + public void onXIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data) { + checkStatus(); + } } 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 41453d3cc..479e91ad8 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 @@ -109,16 +109,11 @@ public void Withdraw(Address _token, String _owner, BigInteger _value) { public void ClaimSicxEarnings(Address _owner, BigInteger _value) { } - @EventLog(indexed = 3) - public void TransferSingle(String _operator, String _from, String _to, BigInteger _id, BigInteger _value) { - } - @External(readonly = true) public String name() { return TAG; } - @External public void updateAddress(String name) { resetAddress(name); @@ -664,28 +659,6 @@ public void govSetPoolTotal(int pid, BigInteger total) { poolLpTotal.set(pid, total); } - @External - public void govSetUserPoolTotal(int pid, Address user, BigInteger total) { - onlyGovernance(); - NetworkAddress _user = new NetworkAddress(NATIVE_NID, user); - setUserPoolTotal(pid, _user, total); - } - - //todo: make sure if this method is required - @External - public void govSetUserPoolTotalV2(int pid, String user, BigInteger total) { - onlyGovernance(); - setUserPoolTotal(pid, NetworkAddress.parse(user), total); - } - private void setUserPoolTotal(int pid, NetworkAddress _user, BigInteger total){ - BigInteger value = balance.at(pid).get(_user); - BigInteger burned = value.subtract(total); - balance.at(pid).set(_user, total); - - TransferSingle(Context.getCaller().toString(), _user.toString(), MINT_ADDRESS.toString(), BigInteger.valueOf(pid), burned); - } - - void swapIcx(Address sender, BigInteger value) { BigInteger sicxIcxPrice = getSicxRate(); diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index 24d65a4fd..2a5b09628 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -314,8 +314,6 @@ void _remove(BigInteger _id, NetworkAddress _user, BigInteger _value, @Optional if (userQuoteLeft.compareTo(getRewardableAmount(quoteToken)) < 0) { _value = userBalance; - //todo: verify we don't need activeAddresses - //activeAddresses.get(_id.intValue()).remove(_user); } BigInteger baseToWithdraw = _value.multiply(totalBase).divide(totalLPToken); @@ -482,12 +480,7 @@ public void addInternal(NetworkAddress _from, Address _baseToken, Address _quote balance.at(id).set(_from, userLpAmount); poolLpTotal.set(id, poolLpAmount); AddV2(BigInteger.valueOf(id), _from.toString(), liquidity, baseToCommit, quoteToCommit); - //todo: check if this event solves - //TransferSingle(from, MINT_ADDRESS.toString(), from, BigInteger.valueOf(id), liquidity); - HubTransfer(BigInteger.valueOf(id), MINT_ADDRESS.toString(), _from.toString(), liquidity, new byte[0]); - - //todo: fix and uncomment - //activeAddresses.get(id).add(from); + HubTransferSingle(BigInteger.valueOf(id), MINT_ADDRESS.toString(), _from.toString(), liquidity, new byte[0]); if (userDepositedBase.compareTo(BigInteger.ZERO) > 0) { withdraw(_baseToken, userDepositedBase); diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java index 309dc8146..01f19aa18 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java @@ -101,7 +101,7 @@ void _transfer(NetworkAddress _from, NetworkAddress _to, BigInteger _value, Inte byte[] dataBytes = (_data == null) ? "None".getBytes() : _data; - HubTransfer(BigInteger.valueOf(_id), _from.toString(), _to.toString(), _value, dataBytes); + HubTransferSingle(BigInteger.valueOf(_id), _from.toString(), _to.toString(), _value, dataBytes); if (!_to.net().equals(NATIVE_NID)) { return; } @@ -111,7 +111,7 @@ void _transfer(NetworkAddress _from, NetworkAddress _to, BigInteger _value, Inte return; } - Context.call(contractAddress, "onIRC31Received", _from.toString(), _from.toString(), _id, _value, dataBytes); + Context.call(contractAddress, "onXIRC31Received", _from.toString(), _from.toString(), _id, _value, dataBytes); } protected boolean isNative(NetworkAddress address) { @@ -123,9 +123,10 @@ boolean isLockingPool(Integer id) { } @EventLog(indexed = 3) - public void HubTransfer(BigInteger _id, String _from, String _to, BigInteger _value, byte[] _data) { - } + public void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value){} + @EventLog(indexed = 3) - public void Transfer(Address _from, Address _to, BigInteger _value, byte[] _data) { + public void HubTransferSingle(BigInteger _id, String _from, String _to, BigInteger _value, byte[] _data) { } + } diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java index a70648e31..08848b07a 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java @@ -643,10 +643,6 @@ void govSetPoolTotal() { } - @Test - void govSetUserPoolTotal() { - assertOnlyCallableBy(governanceScore.getAddress(), dexScore, "govSetUserPoolTotal", 1, dexScore.getAddress(), BigInteger.ZERO); - } @Test void govSetOracleProtection() { 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 778257abc..c4aaa2bb0 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 @@ -150,12 +150,11 @@ private void route(String from, Address startToken, List _path, Big prevToken = currentToken; currentToken = action.toAddress; } - inRoute = false; + inRoute = false; String nativeNid = XCallUtils.getNativeNid(); NetworkAddress networkAddress = NetworkAddress.valueOf(from, nativeNid); if (currentToken == null && prevToken.equals(getSicx())) { - currentToken = EOA_ZERO; BigInteger balance = Context.getBalance(Context.getAddress()); Context.require(balance.compareTo(_minReceive) >= 0, TAG + ": Below minimum receive amount of " + _minReceive); @@ -165,21 +164,15 @@ private void route(String from, Address startToken, List _path, Big return; } - boolean toNative = currentToken == null; - if (toNative) { - currentToken = prevToken; - } - BigInteger balance = (BigInteger) Context.call(currentToken, "balanceOf", Context.getAddress()); Context.require(balance.compareTo(_minReceive) >= 0, TAG + ": Below minimum receive amount of " + _minReceive); byte[] data = new byte[0]; if(networkAddress.net().equals(nativeNid)){ - Context.require(!toNative, TAG + ": Native swaps not available to icon from " + currentToken); data = EMPTY_DATA; } - TokenTransfer.transfer(currentToken, networkAddress.toString(), balance, toNative, data); + TokenTransfer.transfer(currentToken, networkAddress.toString(), balance, data); Route(fromAddress, fromAmount, currentToken, balance); } @@ -296,6 +289,7 @@ private void jsonRoute(String _from, byte[] data) { Context.require(minimumReceive.signum() >= 0, TAG + ": Must specify a positive number for minimum to " + "receive"); } + String receiver; if (params.contains("receiver")) { receiver = params.get("receiver").asString(); diff --git a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java index c0dddbc77..dd172ab2e 100644 --- a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java +++ b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java @@ -182,14 +182,14 @@ void tokenFallback() throws Exception { when(balanced.baln.mock.balanceOf(routerScore.getAddress())).thenReturn(BigInteger.TEN); when(balanced.sicx.mock.balanceOf(routerScore.getAddress())).thenReturn(BigInteger.TEN); - byte[] invalidPathWithSicxTerminalToken = tokenData("_swap", Map.of("path", - new Object[]{balanced.baln.getAddress().toString(), null})); - Executable nonSicxIcxTrade = () -> routerScore.invoke(sicxScore.account, "tokenFallback", owner.getAddress(), - BigInteger.TEN, invalidPathWithSicxTerminalToken); - expectedErrorMessage = "Reverted(0): " + TAG + ": Native swaps not available to icon from " + balanced.baln.getAddress(); - expectErrorMessage(nonSicxIcxTrade, expectedErrorMessage); - - resetInRoute(); +// byte[] invalidPathWithSicxTerminalToken = tokenData("_swap", Map.of("path", +// new Object[]{balanced.baln.getAddress().toString(), null})); +// Executable nonSicxIcxTrade = () -> routerScore.invoke(sicxScore.account, "tokenFallback", owner.getAddress(), +// BigInteger.TEN, invalidPathWithSicxTerminalToken); +// expectedErrorMessage = "Reverted(0): " + TAG + ": Native swaps not available to icon from " + balanced.baln.getAddress(); +// expectErrorMessage(nonSicxIcxTrade, expectedErrorMessage); +// +// resetInRoute(); Account newReceiver = sm.createAccount(); byte[] pathWithSicxTerminalToken = tokenData("_swap", Map.of("path", new Object[]{sicxScore.getAddress().toString(), null}, "receiver", @@ -271,77 +271,6 @@ void xTrade_ToNetworkAddressWithDifferentNet() throws Exception { verify(token.mock).crossTransfer(receiver.toString(), amount, new byte[0]); } - @Test - void xTradeNative_ToNetworkAddressWithDifferentNet() throws Exception { - // Arrange - MockContract token = new MockContract<>(SpokeTokenScoreInterface.class, SpokeToken.class, sm, - owner); - String net = "0x1.eth"; - String net2 = "0x3.bsc"; - BigInteger fee = BigInteger.TEN; - NetworkAddress receiver = new NetworkAddress(net, "cx1"); - BigInteger amount = BigInteger.TEN.multiply(ICX); - when(balanced.sicx.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); - when(token.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); - when(balanced.daofund.mock.getXCallFeePermission(routerScore.getAddress(), net)).thenReturn(true); - when(balanced.assetManager.mock.getNativeAssetAddress(token.getAddress(), net2)) - .thenReturn(new NetworkAddress(net2, "cx3").toString()); - - // Act & Assert - byte[] path = tokenData("_swap", Map.of("path", - new Object[]{token.getAddress().toString(), null}, "receiver", receiver.toString())); - Executable nativeToWrongNet = () -> routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); - String expectedErrorMessage = "Reverted(0): Native swaps are not supported for this network"; - expectErrorMessage(nativeToWrongNet, expectedErrorMessage); - } - - @Test - void xTradeNative_cannotWithdraw() throws Exception { - // Arrange - MockContract token = new MockContract<>(SpokeTokenScoreInterface.class, SpokeToken.class, sm, - owner); - String net = "0x1.eth"; - BigInteger fee = BigInteger.TEN; - NetworkAddress receiver = new NetworkAddress(net, "cx1"); - BigInteger amount = BigInteger.TEN.multiply(ICX); - when(balanced.sicx.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); - when(token.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); - when(balanced.daofund.mock.getXCallFeePermission(routerScore.getAddress(), net)).thenReturn(false); - when(balanced.assetManager.mock.getNativeAssetAddress(token.getAddress(), net)) - .thenReturn(new NetworkAddress(net, "cx3").toString()); - - // Act & Assert - byte[] path = tokenData("_swap", Map.of("path", - new Object[]{token.getAddress().toString(), null}, "receiver", receiver.toString())); - Executable nativeToWrongNet = () -> routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); - String expectedErrorMessage = "Reverted(0): Native swaps are not supported for this network"; - expectErrorMessage(nativeToWrongNet, expectedErrorMessage); - } - - @Test - void xTrade_toNative() throws Exception { - // Arrange - MockContract token = new MockContract<>(SpokeTokenScoreInterface.class, SpokeToken.class, sm, - owner); - String net = "0x1.eth"; - BigInteger fee = BigInteger.TEN; - NetworkAddress receiver = new NetworkAddress(net, "cx1"); - BigInteger amount = BigInteger.TEN.multiply(ICX); - when(balanced.sicx.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); - when(token.mock.balanceOf(routerScore.getAddress())).thenReturn(amount); - when(balanced.daofund.mock.getXCallFeePermission(routerScore.getAddress(), net)).thenReturn(true); - when(balanced.assetManager.mock.getNativeAssetAddress(token.getAddress(), net)) - .thenReturn(new NetworkAddress(net, "cx3").toString()); - - // Act - byte[] path = tokenData("_swap", Map.of("path", - new Object[]{token.getAddress().toString(), null}, "receiver", receiver.toString())); - routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); - - // Assert - verify(balanced.assetManager.mock).withdrawNativeTo(token.getAddress(), receiver.toString(), amount); - } - @Test void xTrade_ToBnUSD() throws Exception { // Arrange diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index 1a46e845b..06e539048 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -189,20 +189,20 @@ private void unstake(BigInteger id, NetworkAddress user, BigInteger value){ } @External - public void onIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data) { + public void onXIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data) { only(dex); Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); NetworkAddress from = NetworkAddress.valueOf(_from); this.stake(from, _id, _value); } -// @External -// public void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data) { -// only(dex); -// Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); -// NetworkAddress from = NetworkAddress.valueOf(_from.toString(), NATIVE_NID); -// this.stake(from, _id, _value); -// } + @External + public void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data) { + only(dex); + Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); + NetworkAddress from = NetworkAddress.valueOf(_from.toString(), NATIVE_NID); + this.stake(from, _id, _value); + } @External public void addDataSource(BigInteger id, String name) { diff --git a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java index 6b7ec783d..7d8fe52e3 100644 --- a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java +++ b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java @@ -147,12 +147,12 @@ void setAndGetRewards() { private void stakeLpTokens(Account from, BigInteger poolId, BigInteger value) { String fromNetworkAddress = NetworkAddress.valueOf(from.getAddress().toString(), NATIVE_NID).toString(); - stakedLpScore.invoke(dex.account, "onIRC31Received", fromNetworkAddress, fromNetworkAddress, poolId, value, + stakedLpScore.invoke(dex.account, "onXIRC31Received", fromNetworkAddress, fromNetworkAddress, poolId, value, new byte[0]); } private void stakeLpTokens(String from, BigInteger poolId, BigInteger value) { - stakedLpScore.invoke(dex.account, "onIRC31Received", from, from, poolId, value, + stakedLpScore.invoke(dex.account, "onXIRC31Received", from, from, poolId, value, new byte[0]); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java index 2dff64f01..2abf8abe3 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/StakedLP.java @@ -67,11 +67,11 @@ public interface StakedLP extends Version { @XCall void xUnstake(String from, BigInteger id, BigInteger value); -// @External -// void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data); + @External + void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data); @External - void onIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data); + void onXIRC31Received(String _operator, String _from, BigInteger _id, BigInteger _value, byte[] _data); @External void addDataSource(BigInteger id, String name); diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/base/IRC31Base.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/base/IRC31Base.java index 8f2df4646..3a7dac5e2 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/base/IRC31Base.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/base/IRC31Base.java @@ -27,6 +27,6 @@ public interface IRC31Base { @External(readonly = true) BigInteger balanceOf(Address _owner, BigInteger _id); -// @EventLog(indexed = 3) -// void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value); + @EventLog(indexed = 3) + void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java b/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java index 90300f359..09561e198 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java @@ -10,7 +10,7 @@ public class TokenTransfer { - public static void transfer(Address token, String to, BigInteger amount, boolean toNative, byte[] data){ + public static void transfer(Address token, String to, BigInteger amount, byte[] data){ NetworkAddress toNetworkAddress = NetworkAddress.parse(to); String NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); if(!NATIVE_NID.equals(toNetworkAddress.net())) { @@ -18,17 +18,11 @@ public static void transfer(Address token, String to, BigInteger amount, boolean String nativeAddress = (String) Context.call(BalancedAddressManager.getAssetManager(), "getNativeAssetAddress", token, toNetworkAddress.net()); BigInteger xCallFee = (BigInteger) Context.call(BalancedAddressManager.getDaofund(), "claimXCallFee", toNetworkAddress.net(), false); if (nativeAddress == null) { - Context.require(!toNative, "Native swaps are not supported for this network"); Context.call(xCallFee, token, "crossTransfer", to, amount, data); } else { - if (toNative) { - Context.call(xCallFee, BalancedAddressManager.getAssetManager(), "withdrawNativeTo", token, to, amount); - } else { - Context.call(xCallFee, BalancedAddressManager.getAssetManager(), "withdrawTo", token, to, amount); - } + Context.call(xCallFee, BalancedAddressManager.getAssetManager(), "withdrawTo", token, to, amount); } }else{ - Context.require(!toNative, "Native swaps are not supported for this network"); Context.call(token, "hubTransfer", toNetworkAddress.toString(), amount, data); } }else{ @@ -37,7 +31,7 @@ public static void transfer(Address token, String to, BigInteger amount, boolean } public static void transfer(Address token, String to, BigInteger amount){ - transfer(token, to, amount, false, new byte[0]); + transfer(token, to, amount, new byte[0]); } private static boolean canWithdraw(String net) { From dbcb461f17c23fea827f45b19fd6850372caa69a Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 30 Oct 2024 16:06:41 +0545 Subject: [PATCH 07/31] Fix: review additional fixes, cleanups, formats --- .../score/core/dex/DexIntegrationTest.java | 3 +- .../balanced/score/core/dex/AbstractDex.java | 2 +- .../score/core/dex/DexDBVariables.java | 1 - .../balanced/score/core/dex/DexImpl.java | 34 +++++++++---------- .../core/dex/IRC31StandardSpokeLpToken.java | 6 ++-- .../core/dex/DexTestSettersAndGetters.java | 17 ---------- .../score/core/rewards/DataSourceImpl.java | 12 +++---- .../score/core/rewards/RewardsImpl.java | 14 ++++---- .../rewards/RewardsTestExternalRewards.java | 1 - .../score/core/router/RouterImpl.java | 2 +- .../score/core/stakedlp/StakedLPImpl.java | 4 --- .../lib/interfaces/tokens/XReceiver.java | 19 ----------- .../score/lib/tokens/HubTokenImpl.java | 1 - .../balanced/score/lib/utils/Versions.java | 10 +++--- .../score/util/mock/xcall/XCallMockImpl.java | 1 - 15 files changed, 43 insertions(+), 84 deletions(-) delete mode 100644 score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/XReceiver.java diff --git a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java index 6530742a4..6084f5630 100644 --- a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java +++ b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java @@ -295,8 +295,7 @@ void testNonContinuousAndContinuousReward() { BigInteger nextUpdatedBalnHolding = userRewardScoreClient.getBalnHolding(tUserAddress.toString()); assertEquals(beforeSleepDay, dexUserScoreClient.getDay()); - System.out.println("updated baln holding: " + updatedBalnHolding); - System.out.println("next updated baln holding: " + nextUpdatedBalnHolding); + assert updatedBalnHolding.compareTo(nextUpdatedBalnHolding) < 0; } 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 479e91ad8..2f5ee1ac7 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 @@ -263,7 +263,7 @@ public boolean precompute(BigInteger snap, BigInteger batch_size) { @External(readonly = true) public BigInteger getDeposit(Address _tokenAddress, Address _user) { - NetworkAddress user = new NetworkAddress(NATIVE_NID, _user); + NetworkAddress user = new NetworkAddress(NATIVE_NID, _user); return deposit.at(_tokenAddress).getOrDefault(user, BigInteger.ZERO); } 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 f0c1d8265..b33080391 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 @@ -18,7 +18,6 @@ import network.balanced.score.core.dex.db.LinkedListDB; import network.balanced.score.core.dex.utils.LPMetadataDB; -import network.balanced.score.lib.utils.BranchedAddressDictDB; import network.balanced.score.lib.utils.BranchedNetworkAddressDictDB; import network.balanced.score.lib.utils.IterableDictDB; import network.balanced.score.lib.utils.SetDB; diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index 2a5b09628..b5007783a 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -64,7 +64,7 @@ public String version() { @Payable public void fallback() { Address user = Context.getCaller(); - if(user.equals(BalancedAddressManager.getDaofund())){ + if (user.equals(BalancedAddressManager.getDaofund())) { return; } isDexOn(); @@ -139,7 +139,7 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { require(!unpackedData.equals(""), "Token Fallback: Data can't be empty"); JsonObject json = Json.parse(unpackedData).asObject(); String method = json.get("method").asString(); - Address fromToken = Context.getCaller(); + Address fromToken = Context.getCaller(); require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Invalid token transfer value"); @@ -173,13 +173,13 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { JsonObject json = Json.parse(unpackedData).asObject(); String method = json.get("method").asString(); - Address fromToken = Context.getCaller(); + Address fromToken = Context.getCaller(); require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Invalid token transfer value"); // Call an internal method based on the "method" param sent in tokenFallBack switch (method) { case "_deposit": { - NetworkAddress from = new NetworkAddress(NATIVE_NID, _from); + NetworkAddress from = new NetworkAddress(NATIVE_NID, _from); deposit(fromToken, from, _value); break; } @@ -238,24 +238,24 @@ public void transfer(Address _to, BigInteger _value, BigInteger _id, @Optional b if (_data == null) { _data = new byte[0]; } - NetworkAddress from = new NetworkAddress(NATIVE_NID, Context.getCaller()); - NetworkAddress to = new NetworkAddress(NATIVE_NID, _to); - _transfer( from, to, _value, _id.intValue(), _data); + NetworkAddress from = new NetworkAddress(NATIVE_NID, Context.getCaller()); + NetworkAddress to = new NetworkAddress(NATIVE_NID, _to); + _transfer(from, to, _value, _id.intValue(), _data); } public void xWithdraw(String from, Address _token, BigInteger _value) { - NetworkAddress sender = NetworkAddress.valueOf(from); + NetworkAddress sender = NetworkAddress.valueOf(from); _withdraw(sender, _token, _value); } @External public void withdraw(Address _token, BigInteger _value) { Address caller = Context.getCaller(); - NetworkAddress sender = new NetworkAddress(NATIVE_NID, caller); + NetworkAddress sender = new NetworkAddress(NATIVE_NID, caller); _withdraw(sender, _token, _value); } - private void _withdraw(NetworkAddress sender, Address _token, BigInteger _value){ + private void _withdraw(NetworkAddress sender, Address _token, BigInteger _value) { isDexOn(); checkStatus(); require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Must specify a positive amount"); @@ -275,7 +275,7 @@ private void _withdraw(NetworkAddress sender, Address _token, BigInteger _value) @External(readonly = true) public BigInteger depositOfUser(Address _owner, Address _token) { - NetworkAddress owner = new NetworkAddress(NATIVE_NID, _owner); + NetworkAddress owner = new NetworkAddress(NATIVE_NID, _owner); NetworkAddressDictDB depositDetails = deposit.at(_token); return depositDetails.getOrDefault(owner, BigInteger.ZERO); } @@ -287,7 +287,7 @@ public void xRemove(String from, BigInteger id, BigInteger value, @Optional Bool @External public void remove(BigInteger _id, BigInteger _value, @Optional boolean _withdraw) { - NetworkAddress owner = new NetworkAddress(NATIVE_NID, Context.getCaller()); + NetworkAddress owner = new NetworkAddress(NATIVE_NID, Context.getCaller()); _remove(_id, owner, _value, _withdraw); } @@ -351,17 +351,17 @@ void _remove(BigInteger _id, NetworkAddress _user, BigInteger _value, @Optional } public void xAdd(String from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, - @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage) { + @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage) { isDexOn(); checkStatus(); isValidPercent(_slippagePercentage.intValue()); - addInternal(NetworkAddress.parse(from), _baseToken, _quoteToken, _baseValue, _quoteValue, + addInternal(NetworkAddress.parse(from), _baseToken, _quoteToken, _baseValue, _quoteValue, _withdraw_unused, _slippagePercentage); } public void addInternal(NetworkAddress _from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, - @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage){ + @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage) { // We check if there is a previously seen pool with this id. // If none is found (return 0), we create a new pool. Integer id = poolId.at(_baseToken).getOrDefault(_quoteToken, 0); @@ -499,8 +499,8 @@ public void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, checkStatus(); isValidPercent(_slippagePercentage.intValue()); - NetworkAddress user = new NetworkAddress(NATIVE_NID, Context.getCaller()); - addInternal(user, _baseToken, _quoteToken, _baseValue, _quoteValue, + NetworkAddress user = new NetworkAddress(NATIVE_NID, Context.getCaller()); + addInternal(user, _baseToken, _quoteToken, _baseValue, _quoteValue, _withdraw_unused, _slippagePercentage); } diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java index 01f19aa18..5e3740326 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java @@ -12,6 +12,7 @@ import java.math.BigInteger; import foundation.icon.xcall.NetworkAddress; + import static network.balanced.score.core.dex.DexDBVariables.*; import static network.balanced.score.core.dex.DexDBVariables.poolLpTotal; import static network.balanced.score.core.dex.utils.Const.SICXICX_POOL_ID; @@ -26,7 +27,7 @@ public BigInteger balanceOf(Address _owner, BigInteger _id) { if (_id.intValue() == SICXICX_POOL_ID) { return getICXBalance(_owner); } else { - NetworkAddress owner = new NetworkAddress(NATIVE_NID, _owner); + NetworkAddress owner = new NetworkAddress(NATIVE_NID, _owner); return DexDBVariables.balance.at(_id.intValue()).getOrDefault(owner, BigInteger.ZERO); } } @@ -123,7 +124,8 @@ boolean isLockingPool(Integer id) { } @EventLog(indexed = 3) - public void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value){} + public void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value) { + } @EventLog(indexed = 3) public void HubTransferSingle(BigInteger _id, String _from, String _to, BigInteger _value, byte[] _data) { diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java index 08848b07a..49443857f 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java @@ -605,23 +605,6 @@ void getPoolStats_notSicxIcxPool() { assertEquals(expectedPoolStats, poolStats); } - //todo: verify and -// @Test -// void getTotalDexAddresses() { -// // Arrange. -// BigInteger bnusdValue = BigInteger.valueOf(195).multiply(EXA); -// BigInteger balnValue = BigInteger.valueOf(350).multiply(EXA); -// BigInteger poolId = BigInteger.TWO; -// -// // Act. -// supplyLiquidity(governanceScore, bnusdScore, balnScore, bnusdValue, balnValue, false); -// supplyLiquidity(ownerAccount, bnusdScore, balnScore, bnusdValue, balnValue, false); -// -// // Assert -// BigInteger totalDexAddresses = (BigInteger) dexScore.call("totalDexAddresses", BigInteger.TWO); -// assertEquals(BigInteger.TWO, totalDexAddresses); -// } - @Test void permit_OnlyGovernance() { // Arrange. diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/DataSourceImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/DataSourceImpl.java index 6d4c15ea1..b74d80ef4 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/DataSourceImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/DataSourceImpl.java @@ -43,7 +43,7 @@ public class DataSourceImpl { private final BranchedAddressDictDB userWeight = new BranchedAddressDictDB<>("user_weight", BigInteger.class); private final BranchedAddressDictDB userWorkingBalance = new BranchedAddressDictDB<>( - "user_working_balance", BigInteger.class); + "user_working_balance", BigInteger.class); private final BranchDB> lastUpdateTimeUs = Context.newBranchDB("last_update_us", BigInteger.class); private final BranchDB> totalWeight = Context.newBranchDB("running_total", @@ -276,7 +276,7 @@ public Map updateSingleUserData(BigInteger currentTime, Bal Address[] externalRewards = getRewardTokens(); Address baln = BalancedAddressManager.getBaln(); Map totalWeight = updateTotalWeight(lastUpdateTimestamp, currentTime, balances, externalRewards, readOnlyContext); - Map accruedRewards = new HashMap<>(externalRewards.length+1); + Map accruedRewards = new HashMap<>(externalRewards.length + 1); accruedRewards.put(baln, BigInteger.ZERO); // If the user's current weight is less than the total, update their weight and issue rewards @@ -348,9 +348,9 @@ private BigInteger computeTotalWeight(BigInteger previousTotalWeight, } private Map updateTotalWeight(BigInteger lastUpdateTimestamp, BigInteger currentTime, - BalanceData balances, Address[] externalRewards, boolean readOnlyContext) { + BalanceData balances, Address[] externalRewards, boolean readOnlyContext) { Address baln = BalancedAddressManager.getBaln(); - Map externalTotals = new HashMap<>(externalRewards.length+1); + Map externalTotals = new HashMap<>(externalRewards.length + 1); externalTotals.put(baln, getTotalWeight()); for (Address token : externalRewards) { externalTotals.put(token, externalTotalWeights.at(dbKey).getOrDefault(token, BigInteger.ZERO)); @@ -378,7 +378,7 @@ private Map updateTotalWeight(BigInteger lastUpdateTimestam BigInteger emission = getTotalDist(previousRewardsDay, readOnlyContext); externalTotals.put(baln, computeTotalWeight(externalTotals.get(baln), emission, balances.prevWorkingSupply, lastUpdateTimestamp, - endComputeTimestampUs)); + endComputeTimestampUs)); for (Address token : externalRewards) { BigInteger externalEmission = getTotalExternalDist(previousRewardsDay, token); if (externalEmission.equals(BigInteger.ZERO)) { @@ -437,7 +437,7 @@ public Map getUserData(String user) { data.put("working balance", getWorkingBalance(user, true)); for (Address addr : externalRewards) { - data.put(addr.toString() + "_weight", getExternalUserWeight(user,addr)); + data.put(addr.toString() + "_weight", getExternalUserWeight(user, addr)); } return data; } diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java index 003112218..0056fd6f3 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java @@ -358,7 +358,7 @@ private boolean mintAndAllocateBalnReward(BigInteger platformDay) { for (String recipient : recipients) { BigInteger split = distributionPercentages.get(recipient); BigInteger share = split.multiply(remaining).divide(shares); - Context.call(getBaln(), "transfer", BalancedAddressManager.getAddress(recipient) , share, new byte[0]); + Context.call(getBaln(), "transfer", BalancedAddressManager.getAddress(recipient), share, new byte[0]); remaining = remaining.subtract(share); shares = shares.subtract(split); } @@ -397,7 +397,7 @@ public void handleCallMessage(String _from, byte[] _data, @Optional String[] _pr } public void xClaimRewards(String from, @Optional String to, @Optional String[] sources) { - if (to.isEmpty()){ + if (to.isEmpty()) { to = from; } _claimRewards(to, sources); @@ -406,13 +406,13 @@ public void xClaimRewards(String from, @Optional String to, @Optional String[] s @External public void claimRewards(@Optional String[] sources) { checkStatus(); - if (sources == null || sources.length==0) { + if (sources == null || sources.length == 0) { sources = getAllSources(); } _claimRewards(Context.getCaller().toString(), sources); } - private void _claimRewards(String address, String[] sources){ + private void _claimRewards(String address, String[] sources) { NetworkAddress networkAddress = NetworkAddress.valueOf(address, NATIVE_NID); BigInteger boostedBalance = fetchBoostedBalance(address); BigInteger boostedSupply = fetchBoostedSupply(); @@ -439,6 +439,7 @@ private void _claimRewards(String address, String[] sources){ } } + @External public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { checkStatus(); @@ -1036,9 +1037,10 @@ private static BigInteger dailyDistribution(BigInteger day) { private BigInteger fetchBoostedBalance(String user) { NetworkAddress networkAddress = NetworkAddress.valueOf(user, NATIVE_NID); Address address = null; - try{ + try { address = Address.fromString(user); - } catch (Exception ignored){} + } catch (Exception ignored) { + } if (!networkAddress.net().equals(NATIVE_NID) || address == null) { return BigInteger.ZERO; } diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java index ec1dc7fa0..ec2cac320 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java @@ -378,7 +378,6 @@ void externalRewards_crosschain() { rewardsScore.invoke(mockBalanced.xCall.account, "handleCallMessage", fromNetworkAddress, getClaimRewardData(fromNetworkAddress, sources), protocols); - //todo: calculate the expected value and replace the hard coded value verify(rewardsScoreSpy).RewardsClaimedV2(mockBalanced.sicx.account.getAddress(), fromNetworkAddress, new BigInteger("350000000000000000000")); verify(rewardsScoreSpy).RewardsClaimedV2(mockBalanced.baln.account.getAddress(), fromNetworkAddress, new BigInteger("8997986111111111111108")); } 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 c4aaa2bb0..a653f04c0 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 @@ -168,7 +168,7 @@ private void route(String from, Address startToken, List _path, Big Context.require(balance.compareTo(_minReceive) >= 0, TAG + ": Below minimum receive amount of " + _minReceive); byte[] data = new byte[0]; - if(networkAddress.net().equals(nativeNid)){ + if (networkAddress.net().equals(nativeNid)) { data = EMPTY_DATA; } diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index 06e539048..3ff135a7a 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -35,10 +35,6 @@ public class StakedLPImpl implements StakedLP { - //todo: verify this migration works -// private static final BranchDB> poolStakedDetails = -// Context.newBranchDB("poolStakeDetails", BigInteger.class); - final static AddressBranchDictDB poolStakedDetails = new AddressBranchDictDB<>("poolStakeDetails", BigInteger.class); diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/XReceiver.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/XReceiver.java deleted file mode 100644 index 113994ebb..000000000 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/tokens/XReceiver.java +++ /dev/null @@ -1,19 +0,0 @@ -/* -package network.balanced.score.lib.interfaces.tokens; - -import foundation.icon.score.client.ScoreInterface; -import network.balanced.score.lib.annotations.XCall; -import score.Address; -import score.annotation.Optional; - -import java.math.BigInteger; - -@ScoreInterface -public interface XReceiver { - - @XCall - void xAdd(String from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, - @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage); - -} -*/ 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 070d769c2..0da49765b 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 @@ -210,7 +210,6 @@ public void _transferToSpoke(BigInteger fee, NetworkAddress from, NetworkAddress public void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) { checkStatus(); only(BalancedAddressManager.getXCall()); - Context.println(_from); XCallUtils.verifyXCallProtocols(_from, _protocols); HubTokenXCall.process(this, _from, _data); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java index 8340eba95..e85f0d240 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java @@ -26,15 +26,15 @@ public class Versions { public final static String WORKERTOKEN = "v1.0.0"; public final static String BNUSD = "v1.1.1"; public final static String FEEHANDLER = "v1.0.1"; - public final static String REWARDS = "v1.2.0"; + public final static String REWARDS = "v1.2.1"; public final static String STABILITY = "v1.1.1"; public final static String BALANCEDORACLE = "v1.2.0"; - public final static String DAOFUND = "v1.1.1"; - public final static String DEX = "v1.1.1"; + public final static String DAOFUND = "v1.1.2"; + public final static String DEX = "v1.1.2"; public final static String GOVERNANCE = "v1.0.2"; public final static String REBALANCING = "v1.0.0"; - public final static String ROUTER = "v1.1.5"; - public final static String STAKEDLP = "v1.0.1"; + public final static String ROUTER = "v1.1.6"; + public final static String STAKEDLP = "v1.0.2"; public final static String BOOSTED_BALN = "v1.1.0"; public final static String BRIBING = "v1.0.1"; public final static String BALANCED_OTC = "v1.0.0"; diff --git a/util-contracts/XCallMock/src/main/java/network/balanced/score/util/mock/xcall/XCallMockImpl.java b/util-contracts/XCallMock/src/main/java/network/balanced/score/util/mock/xcall/XCallMockImpl.java index 3e59f12a1..f2ac0365e 100644 --- a/util-contracts/XCallMock/src/main/java/network/balanced/score/util/mock/xcall/XCallMockImpl.java +++ b/util-contracts/XCallMock/src/main/java/network/balanced/score/util/mock/xcall/XCallMockImpl.java @@ -82,7 +82,6 @@ public BigInteger sendCall(String _to, byte[] _data) { @External public void recvCall(Address to, String from, byte[] message) { - Context.println(to.toString()); Context.call(to, "handleCallMessage", from, message); } From 1b20143f435ab4312ed6f6b28916d08142d7ebf5 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 6 Nov 2024 13:14:47 +0545 Subject: [PATCH 08/31] to param optional on xTokenFallback deposit, xWithdraw replaced with withdraw --- .../java/network/balanced/score/core/dex/DexImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index b5007783a..f3f05350c 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -145,7 +145,10 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { if (method.equals("_deposit")) { JsonObject params = json.get("params").asObject(); - String to = params.get("address").asString(); + String to = _from; + if(params.get("address")!=null){ + to = params.get("address").asString(); + } deposit(fromToken, NetworkAddress.valueOf(to), _value); } else { // If no supported method was sent, revert the transaction @@ -483,11 +486,11 @@ public void addInternal(NetworkAddress _from, Address _baseToken, Address _quote HubTransferSingle(BigInteger.valueOf(id), MINT_ADDRESS.toString(), _from.toString(), liquidity, new byte[0]); if (userDepositedBase.compareTo(BigInteger.ZERO) > 0) { - withdraw(_baseToken, userDepositedBase); + xWithdraw(_from.toString(), _baseToken, userDepositedBase); } if (userDepositedQuote.compareTo(BigInteger.ZERO) > 0) { - withdraw(_quoteToken, userDepositedQuote); + xWithdraw(_from.toString(), _quoteToken, userDepositedQuote); } } From fd54215750814a85dc33b3af5dab9cfd17c2415a Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 7 Nov 2024 16:00:55 +0545 Subject: [PATCH 09/31] unit tests for optional to in xTokenFallback and xWithdraw on xAdd --- .../balanced/score/core/dex/DexTestBase.java | 5 +++ .../balanced/score/core/dex/DexTestCore.java | 39 ++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java index 90c61905f..9a4e5850d 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java @@ -108,6 +108,11 @@ protected void xDepositToken(String depositor, String to, Account tokenScore, Bi Map.of("address", to))); } + protected void xDepositTokenWithoutTo(String depositor, String to, Account tokenScore, BigInteger value) { + contextMock.when(() -> Context.call(any(Address.class), eq("decimals"))).thenReturn(BigInteger.valueOf(18)); + dexScore.invoke(tokenScore, "xTokenFallback", depositor, value, tokenData("_deposit", Map.of())); + } + /* * String _from, byte[] _data, @Optional String[] _protocols * */ diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java index 44479408d..83f04aa8a 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java @@ -41,6 +41,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; public class DexTestCore extends DexTestBase { @@ -114,8 +115,18 @@ void cancelSicxIcxOrder() { @Test void crossChainDeposit() { String fromNetworkAddress = "0x1.ETH/0x123"; + String toNetworkAddress = "0x1.ETH/0x124"; BigInteger depositValue = BigInteger.valueOf(100).multiply(EXA); - xDepositToken(fromNetworkAddress, fromNetworkAddress, bnusdScore, depositValue); + xDepositToken(fromNetworkAddress, toNetworkAddress, bnusdScore, depositValue); + BigInteger retrievedValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), toNetworkAddress); + assertEquals(depositValue, retrievedValue); + } + + @Test + void crossChainDepositWithNoToAddress() { + String fromNetworkAddress = "0x1.ETH/0x123"; + BigInteger depositValue = BigInteger.valueOf(100).multiply(EXA); + xDepositTokenWithoutTo(fromNetworkAddress, null, bnusdScore, depositValue); BigInteger retrievedValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); assertEquals(depositValue, retrievedValue); } @@ -145,6 +156,32 @@ void crossChainLP(){ } + @Test + void crossChainLPWithWithdraw(){ + // Arrange + String fromNetworkAddress = "0x1.ETH/0x123"; + BigInteger depositValue = BigInteger.valueOf(200).multiply(EXA); + BigInteger addValue = depositValue.divide(BigInteger.TWO); + xDepositToken(fromNetworkAddress, fromNetworkAddress, bnusdScore, depositValue); + BigInteger retrievedValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); + assertEquals(depositValue, retrievedValue); + + xDepositToken(fromNetworkAddress, fromNetworkAddress, sicxScore, depositValue); + BigInteger sicxValue = (BigInteger) dexScore.call("getDepositV2", bnusdScore.getAddress(), fromNetworkAddress); + assertEquals(depositValue, sicxValue); + + // Act - create pool + String[] protocols = new String[0]; + byte[] data = getAddLPData(bnusdScore.getAddress(), sicxScore.getAddress(), addValue, addValue, false, BigInteger.ZERO); + contextMock.when(() -> Context.call(any(Address.class), eq("getXCallFeePermission"), any(Address.class), any(String.class))).thenReturn(true); + contextMock.when(() -> Context.call(any(Address.class), eq("getNativeAssetAddress"), any(Address.class), any(String.class))).thenReturn(null); + contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); + contextMock.when(() -> Context.call(any(BigInteger.class), any(Address.class), eq("crossTransfer"), any(String.class), any(BigInteger.class), any(byte[].class))).thenReturn(null); + handleCallMessageWithOutProtocols(fromNetworkAddress, data, protocols); + + contextMock.verify(() -> Context.call(any(BigInteger.class), any(Address.class), eq("crossTransfer"), any(String.class), any(BigInteger.class), any(byte[].class)), times(2)); + } + @Test void xRemoveNotWithdraw(){ // Arrange From 73adf703b590f1a15d772c07ae45c92217a95132 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 15 Nov 2024 11:56:28 +0545 Subject: [PATCH 10/31] fix: Address type changed to String type on xcall annotated methods --- .gitignore | 2 ++ .../score/core/dex/DexIntegrationTest.java | 4 ++-- .../balanced/score/core/dex/DexImpl.java | 16 +++++++-------- .../balanced/score/core/dex/DexTestCore.java | 20 ++++++++++++++----- .../core/rewards/RewardsIntegrationTest.java | 4 ++-- .../stakedlp/StakedlpIntegrationTest.java | 4 ++-- .../score/core/stakedlp/StakedLPImpl.java | 4 ++++ .../balanced/score/lib/interfaces/Dex.java | 4 ++-- .../balanced/score/lib/utils/Versions.java | 12 +++++------ 9 files changed, 43 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index e387d66a1..556e075fe 100644 --- a/.gitignore +++ b/.gitignore @@ -100,3 +100,5 @@ gradle.properties */bin/ /bin/ bin/ + +crosschainlp.md \ No newline at end of file diff --git a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java index 6084f5630..7cc52dbce 100644 --- a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java +++ b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java @@ -382,7 +382,7 @@ void crossChainLP() { dexAddQuoteCoin((Address) quoteAssetAddress); // Act - byte[] xaddMessage = getAddLPData(baseAssetAddress, quoteAssetAddress, amount, amount, false, BigInteger.valueOf(5) ); + byte[] xaddMessage = getAddLPData(baseAssetAddress.toString(), quoteAssetAddress.toString(), amount, amount, false, BigInteger.valueOf(5) ); owner.xcall.recvCall(dexScoreClient._address(), ethAccount.toString(), xaddMessage); // Verify @@ -467,7 +467,7 @@ static byte[] getStakeData(BigInteger poolId, BigInteger amount, String to, byte return writer.toByteArray(); } - static byte[] getAddLPData(score.Address baseToken, score.Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { + static byte[] getAddLPData(String baseToken, String quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); writer.beginList(7); writer.write("xadd"); diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index f3f05350c..e895ca33a 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -246,9 +246,9 @@ public void transfer(Address _to, BigInteger _value, BigInteger _id, @Optional b _transfer(from, to, _value, _id.intValue(), _data); } - public void xWithdraw(String from, Address _token, BigInteger _value) { + public void xWithdraw(String from, String _token, BigInteger _value) { NetworkAddress sender = NetworkAddress.valueOf(from); - _withdraw(sender, _token, _value); + _withdraw(sender, Address.fromString(_token), _value); } @External @@ -347,19 +347,19 @@ void _remove(BigInteger _id, NetworkAddress _user, BigInteger _value, @Optional userQuoteDeposit.set(_user, depositedQuote.add(quoteToWithdraw)); if (_withdraw) { - xWithdraw(_user.toString(), baseToken, baseToWithdraw); - xWithdraw(_user.toString(), quoteToken, quoteToWithdraw); + xWithdraw(_user.toString(), baseToken.toString(), baseToWithdraw); + xWithdraw(_user.toString(), quoteToken.toString(), quoteToWithdraw); } } - public void xAdd(String from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, + public void xAdd(String from, String _baseToken, String _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage) { isDexOn(); checkStatus(); isValidPercent(_slippagePercentage.intValue()); - addInternal(NetworkAddress.parse(from), _baseToken, _quoteToken, _baseValue, _quoteValue, + addInternal(NetworkAddress.parse(from), Address.fromString(_baseToken), Address.fromString(_quoteToken), _baseValue, _quoteValue, _withdraw_unused, _slippagePercentage); } @@ -486,11 +486,11 @@ public void addInternal(NetworkAddress _from, Address _baseToken, Address _quote HubTransferSingle(BigInteger.valueOf(id), MINT_ADDRESS.toString(), _from.toString(), liquidity, new byte[0]); if (userDepositedBase.compareTo(BigInteger.ZERO) > 0) { - xWithdraw(_from.toString(), _baseToken, userDepositedBase); + xWithdraw(_from.toString(), _baseToken.toString(), userDepositedBase); } if (userDepositedQuote.compareTo(BigInteger.ZERO) > 0) { - xWithdraw(_from.toString(), _quoteToken, userDepositedQuote); + xWithdraw(_from.toString(), _quoteToken.toString(), userDepositedQuote); } } diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java index 83f04aa8a..8454cea6b 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java @@ -146,7 +146,7 @@ void crossChainLP(){ // Act String[] protocols = new String[0]; - byte[] data = getAddLPData(bnusdScore.getAddress(), sicxScore.getAddress(), depositValue, depositValue, false, BigInteger.ZERO); + byte[] data = getAddLPData(bnusdScore.getAddress().toString(), sicxScore.getAddress().toString(), depositValue, depositValue, false, BigInteger.ZERO); handleCallMessageWithOutProtocols(fromNetworkAddress, data, protocols); // Assert @@ -156,6 +156,16 @@ void crossChainLP(){ } + public static byte[] hexStringToByteArray(String hex) { + int length = hex.length(); + byte[] data = new byte[length / 2]; + for (int i = 0; i < length; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + + Character.digit(hex.charAt(i+1), 16)); + } + return data; + } + @Test void crossChainLPWithWithdraw(){ // Arrange @@ -172,7 +182,7 @@ void crossChainLPWithWithdraw(){ // Act - create pool String[] protocols = new String[0]; - byte[] data = getAddLPData(bnusdScore.getAddress(), sicxScore.getAddress(), addValue, addValue, false, BigInteger.ZERO); + byte[] data = getAddLPData(bnusdScore.getAddress().toString(), sicxScore.getAddress().toString(), addValue, addValue, false, BigInteger.ZERO); contextMock.when(() -> Context.call(any(Address.class), eq("getXCallFeePermission"), any(Address.class), any(String.class))).thenReturn(true); contextMock.when(() -> Context.call(any(Address.class), eq("getNativeAssetAddress"), any(Address.class), any(String.class))).thenReturn(null); contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); @@ -196,7 +206,7 @@ void xRemoveNotWithdraw(){ assertEquals(depositValue, sicxValue); String[] protocols = new String[0]; - byte[] data = getAddLPData(bnusdScore.getAddress(), sicxScore.getAddress(), depositValue, depositValue, false, BigInteger.ZERO); + byte[] data = getAddLPData(bnusdScore.getAddress().toString(), sicxScore.getAddress().toString(), depositValue, depositValue, false, BigInteger.ZERO); handleCallMessageWithOutProtocols(fromNetworkAddress, data, protocols); BigInteger poolId = (BigInteger) dexScore.call("getPoolId", bnusdScore.getAddress(), sicxScore.getAddress()); @@ -233,7 +243,7 @@ void xRemoveAndWithdraw(){ // Arrange supply liquidity String[] protocols = new String[0]; - byte[] data = getAddLPData(bnusdScore.getAddress(), sicxScore.getAddress(), depositValue, depositValue, false, BigInteger.ZERO); + byte[] data = getAddLPData(bnusdScore.getAddress().toString(), sicxScore.getAddress().toString(), depositValue, depositValue, false, BigInteger.ZERO); handleCallMessageWithOutProtocols(fromNetworkAddress, data, protocols); BigInteger poolId = (BigInteger) dexScore.call("getPoolId", bnusdScore.getAddress(), sicxScore.getAddress()); @@ -269,7 +279,7 @@ static byte[] getXRemoveData(BigInteger poolId, BigInteger lpTokenBalance, Boole return writer.toByteArray(); } - static byte[] getAddLPData(Address baseToken, Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { + static byte[] getAddLPData(String baseToken, String quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); writer.beginList(7); writer.write("xadd"); diff --git a/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java b/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java index 969e3606f..f6dfc8681 100644 --- a/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java +++ b/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java @@ -399,7 +399,7 @@ void crossChainClaimRewards(){ dexAddQuoteCoin((Address) quoteAssetAddress); // Arrange - add pool - byte[] xaddMessage = getAddLPData(baseAssetAddress, quoteAssetAddress, amount, amount, false, BigInteger.valueOf(5) ); + byte[] xaddMessage = getAddLPData(baseAssetAddress.toString(), quoteAssetAddress.toString(), amount, amount, false, BigInteger.valueOf(5) ); owner.xcall.recvCall(dex._address(), ethAccount.toString(), xaddMessage); // Arrange - stake @@ -579,7 +579,7 @@ private void addNewDataSource(String name, BigInteger id, BigInteger type) { balanced.ownerClient.governance.execute(actions.toString()); } - static byte[] getAddLPData(score.Address baseToken, score.Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { + static byte[] getAddLPData(String baseToken, String quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); writer.beginList(7); writer.write("xadd"); diff --git a/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java b/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java index 12a8feeb6..24e417daf 100644 --- a/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java +++ b/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java @@ -207,7 +207,7 @@ void crossChainStakeAndUnstake() { dexAddQuoteCoin((Address) quoteAssetAddress); // Arrange - add pool - byte[] xaddMessage = getAddLPData(baseAssetAddress, quoteAssetAddress, amount, amount, false, BigInteger.valueOf(5) ); + byte[] xaddMessage = getAddLPData(baseAssetAddress.toString(), quoteAssetAddress.toString(), amount, amount, false, BigInteger.valueOf(5) ); owner.xcall.recvCall(dexScoreClient._address(), ethAccount.toString(), xaddMessage); // Act - stake @@ -275,7 +275,7 @@ private void addNewDataSource(String name, BigInteger id, BigInteger type) { balanced.ownerClient.governance.execute(actions.toString()); } - static byte[] getAddLPData(score.Address baseToken, score.Address quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { + static byte[] getAddLPData(String baseToken, String quoteToken, BigInteger baseValue, BigInteger quoteValue, Boolean withdraw_unused, BigInteger slippagePercentage) { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); writer.beginList(7); writer.write("xadd"); diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index 3ff135a7a..cb17b4535 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -147,6 +147,9 @@ public void handleCallMessage(String _from, byte[] _data, @Optional String[] _pr } public void xUnstake(String from, BigInteger id, BigInteger value) { + Context.println("from is: "+from); + Context.println("id is: "+id); + Context.println("value is: "+value); unstake(id, NetworkAddress.valueOf(from), value); } @@ -158,6 +161,7 @@ public void unstake(BigInteger id, BigInteger value) { } private void unstake(BigInteger id, NetworkAddress user, BigInteger value){ + Context.println("value is: "+value); Context.require(value.compareTo(BigInteger.ZERO) > 0, "StakedLP: Cannot unstake less than zero value"); BigInteger previousBalance = poolStakedDetails.at(user).getOrDefault(id, BigInteger.ZERO); BigInteger previousTotal = totalStaked(id); 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 2a10d9d81..f08ff4f9e 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 @@ -187,14 +187,14 @@ void add(Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInte @Optional boolean _withdraw_unused, @Optional BigInteger _slippagePercentage); @XCall - void xAdd(String from, Address _baseToken, Address _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, + void xAdd(String from, String _baseToken, String _quoteToken, BigInteger _baseValue, BigInteger _quoteValue, @Optional Boolean _withdraw_unused, @Optional BigInteger _slippagePercentage); @XCall void xHubTransfer(String from, String _to, BigInteger _value, BigInteger _id, byte[] _data); @XCall - void xWithdraw(String from, Address _token, BigInteger _value); + void xWithdraw(String from, String _token, BigInteger _value); @XCall void xRemove(String from, BigInteger id, BigInteger value, @Optional Boolean withdraw); diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java index e85f0d240..c12f6eb68 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java @@ -19,22 +19,22 @@ public class Versions { public final static String BALN = "v1.1.0"; public final static String DIVIDENDS = "v1.0.0"; - public final static String LOANS = "v1.2.0"; + public final static String LOANS = "v1.2.3"; public final static String RESERVE = "v1.0.0"; public final static String SICX = "v1.1.0"; public final static String STAKING = "v1.0.1"; public final static String WORKERTOKEN = "v1.0.0"; public final static String BNUSD = "v1.1.1"; public final static String FEEHANDLER = "v1.0.1"; - public final static String REWARDS = "v1.2.1"; + public final static String REWARDS = "v1.2.3"; public final static String STABILITY = "v1.1.1"; public final static String BALANCEDORACLE = "v1.2.0"; - public final static String DAOFUND = "v1.1.2"; - public final static String DEX = "v1.1.2"; + public final static String DAOFUND = "v1.1.4"; + public final static String DEX = "v1.1.6"; public final static String GOVERNANCE = "v1.0.2"; public final static String REBALANCING = "v1.0.0"; - public final static String ROUTER = "v1.1.6"; - public final static String STAKEDLP = "v1.0.2"; + public final static String ROUTER = "v1.1.8"; + public final static String STAKEDLP = "v1.0.7"; public final static String BOOSTED_BALN = "v1.1.0"; public final static String BRIBING = "v1.0.1"; public final static String BALANCED_OTC = "v1.0.0"; From 3be7c9ba4377e0d4af929e30a7a906c4473bbda0 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 15 Nov 2024 15:24:18 +0545 Subject: [PATCH 11/31] crosschain lp feature implementation guidance doc --- .gitignore | 2 - crosschainlp.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 crosschainlp.md diff --git a/.gitignore b/.gitignore index 556e075fe..e387d66a1 100644 --- a/.gitignore +++ b/.gitignore @@ -100,5 +100,3 @@ gradle.properties */bin/ /bin/ bin/ - -crosschainlp.md \ No newline at end of file diff --git a/crosschainlp.md b/crosschainlp.md new file mode 100644 index 000000000..746249621 --- /dev/null +++ b/crosschainlp.md @@ -0,0 +1,144 @@ +## Crosschain LP Feature Implementation Steps +The Crosschain Liquidity feature allows users to create a liquidity pool and/or provide +liquidity to a pool existing on the balanced from one of the spoke chain. Other activities +involved in this feature are staking the LP tokens, claiming rewards, unstaking the LP tokens, + removing the liquidity from the pool and withdrawing the deposited amount. Adding the liquidity + to a pool involves two steps 1) deposit a pair of tokens to the dex 2) add liquidity. Lets deep +dive in each steps + + +### Create/Add liquidity +Creating a Liquidity pool requires two tokens (Base Token, Quote Token). The first step is to +deposit the tokens. To deposit the tokens from spoke chain we use Asset manager contract of the +spoke chain or Balanced Dollar Contract of the spoke chain of one of the token of the +pair is bnUSD. +#### Deposit tokens + While depositing the token data field should have the following value: + +```javascript + function tokenData(method: string, params: Record): Buffer { + const map = { + method: method, + params: params, + }; + + const jsonString = JSON.stringify(map); + return Buffer.from(jsonString, "utf-8"); + } + + let data = tokenData("_deposit", {}); +``` +#### Create a pool/Add liquidity +To create a pool the Quote Token needs to be added in the Dex priorly (Balanced governance only function). +No other action to take, and simply adding liquidity will create a pool if there does not exist +already, otherwise it will simply add liquidity on the existing pool. Adding crosschain lp requires a call +to the spoke Xcall contract on `sendCall` method. A call to Solana Xcall contract looks like: + +```javascript + let sources=xmState.sources; + let destinations=xmState.destinations; + let baseToken = "cx87f7f8ceaa054d46ba7343a2ecd21208e12913c6"; //testnet bnusd address + let quoteToken = "cx6c46fbf0ac7e13c808424327bbf1cb4b699e14a5"; //testnet wrap sol address + let data = getAddLPData(baseToken, quoteToken, baseAmount, quoteAmount, true, slippagePercentage); //get rlp encoded data + let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_dex }; //icon nid hardcoded + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to) .... +``` + + +### Stake LP Tokens +Once a user provide the liquidity to a pool, they get respective LP tokens as the proof of the liquidity. +They may want to stake the LP tokens if the pool is incentivised. A user can stake their LP tokens +with a crosschain call. The crosschain call will be a call to the spoke Xcall contract's `sendCall` +method that looks like: +```javascript + let sources=xmState.sources; + let destinations=xmState.destinations; + let data = getStakeData("0x2.icon/cx0e04a92802d171a8d9f318f6568af47d68dba902", poolId, lpTokenAmount); //testnet stakedLp contract's network address hardcodec + let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_dex }; + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to) .... +``` + + +### Claim rewards +Once a user stakes their LP token of incentivised pool, the reward starts to be calculated, the User can +claim the rewards of minimum one day. To claim the rewards with crosschain call, here is a code sample for +Solana blockchain: +```javascript + let sources=xmState.sources; + let destinations=xmState.destinations; + let data = getClaimRewardData("", []); //to filed is optional and protocol list is also optional + let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_rewards }; + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to) ..... +``` + +### Unstake LP tokens +A user can unstake their LP tokens with a crosschain call on calling the `sendCall` method of spoke +Xcall method. here is a sample script for the Solana blockchain +```javascript + let sources=xmState.sources; + let destinations=xmState.destinations; + let data = getUnStakeData(poolId, lpTokenAmount); //rlp encoded data + let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_stakedlp }; + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to).... +``` +### +To remove the liquidity from a pool: +```javascript + let sources=xmState.sources; + let destinations=xmState.destinations; + let data = getXRemoveData(poolId, lpTokenAmout, true); + let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_dex }; + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to).... +``` +### +To withdraw the deposited amount: +```javascript + let sources=xmState.sources; + let destinations=xmState.destinations; + let baseToken = "cx6c46fbf0ac7e13c808424327bbf1cb4b699e14a5"; //testnet wrapped sol token address + let data = getWithdrawData(baseToken, withdrawAmount); + let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_dex }; + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to)... +``` \ No newline at end of file From 465d2867008d2eac7eabba58db80ec6943228643 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 18 Nov 2024 22:54:54 +0545 Subject: [PATCH 12/31] fallback method added to rewards and stakedLp, router tested --- .../network/balanced/score/core/rewards/RewardsImpl.java | 5 +++++ .../network/balanced/score/core/stakedlp/StakedLPImpl.java | 5 +++++ .../java/network/balanced/score/lib/utils/Versions.java | 6 +++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java index 0056fd6f3..3ae6a681c 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java @@ -30,6 +30,7 @@ import score.annotation.EventLog; import score.annotation.External; import score.annotation.Optional; +import score.annotation.Payable; import scorex.util.ArrayList; import scorex.util.HashMap; @@ -1064,6 +1065,10 @@ private BigInteger fetchBoostedSupply() { } } + @Payable + public void fallback() { + } + @EventLog(indexed = 1) public void RewardsClaimed(Address _address, BigInteger _amount) { } diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index cb17b4535..854692334 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -24,6 +24,7 @@ import score.annotation.EventLog; import score.annotation.External; import score.annotation.Optional; +import score.annotation.Payable; import scorex.util.HashMap; import java.math.BigInteger; @@ -281,4 +282,8 @@ private void stake(NetworkAddress user, BigInteger id, BigInteger value) { Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, user.toString(), newBalance); } } + + @Payable + public void fallback() { + } } diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java index c12f6eb68..6b40dc0c8 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java @@ -26,15 +26,15 @@ public class Versions { public final static String WORKERTOKEN = "v1.0.0"; public final static String BNUSD = "v1.1.1"; public final static String FEEHANDLER = "v1.0.1"; - public final static String REWARDS = "v1.2.3"; + public final static String REWARDS = "v1.2.4"; public final static String STABILITY = "v1.1.1"; public final static String BALANCEDORACLE = "v1.2.0"; public final static String DAOFUND = "v1.1.4"; - public final static String DEX = "v1.1.6"; + public final static String DEX = "v1.1.8"; public final static String GOVERNANCE = "v1.0.2"; public final static String REBALANCING = "v1.0.0"; public final static String ROUTER = "v1.1.8"; - public final static String STAKEDLP = "v1.0.7"; + public final static String STAKEDLP = "v1.0.8"; public final static String BOOSTED_BALN = "v1.1.0"; public final static String BRIBING = "v1.0.1"; public final static String BALANCED_OTC = "v1.0.0"; From 102174fced40cd8462684c7e08e09968acc06d9f Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 19 Nov 2024 09:34:06 +0545 Subject: [PATCH 13/31] fallback method removed from stakedLp contract --- .../network/balanced/score/core/stakedlp/StakedLPImpl.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index 854692334..5cfc2176f 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -283,7 +283,4 @@ private void stake(NetworkAddress user, BigInteger id, BigInteger value) { } } - @Payable - public void fallback() { - } } From 14ad8077db94a4544bd6bf283761309feaa38b61 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 20 Nov 2024 13:42:44 +0545 Subject: [PATCH 14/31] unused variables, imports and commented codes removed --- .../score/core/dex/DexDBVariables.java | 17 ----------- .../balanced/score/core/dex/DexImpl.java | 4 +-- .../core/dex/DexTestSettersAndGetters.java | 20 ------------- .../core/rewards/RewardsIntegrationTest.java | 29 ++++++++----------- .../score/core/rewards/DataSourceDB.java | 4 --- .../score/core/rewards/RewardsImpl.java | 17 ----------- .../score/core/rewards/RewardsTestBase.java | 9 +++--- .../rewards/RewardsTestExternalRewards.java | 23 ++++----------- .../core/rewards/RewardsTestRewards.java | 6 ---- .../score/core/rewards/RewardsTestSetup.java | 4 +-- .../stakedlp/StakedlpIntegrationTest.java | 18 ++++++------ .../score/core/stakedlp/StakedLPImpl.java | 16 +++++----- .../score/core/stakedlp/StakedLPTest.java | 21 +++++--------- 13 files changed, 51 insertions(+), 137 deletions(-) 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 b33080391..97c8e40af 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 @@ -37,8 +37,6 @@ public class DexDBVariables { private static final String CURRENT_DAY = "current_day"; private static final String TIME_OFFSET = "time_offset"; - private static final String REWARDS_DONE = "rewards_done"; - private static final String DIVIDENDS_DONE = "dividends_done"; private static final String DEPOSIT = "deposit"; private static final String POOL_ID = "poolId"; private static final String NONCE = "nonce"; @@ -58,8 +56,6 @@ public class DexDBVariables { private static final String SICX_EARNINGS = "sicxEarnings"; private static final String MARKETS_NAMES = "marketsToNames"; private static final String TOKEN_PRECISIONS = "token_precisions"; - private static final String CURRENT_TX = "current_tx"; - private static final String CONTINUOUS_REWARDS_DAY = "continuous_rewards_day"; public static final String VERSION = "version"; public static final String ORACLE_PROTECTION = "oracle_protection"; @@ -68,8 +64,6 @@ public class DexDBVariables { public final static VarDB dexOn = Context.newVarDB(DEX_ON, Boolean.class); // Deposits - Map: token_address -> user_address -> value -// final static BranchDB> deposit = Context.newBranchDB(DEPOSIT, -// BigInteger.class); final static BranchedNetworkAddressDictDB deposit = new BranchedNetworkAddressDictDB<>(DEPOSIT, BigInteger.class); // Pool IDs - Map: token address -> opposite token_address -> id @@ -88,12 +82,9 @@ public class DexDBVariables { // User Balances // Map: pool_id -> user address -> lp token balance -// final static BranchDB> balance = Context.newBranchDB(BALANCE, -// BigInteger.class); final static BranchedNetworkAddressDictDB balance = new BranchedNetworkAddressDictDB<>(BALANCE, BigInteger.class); - // Map: pool_id -> user address -> ids/values/length -> length/0 -> value final static BranchDB>>> accountBalanceSnapshot = Context.newBranchDB(ACCOUNT_BALANCE_SNAPSHOT, BigInteger.class); @@ -108,8 +99,6 @@ public class DexDBVariables { // Rewards/timekeeping logic final static VarDB currentDay = Context.newVarDB(CURRENT_DAY, BigInteger.class); final static VarDB timeOffset = Context.newVarDB(TIME_OFFSET, BigInteger.class); - final static VarDB rewardsDone = Context.newVarDB(REWARDS_DONE, Boolean.class); - final static VarDB dividendsDone = Context.newVarDB(DIVIDENDS_DONE, Boolean.class); final static LPMetadataDB activeAddresses = new LPMetadataDB(); // Pools must use one of these as quote currency @@ -144,12 +133,6 @@ public class DexDBVariables { final static DictDB tokenPrecisions = Context.newDictDB(TOKEN_PRECISIONS, BigInteger.class); - // VarDB used to track the current sent transaction. This helps bound iterations. - final static VarDB currentTx = Context.newVarDB(CURRENT_TX, byte[].class); - - // Activation of continuous rewards day - final static VarDB continuousRewardsDay = Context.newVarDB(CONTINUOUS_REWARDS_DAY, BigInteger.class); - public static final VarDB currentVersion = Context.newVarDB(VERSION, String.class); //Map: pid -> percentage diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index e895ca33a..d2690e550 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -146,7 +146,7 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { if (method.equals("_deposit")) { JsonObject params = json.get("params").asObject(); String to = _from; - if(params.get("address")!=null){ + if (params.get("address") != null) { to = params.get("address").asString(); } deposit(fromToken, NetworkAddress.valueOf(to), _value); @@ -347,7 +347,7 @@ void _remove(BigInteger _id, NetworkAddress _user, BigInteger _value, @Optional userQuoteDeposit.set(_user, depositedQuote.add(quoteToWithdraw)); if (_withdraw) { - xWithdraw(_user.toString(), baseToken.toString(), baseToWithdraw); + xWithdraw(_user.toString(), baseToken.toString(), baseToWithdraw); xWithdraw(_user.toString(), quoteToken.toString(), quoteToWithdraw); } diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java index 49443857f..76702509a 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestSettersAndGetters.java @@ -482,26 +482,6 @@ void getBnusdValue_sicxIcxPool() { assertEquals(expectedPoolValue, poolValue); } - // @Test - // void getBnusdValue_sicxIsQuote() { - // // Arrange. - // BigInteger balnValue = BigInteger.valueOf(195).multiply(EXA); - // BigInteger sicxValue = BigInteger.valueOf(350).multiply(EXA); - // String poolName = "bnUSD/sICX"; - // BigInteger poolId = BigInteger.TWO; - // BigInteger sicxBnusdPrice = BigInteger.valueOf(10).multiply(EXA); - // BigInteger expectedValue = (sicxValue.multiply(BigInteger.TWO).multiply(sicxBnusdPrice)).divide(EXA); - // doReturn(sicxBnusdPrice).when(dexScoreSpy).getSicxBnusdPrice(); - - // // Act. Why can I not supply with sicx as quote currency? Fails. - // dexScore.invoke(governanceScore, "setMarketName", poolId, poolName); - // supplyLiquidity(ownerAccount, bnusdScore, sicxScore, balnValue, sicxValue, false); - - // // Assert. - // //BigInteger poolValue = (BigInteger) dexScore.call( "getBnusdValue", poolName); - // //assertEquals(expectedValue, poolValue); - // } - @Test void getBnusdValue_bnusdIsQuote() { // Arrange. diff --git a/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java b/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java index f6dfc8681..32f236809 100644 --- a/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java +++ b/core-contracts/Rewards/src/intTest/java/network/balanced/score/core/rewards/RewardsIntegrationTest.java @@ -19,15 +19,12 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; -import com.iconloop.score.test.Account; import foundation.icon.jsonrpc.Address; -import foundation.icon.score.client.DefaultScoreClient; import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.interfaces.*; import network.balanced.score.lib.test.integration.Balanced; import network.balanced.score.lib.test.integration.BalancedClient; import network.balanced.score.lib.test.integration.ScoreIntegrationTest; -import org.json.JSONArray; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -36,14 +33,11 @@ import score.UserRevertedException; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import static network.balanced.score.lib.test.integration.BalancedUtils.*; import static network.balanced.score.lib.utils.Constants.*; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.verify; class RewardsIntegrationTest implements ScoreIntegrationTest { private static Balanced balanced; @@ -232,7 +226,7 @@ void boostRewards() throws Exception { Map> boostData = reader.rewards.getBoostData( icxSicxLpBoosted.getAddress().toString(), - new String[] { "sICX/ICX", "Loans" }); + new String[]{"sICX/ICX", "Loans"}); assertEquals(currentWorkingBalanceAndSupply.get("workingSupply"), boostData.get("sICX/ICX").get( "workingSupply")); assertEquals(currentWorkingBalanceAndSupply.get("workingBalance"), boostData.get("sICX/ICX").get( @@ -363,7 +357,7 @@ void removeRewardsDistributions() throws Exception { } @Test - void crossChainClaimRewards(){ + void crossChainClaimRewards() { // Arrange NetworkAddress ethBaseAssetAddress = new NetworkAddress(balanced.ETH_NID, balanced.ETH_TOKEN_ADDRESS); NetworkAddress ethQuoteAssetAddress = new NetworkAddress(balanced.ETH_NID, "ox100"); @@ -387,27 +381,28 @@ void crossChainClaimRewards(){ score.Address quoteAssetAddress = owner.assetManager.getAssetAddress(ethQuoteAssetAddress.toString()); // Arrange - deposits - byte[] deposit1 = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", - new JsonObject().set( "address", ethAccount.toString()))); + byte[] deposit1 = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set("address", ethAccount.toString()))); owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit1); - byte[] deposit2 = AssetManagerMessages.deposit("ox100", ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", - new JsonObject().set( "address", ethAccount.toString()))); + byte[] deposit2 = AssetManagerMessages.deposit("ox100", ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set("address", ethAccount.toString()))); owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit2); // Arrange add quote token dexAddQuoteCoin((Address) quoteAssetAddress); // Arrange - add pool - byte[] xaddMessage = getAddLPData(baseAssetAddress.toString(), quoteAssetAddress.toString(), amount, amount, false, BigInteger.valueOf(5) ); + byte[] xaddMessage = getAddLPData(baseAssetAddress.toString(), quoteAssetAddress.toString(), amount, amount, false, BigInteger.valueOf(5)); owner.xcall.recvCall(dex._address(), ethAccount.toString(), xaddMessage); // Arrange - stake BigInteger poolId = dex.getPoolId(baseAssetAddress, quoteAssetAddress); - try{ + try { addNewDataSource("test1", poolId, BigInteger.ONE); - } catch (Exception ignored){} + } catch (Exception ignored) { + } BigInteger balance = dex.xBalanceOf(ethAccount.toString(), poolId); byte[] stakeData = getStakeData(stakingAddress, balance, poolId, "stake".getBytes()); owner.xcall.recvCall(owner.dex._address(), ethAccount.toString(), stakeData); @@ -415,7 +410,7 @@ void crossChainClaimRewards(){ // Act balanced.increaseDay(2); - String[] sources = new String[] {}; + String[] sources = new String[]{}; byte[] claimData = getClaimRewardData(ethAccount.toString(), sources); owner.xcall.recvCall(rewards._address(), ethAccount.toString(), claimData); @@ -554,7 +549,7 @@ static byte[] getClaimRewardData(String to, String[] sources) { writer.write("xclaimrewards"); writer.write(to); writer.beginList(sources.length); - for(String source : sources) { + for (String source : sources) { writer.write(source); } writer.end(); diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/DataSourceDB.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/DataSourceDB.java index 70278f42a..ed5d8d08e 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/DataSourceDB.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/DataSourceDB.java @@ -38,10 +38,6 @@ public static int size() { return names.size(); } - public static boolean hasSource(String name) { - return contains(names, name); - } - public static void newSource(String name, Address address) { Context.require(!contains(names, name), TAG + ": Data source already exists"); diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java index 3ae6a681c..bba22a8ab 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java @@ -881,23 +881,6 @@ private void verifyPercentages() { Context.require(total.compareTo(HUNDRED_PERCENTAGE) <= 0, "Sum of distributions exceeds 100%"); } - private BigInteger getVotableDist() { - BigInteger total = HUNDRED_PERCENTAGE; - List recipients = distributionPercentages.keys(); - for (String recipient : recipients) { - BigInteger split = distributionPercentages.get(recipient); - total = total.subtract(split); - } - - List fixedPercentageSources = fixedDistributionPercentages.keys(); - for (String recipient : fixedPercentageSources) { - BigInteger split = fixedDistributionPercentages.get(recipient); - total = total.subtract(split); - } - - return total; - } - public static String[] getAllSources() { int dataSourcesCount = DataSourceDB.size(); String[] sources = new String[dataSourcesCount]; diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java index 35270539b..45a72e50e 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestBase.java @@ -25,6 +25,7 @@ import network.balanced.score.lib.utils.Names; import network.balanced.score.lib.test.mock.MockContract; import network.balanced.score.lib.test.mock.MockBalanced; + import static network.balanced.score.lib.utils.Constants.MICRO_SECONDS_IN_A_DAY; import org.mockito.MockedStatic; @@ -44,7 +45,7 @@ class RewardsTestBase extends UnitTest { static final Long DAY = 43200L; - static final Long WEEK_BLOCKS = 7*DAY; + static final Long WEEK_BLOCKS = 7 * DAY; static final BigInteger EXA = BigInteger.TEN.pow(18); @@ -87,7 +88,7 @@ void setup() throws Exception { BigInteger startTime = BigInteger.valueOf(sm.getBlock().getTimestamp()); // One vote period before being able to start voting - sm.getBlock().increase(DAY*10); + sm.getBlock().increase(DAY * 10); when(mockBalanced.xCall.mock.getNetworkId()).thenReturn(NATIVE_NID); doNothing().when(mockBalanced.sicx.mock).transfer(any(Address.class), any(BigInteger.class), any(byte[].class)); @@ -129,7 +130,7 @@ void setup() throws Exception { rewardsScore.invoke(owner, "setFixedSourcePercentage", "Loans", EXA.divide(BigInteger.TEN)); // One vote period to apply votes - sm.getBlock().increase(DAY*10); + sm.getBlock().increase(DAY * 10); rewardsScore.invoke(owner, "updateRelativeSourceWeight", "sICX/ICX", BigInteger.valueOf(sm.getBlock().getTimestamp())); @@ -199,7 +200,7 @@ void mockUserWeight(Account user, BigInteger weight) { } @SuppressWarnings("unchecked") - BigInteger getVotePercentage(String name){ + BigInteger getVotePercentage(String name) { Map> data = (Map>) rewardsScore.call("getDistributionPercentages"); return data.get("Voting").get(name).add(data.get("Fixed").getOrDefault(name, BigInteger.ZERO)); } diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java index ec2cac320..087212ba1 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestExternalRewards.java @@ -18,10 +18,6 @@ import com.iconloop.score.test.Account; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import score.Address; - import org.json.JSONArray; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -30,10 +26,7 @@ import score.Context; import static network.balanced.score.lib.utils.Constants.*; -import static network.balanced.score.lib.utils.Constants.EXA; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import java.math.BigInteger; @@ -86,7 +79,7 @@ void externalRewards_base() { JSONArray data = new JSONArray(_data); rewardsScore.invoke(mockBalanced.sicx.account, "tokenFallback", externalRewardsProvider.getAddress(), - sICXRewards, data.toString().getBytes()); + sICXRewards, data.toString().getBytes()); BigInteger emission = (BigInteger) rewardsScore.call("getEmission", BigInteger.valueOf(-1)); BigInteger dist = getVotePercentage("sICX/ICX").multiply(emission).divide(EXA); BigInteger userDist = dist.multiply(balance).divide(totalSupply); @@ -387,18 +380,14 @@ static byte[] getClaimRewardData(String to, String[] sources) { writer.beginList(3); writer.write("xclaimrewards"); writer.write(to); - writer.beginList(sources.length); - for(String source : sources) { - writer.write(source); - } - writer.end(); + writer.beginList(sources.length); + for (String source : sources) { + writer.write(source); + } + writer.end(); writer.end(); return writer.toByteArray(); } - protected void handleCallMessageWithOutProtocols(String from, byte[] data, String[] protocols ) { - rewardsScore.invoke(mockBalanced.xCall.account, "handleCallMessage", from, data, protocols); - } - } \ No newline at end of file diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestRewards.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestRewards.java index 2e70ee826..a333bb356 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestRewards.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestRewards.java @@ -726,17 +726,11 @@ void setGetVotable() { assertTrue(!(boolean)rewardsScore.call("isVotable", "sICX/ICX")); } - @Test - void addType() { - // assertOnlyCallableByGovernance(rewardsScore, "addType", "newType"); - } - @Test void setGetTypeWeight() { int type = (int)rewardsScore.call("getSourceType", "sICX/ICX"); rewardsScore.invoke(owner, "checkpoint"); assertEquals(EXA ,rewardsScore.call("getCurrentTypeWeight", type)); - // assertOnlyCallableByGovernance(rewardsScore, "changeTypeWeight", type, EXA.multiply(BigInteger.TWO)); rewardsScore.invoke(owner, "changeTypeWeight", type, EXA.multiply(BigInteger.TWO)); assertEquals(EXA.multiply(BigInteger.TWO) ,rewardsScore.call("getCurrentTypeWeight", type)); } diff --git a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestSetup.java b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestSetup.java index 012ce2fe3..723133339 100644 --- a/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestSetup.java +++ b/core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestSetup.java @@ -50,7 +50,7 @@ void setAndGetTimeOffset() { BigInteger timeOffset = BigInteger.ONE.multiply(MICRO_SECONDS_IN_A_DAY).negate(); Account nonOwner = sm.createAccount(); String expectedErrorMessage = "SenderNotScoreOwner"; - Executable setNotFromOwner = () -> rewardsScore.invoke(nonOwner, "setTimeOffset",timeOffset); + Executable setNotFromOwner = () -> rewardsScore.invoke(nonOwner, "setTimeOffset", timeOffset); expectErrorMessage(setNotFromOwner, expectedErrorMessage); rewardsScore.invoke(owner, "setTimeOffset", timeOffset); @@ -94,7 +94,7 @@ void setBoostWeight() { Account nonOwner = sm.createAccount(); String expectedErrorMessage = "SenderNotScoreOwner"; - Executable setNotFromOwner = () -> rewardsScore.invoke(nonOwner, "setBoostWeight",weight); + Executable setNotFromOwner = () -> rewardsScore.invoke(nonOwner, "setBoostWeight", weight); expectErrorMessage(setNotFromOwner, expectedErrorMessage); expectedErrorMessage = "Reverted(0): Boost weight has to be above 1%"; Executable setWeightAbove = () -> rewardsScore.invoke(owner, "setBoostWeight", weightBelow); diff --git a/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java b/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java index 24e417daf..a896b11ee 100644 --- a/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java +++ b/core-contracts/StakedLP/src/intTest/java/network/balanced/score/core/stakedlp/StakedlpIntegrationTest.java @@ -18,7 +18,6 @@ import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; -import foundation.icon.icx.KeyWallet; import foundation.icon.icx.Wallet; import foundation.icon.jsonrpc.Address; import foundation.icon.score.client.DefaultScoreClient; @@ -91,7 +90,7 @@ public class StakedlpIntegrationTest { chain.networkId, balanced.owner, tokenAClient._address()); ownerDexTestBaseScoreClient = new DexTestScoreClient(chain.getEndpointURL(), chain.networkId, balanced.owner, tokenBClient._address()); - }catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); System.out.println("Error on init test: " + e.getMessage()); } @@ -195,27 +194,28 @@ void crossChainStakeAndUnstake() { score.Address quoteAssetAddress = owner.assetManager.getAssetAddress(ethQuoteAssetAddress.toString()); // Arrange - deposits - byte[] deposit1 = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", - new JsonObject().set( "address", ethAccount.toString()))); + byte[] deposit1 = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set("address", ethAccount.toString()))); owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit1); - byte[] deposit2 = AssetManagerMessages.deposit("ox100", ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", - new JsonObject().set( "address", ethAccount.toString()))); + byte[] deposit2 = AssetManagerMessages.deposit("ox100", ethAccount.account(), toNetworkAddress, amount, tokenData("_deposit", + new JsonObject().set("address", ethAccount.toString()))); owner.xcall.recvCall(owner.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), deposit2); // Arrange add quote token dexAddQuoteCoin((Address) quoteAssetAddress); // Arrange - add pool - byte[] xaddMessage = getAddLPData(baseAssetAddress.toString(), quoteAssetAddress.toString(), amount, amount, false, BigInteger.valueOf(5) ); + byte[] xaddMessage = getAddLPData(baseAssetAddress.toString(), quoteAssetAddress.toString(), amount, amount, false, BigInteger.valueOf(5)); owner.xcall.recvCall(dexScoreClient._address(), ethAccount.toString(), xaddMessage); // Act - stake BigInteger poolId = dexScoreClient.getPoolId(baseAssetAddress, quoteAssetAddress); - try{ + try { addNewDataSource("test1", poolId, BigInteger.ONE); - } catch (Exception ignored){} + } catch (Exception ignored) { + } BigInteger balance = dexScoreClient.xBalanceOf(ethAccount.toString(), poolId); byte[] stakeData = getStakeData(stakingAddress, balance, poolId, "stake".getBytes()); owner.xcall.recvCall(owner.dex._address(), ethAccount.toString(), stakeData); diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index 5cfc2176f..f76fc912e 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -24,7 +24,6 @@ import score.annotation.EventLog; import score.annotation.External; import score.annotation.Optional; -import score.annotation.Payable; import scorex.util.HashMap; import java.math.BigInteger; @@ -51,6 +50,7 @@ public class StakedLPImpl implements StakedLP { private static final VarDB
rewards = Context.newVarDB("rewardsAddress", Address.class); private final VarDB currentVersion = Context.newVarDB("version", String.class); public static String NATIVE_NID; + public StakedLPImpl(Address governance) { if (StakedLPImpl.governance.get() == null) { Context.require(governance.isContract(), "StakedLP: Governance address should be a contract"); @@ -148,9 +148,9 @@ public void handleCallMessage(String _from, byte[] _data, @Optional String[] _pr } public void xUnstake(String from, BigInteger id, BigInteger value) { - Context.println("from is: "+from); - Context.println("id is: "+id); - Context.println("value is: "+value); + Context.println("from is: " + from); + Context.println("id is: " + id); + Context.println("value is: " + value); unstake(id, NetworkAddress.valueOf(from), value); } @@ -161,8 +161,8 @@ public void unstake(BigInteger id, BigInteger value) { unstake(id, user, value); } - private void unstake(BigInteger id, NetworkAddress user, BigInteger value){ - Context.println("value is: "+value); + private void unstake(BigInteger id, NetworkAddress user, BigInteger value) { + Context.println("value is: " + value); Context.require(value.compareTo(BigInteger.ZERO) > 0, "StakedLP: Cannot unstake less than zero value"); BigInteger previousBalance = poolStakedDetails.at(user).getOrDefault(id, BigInteger.ZERO); BigInteger previousTotal = totalStaked(id); @@ -276,9 +276,9 @@ private void stake(NetworkAddress user, BigInteger id, BigInteger value) { Stake(user.toString(), id, value); - if(user.net().equals(NATIVE_NID)) { + if (user.net().equals(NATIVE_NID)) { Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, user.account(), newBalance); - }else{ + } else { Context.call(rewards.get(), "updateBalanceAndSupply", poolName, newTotal, user.toString(), newBalance); } } diff --git a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java index 7d8fe52e3..c1f1c6157 100644 --- a/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java +++ b/core-contracts/StakedLP/src/test/java/network/balanced/score/core/stakedlp/StakedLPTest.java @@ -24,14 +24,11 @@ import network.balanced.score.lib.test.UnitTest; import network.balanced.score.lib.test.mock.MockBalanced; import network.balanced.score.lib.test.mock.MockContract; -import network.balanced.score.lib.utils.BalancedAddressManager; -import network.balanced.score.lib.utils.Names; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; -import org.mockito.MockedStatic; import org.mockito.Mockito; import score.Address; import score.ByteArrayObjectWriter; @@ -53,7 +50,6 @@ public class StakedLPTest extends UnitTest { public static final Account owner = sm.createAccount(); private Score stakedLpScore; - //public static final Account governanceScore = Account.newScoreAccount(1); private final Account alice = sm.createAccount(); private final Account bob = sm.createAccount(); @@ -67,6 +63,7 @@ public class StakedLPTest extends UnitTest { public static final String poolOneName = "pool1"; public static final String poolTwoName = "pool2"; private final String NATIVE_NID = "0x1.ICON"; + @BeforeEach public void setup() throws Exception { mockBalanced = new MockBalanced(sm, owner); @@ -157,7 +154,7 @@ private void stakeLpTokens(String from, BigInteger poolId, BigInteger value) { } @Test - void crossChainStake(){ + void crossChainStake() { setAndGetDex(); setAndGetRewards(); String fromNetworkAddress1 = "0x1.ETH/0x123"; @@ -206,7 +203,7 @@ void crossChainStake(){ } @Test - void xUnstake(){ + void xUnstake() { setAndGetDex(); setAndGetRewards(); String fromNetworkAddress = "0x1.ETH/0x123"; @@ -230,7 +227,7 @@ static byte[] getAddLPData(BigInteger id, BigInteger value) { } - protected void handleCallMessageWithOutProtocols(String from, byte[] data, String[] protocols ) { + protected void handleCallMessageWithOutProtocols(String from, byte[] data, String[] protocols) { stakedLpScore.invoke(mockBalanced.xCall.account, "handleCallMessage", from, data, protocols); } @@ -322,7 +319,7 @@ void testUnstake() { BigInteger.ONE)); verify(dex.mock).hubTransfer(NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), aliceUnstakeAmount, BigInteger.ONE, new byte[0]); verify(rewards.mock).updateBalanceAndSupply(poolOneName, totalStakedBalanceBeforeUnstake, NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), - aliceStakedBalance); + aliceStakedBalance); // Adjust the values after first unstake @@ -344,10 +341,6 @@ void testUnstake() { BigInteger.ONE)); verify(dex.mock, times(2)).hubTransfer(NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), aliceStakedBalance, BigInteger.ONE, new byte[0]); - // Unstake from pool 2 - // Unstake from unsupported pool -// stakedLpScore.invoke(Account.getAccount(governanceScore.getAddress()), "removePool", BigInteger.TWO); - BigInteger aliceStakedBalancePool2 = (BigInteger) stakedLpScore.call("balanceOf", alice.getAddress(), BigInteger.TWO); // BigInteger aliceLPBalancePool2 = (BigInteger) dex.call("balanceOf", alice.getAddress(), BigInteger.TWO); @@ -375,7 +368,7 @@ void testStakeUnstake_unnamedPool() { when(dex.mock.balanceOf(alice.getAddress(), poolId)).thenReturn(initialLpTokenBalance); // Act & Assert - Executable zeroStakeValue = () -> stakeLpTokens(alice, poolId, BigInteger.TEN); + Executable zeroStakeValue = () -> stakeLpTokens(alice, poolId, BigInteger.TEN); String expectedErrorMessage = "Pool id: " + poolId + " is not a valid pool"; expectErrorMessage(zeroStakeValue, expectedErrorMessage); @@ -396,6 +389,6 @@ void testStakeUnstake_unnamedPool() { balanceAndSupply = (Map) stakedLpScore.call("getBalanceAndSupply", name, alice.getAddress().toString()); assertEquals(BigInteger.valueOf(8), balanceAndSupply.get("_balance")); assertEquals(BigInteger.valueOf(8), balanceAndSupply.get("_totalSupply")); - verify(rewards.mock).updateBalanceAndSupply(name, balanceAndSupply.get("_totalSupply"), NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), balanceAndSupply.get("_balance")); + verify(rewards.mock).updateBalanceAndSupply(name, balanceAndSupply.get("_totalSupply"), NetworkAddress.valueOf(alice.getAddress().toString(), NATIVE_NID).toString(), balanceAndSupply.get("_balance")); } } From f792a5ec68a85777ff3408e67d8d0016f6054e73 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 20 Nov 2024 17:22:27 +0545 Subject: [PATCH 15/31] unused variables, imports and commented codes removed --- .../score/core/rewards/RewardsImpl.java | 4 +- .../score/core/stakedlp/StakedLPImpl.java | 10 +- .../score/lib/utils/TokenTransferTest.java | 155 ++++++++++++++++++ 3 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java index bba22a8ab..d51b7dba4 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java @@ -414,7 +414,7 @@ public void claimRewards(@Optional String[] sources) { } private void _claimRewards(String address, String[] sources) { - NetworkAddress networkAddress = NetworkAddress.valueOf(address, NATIVE_NID); + NetworkAddress networkAddress = new NetworkAddress(NATIVE_NID, address); BigInteger boostedBalance = fetchBoostedBalance(address); BigInteger boostedSupply = fetchBoostedSupply(); updateAllUserRewards(address, sources, boostedBalance, boostedSupply); @@ -1019,7 +1019,7 @@ private static BigInteger dailyDistribution(BigInteger day) { } private BigInteger fetchBoostedBalance(String user) { - NetworkAddress networkAddress = NetworkAddress.valueOf(user, NATIVE_NID); + NetworkAddress networkAddress = new NetworkAddress(NATIVE_NID, user); Address address = null; try { address = Address.fromString(user); diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index f76fc912e..8521a983f 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -124,7 +124,7 @@ public void setRewards(Address rewards) { @External(readonly = true) public BigInteger balanceOf(Address _owner, BigInteger _id) { - NetworkAddress owner = NetworkAddress.valueOf(_owner.toString(), NATIVE_NID); + NetworkAddress owner = new NetworkAddress(NATIVE_NID, _owner.toString()); return poolStakedDetails.at(owner).getOrDefault(_id, BigInteger.ZERO); } @@ -148,21 +148,17 @@ public void handleCallMessage(String _from, byte[] _data, @Optional String[] _pr } public void xUnstake(String from, BigInteger id, BigInteger value) { - Context.println("from is: " + from); - Context.println("id is: " + id); - Context.println("value is: " + value); unstake(id, NetworkAddress.valueOf(from), value); } @External public void unstake(BigInteger id, BigInteger value) { Address caller = Context.getCaller(); - NetworkAddress user = NetworkAddress.valueOf(caller.toString(), NATIVE_NID); + NetworkAddress user = new NetworkAddress(NATIVE_NID, caller); unstake(id, user, value); } private void unstake(BigInteger id, NetworkAddress user, BigInteger value) { - Context.println("value is: " + value); Context.require(value.compareTo(BigInteger.ZERO) > 0, "StakedLP: Cannot unstake less than zero value"); BigInteger previousBalance = poolStakedDetails.at(user).getOrDefault(id, BigInteger.ZERO); BigInteger previousTotal = totalStaked(id); @@ -201,7 +197,7 @@ public void onXIRC31Received(String _operator, String _from, BigInteger _id, Big public void onIRC31Received(Address _operator, Address _from, BigInteger _id, BigInteger _value, byte[] _data) { only(dex); Context.require(_value.signum() > 0, "StakedLP: Token value should be a positive number"); - NetworkAddress from = NetworkAddress.valueOf(_from.toString(), NATIVE_NID); + NetworkAddress from = new NetworkAddress(NATIVE_NID, _from); this.stake(from, _id, _value); } diff --git a/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java b/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java new file mode 100644 index 000000000..8c2b38a72 --- /dev/null +++ b/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java @@ -0,0 +1,155 @@ +package network.balanced.score.lib.utils; + +import com.iconloop.score.test.Account; +import com.iconloop.score.test.Score; +import com.iconloop.score.test.ServiceManager; +import foundation.icon.xcall.NetworkAddress; +import network.balanced.score.lib.test.UnitTest; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import score.Address; +import score.Context; + +import java.math.BigInteger; + +import static network.balanced.score.lib.utils.Constants.EXA; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +public class TokenTransferTest extends UnitTest { + + private static final ServiceManager sm = getServiceManager(); + private static final Account owner = sm.createAccount(); + private static final Account user = sm.createAccount(); + private static final Account contract = sm.createAccount(); + + private static Score dummyScore; + + protected final MockedStatic contextMock = Mockito.mockStatic(Context.class, Mockito.CALLS_REAL_METHODS); + protected final MockedStatic addressManagerMock = Mockito.mockStatic(BalancedAddressManager.class, Mockito.CALLS_REAL_METHODS); + + @BeforeAll + public static void setup() throws Exception{ + dummyScore = sm.deploy(owner, DummyScore.class); + } + + @Test + public void crossTransfer(){ + // Arrange + addressManagerMock.when(BalancedAddressManager::getXCall).thenReturn(contract.getAddress()); + addressManagerMock.when(BalancedAddressManager::getDaofund).thenReturn(contract.getAddress()); + addressManagerMock.when(BalancedAddressManager::getAssetManager).thenReturn(contract.getAddress()); + + contextMock.when(() -> Context.call(any(Address.class), eq("getNetworkId"))).thenReturn("0x2.ICON"); + contextMock.when(Context::getAddress).thenReturn(contract.getAddress()); + contextMock.when(() -> Context.call(any(Address.class), eq("getXCallFeePermission"), any(Address.class), any(String.class))).thenReturn(true); //can withdraw true - crossTransfer + contextMock.when(() -> Context.call(any(Address.class), eq("getNativeAssetAddress"), any(Address.class), any(String.class))).thenReturn(null); + contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); + contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); + + // Act + try { + TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); + }catch (Exception ignore){} + + contextMock.when(() -> Context.call(any(BigInteger.class), any(Address.class), eq("crossTransfer"), any(String.class), any(BigInteger.class), any(byte[].class))).thenReturn(true); + + // Verify + TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); + + //close mock + contextMock.close(); + addressManagerMock.close(); + } + + @Test + public void hubTransfer(){ + // Arrange + addressManagerMock.when(BalancedAddressManager::getXCall).thenReturn(contract.getAddress()); + addressManagerMock.when(BalancedAddressManager::getDaofund).thenReturn(contract.getAddress()); + addressManagerMock.when(BalancedAddressManager::getAssetManager).thenReturn(contract.getAddress()); + + contextMock.when(() -> Context.call(any(Address.class), eq("getNetworkId"))).thenReturn("0x2.ICON"); + contextMock.when(Context::getAddress).thenReturn(contract.getAddress()); + contextMock.when(() -> Context.call(any(Address.class), eq("getXCallFeePermission"), any(Address.class), any(String.class))).thenReturn(false); //can withdraw false - causes hub transfer + contextMock.when(() -> Context.call(any(Address.class), eq("getNativeAssetAddress"), any(Address.class), any(String.class))).thenReturn(null); + contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); + + // Act + try { + TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); + }catch (Exception ignore){} + + contextMock.when(() -> Context.call(any(Address.class), eq("hubTransfer"), any(String.class), any(BigInteger.class), any(byte[].class))).thenReturn(true); + + // Verify + TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); + + //close mock + contextMock.close(); + addressManagerMock.close(); + } + + @Test + public void transfer(){ + // Arrange + addressManagerMock.when(BalancedAddressManager::getXCall).thenReturn(contract.getAddress()); + addressManagerMock.when(BalancedAddressManager::getDaofund).thenReturn(contract.getAddress()); + addressManagerMock.when(BalancedAddressManager::getAssetManager).thenReturn(contract.getAddress()); + + contextMock.when(() -> Context.call(any(Address.class), eq("getNetworkId"))).thenReturn("0x2.ICON"); + + // Act + try { + TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x2.ICON", user.getAddress()).toString(), BigInteger.TWO); // native nid for transfer + }catch (Exception ignore){} + + contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), any(BigInteger.class), any(byte[].class))).thenReturn(true); + + // Verify + TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x2.ICON", user.getAddress()).toString(), BigInteger.TWO); // native nid for transfer + + //close mock + contextMock.close(); + addressManagerMock.close(); + } + + @Test + public void withdrawTo(){ + // Arrange + addressManagerMock.when(BalancedAddressManager::getXCall).thenReturn(contract.getAddress()); + addressManagerMock.when(BalancedAddressManager::getDaofund).thenReturn(contract.getAddress()); + addressManagerMock.when(BalancedAddressManager::getAssetManager).thenReturn(contract.getAddress()); + + contextMock.when(() -> Context.call(any(Address.class), eq("getNetworkId"))).thenReturn("0x2.ICON"); + contextMock.when(Context::getAddress).thenReturn(contract.getAddress()); + contextMock.when(() -> Context.call(any(Address.class), eq("getXCallFeePermission"), any(Address.class), any(String.class))).thenReturn(true); //can withdraw false - causes hub transfer + contextMock.when(() -> Context.call(any(Address.class), eq("getNativeAssetAddress"), any(Address.class), any(String.class))).thenReturn(contract.getAddress().toString()); // if exists on asset manager should call withdrawTo + contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); + + // Act + try { + TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); + }catch (Exception ignore){} + + contextMock.when(() -> Context.call(any(BigInteger.class), any(Address.class), eq("withdrawTo"), any(Address.class), any(String.class), any(BigInteger.class))).thenReturn(true); + + // Verify + TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); + + //close mock + contextMock.close(); + addressManagerMock.close(); + } + + + public static class DummyScore { + public DummyScore() { + + } + } + + +} From 09730212934a6cac1a5c60ecc61756f9a3422465 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 21 Nov 2024 08:01:07 +0545 Subject: [PATCH 16/31] addressManagerMock static mock issue on TokenTransfer test is fixed --- .../score/core/rewards/RewardsImpl.java | 4 +-- .../score/lib/utils/TokenTransferTest.java | 33 +++++++++++-------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java index d51b7dba4..bba22a8ab 100644 --- a/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java +++ b/core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java @@ -414,7 +414,7 @@ public void claimRewards(@Optional String[] sources) { } private void _claimRewards(String address, String[] sources) { - NetworkAddress networkAddress = new NetworkAddress(NATIVE_NID, address); + NetworkAddress networkAddress = NetworkAddress.valueOf(address, NATIVE_NID); BigInteger boostedBalance = fetchBoostedBalance(address); BigInteger boostedSupply = fetchBoostedSupply(); updateAllUserRewards(address, sources, boostedBalance, boostedSupply); @@ -1019,7 +1019,7 @@ private static BigInteger dailyDistribution(BigInteger day) { } private BigInteger fetchBoostedBalance(String user) { - NetworkAddress networkAddress = new NetworkAddress(NATIVE_NID, user); + NetworkAddress networkAddress = NetworkAddress.valueOf(user, NATIVE_NID); Address address = null; try { address = Address.fromString(user); diff --git a/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java b/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java index 8c2b38a72..e8f625057 100644 --- a/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java +++ b/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java @@ -5,6 +5,8 @@ import com.iconloop.score.test.ServiceManager; import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.test.UnitTest; +import network.balanced.score.lib.test.mock.MockBalanced; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; @@ -27,12 +29,15 @@ public class TokenTransferTest extends UnitTest { private static Score dummyScore; - protected final MockedStatic contextMock = Mockito.mockStatic(Context.class, Mockito.CALLS_REAL_METHODS); - protected final MockedStatic addressManagerMock = Mockito.mockStatic(BalancedAddressManager.class, Mockito.CALLS_REAL_METHODS); + protected static MockedStatic contextMock; + protected static MockedStatic addressManagerMock; @BeforeAll public static void setup() throws Exception{ dummyScore = sm.deploy(owner, DummyScore.class); + MockBalanced mockBalanced = new MockBalanced(sm, owner); + contextMock = Mockito.mockStatic(Context.class, Mockito.CALLS_REAL_METHODS); + addressManagerMock = MockBalanced.addressManagerMock; } @Test @@ -59,9 +64,6 @@ public void crossTransfer(){ // Verify TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); - //close mock - contextMock.close(); - addressManagerMock.close(); } @Test @@ -87,9 +89,6 @@ public void hubTransfer(){ // Verify TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); - //close mock - contextMock.close(); - addressManagerMock.close(); } @Test @@ -111,9 +110,7 @@ public void transfer(){ // Verify TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x2.ICON", user.getAddress()).toString(), BigInteger.TWO); // native nid for transfer - //close mock - contextMock.close(); - addressManagerMock.close(); + } @Test @@ -139,11 +136,19 @@ public void withdrawTo(){ // Verify TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); - //close mock - contextMock.close(); - addressManagerMock.close(); } + @AfterAll + public static void teardown() { + if (contextMock != null) { + contextMock.close(); + contextMock = null; + } + if (addressManagerMock != null) { + addressManagerMock.close(); + addressManagerMock = null; + } + } public static class DummyScore { public DummyScore() { From e218850050419c01bb6bec9e9d3283e24445de86 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 21 Nov 2024 11:10:36 +0545 Subject: [PATCH 17/31] test updates on xcall, transfer method merged in token class,exception verified on token transfer test --- .../balanced/score/core/dex/DexImpl.java | 12 -------- .../core/dex/IRC31StandardSpokeLpToken.java | 26 ++++++++++------- .../balanced/score/core/dex/DexTestCore.java | 29 ++++++++++--------- .../score/lib/utils/TokenTransferTest.java | 28 +++++++++++------- 4 files changed, 48 insertions(+), 47 deletions(-) diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index d2690e550..1b21ab10b 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -234,18 +234,6 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { } } - @External - public void transfer(Address _to, BigInteger _value, BigInteger _id, @Optional byte[] _data) { - isDexOn(); - checkStatus(); - if (_data == null) { - _data = new byte[0]; - } - NetworkAddress from = new NetworkAddress(NATIVE_NID, Context.getCaller()); - NetworkAddress to = new NetworkAddress(NATIVE_NID, _to); - _transfer(from, to, _value, _id.intValue(), _data); - } - public void xWithdraw(String from, String _token, BigInteger _value) { NetworkAddress sender = NetworkAddress.valueOf(from); _withdraw(sender, Address.fromString(_token), _value); diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java index 5e3740326..85833ea18 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java @@ -15,8 +15,10 @@ import static network.balanced.score.core.dex.DexDBVariables.*; import static network.balanced.score.core.dex.DexDBVariables.poolLpTotal; +import static network.balanced.score.core.dex.utils.Check.isDexOn; import static network.balanced.score.core.dex.utils.Const.SICXICX_POOL_ID; import static network.balanced.score.core.dex.utils.Const.TAG; +import static network.balanced.score.lib.utils.Check.checkStatus; public abstract class IRC31StandardSpokeLpToken extends FloorLimited implements Dex { @@ -40,16 +42,23 @@ public BigInteger xBalanceOf(String _owner, BigInteger _id) { @External public void transfer(Address _to, BigInteger _value, BigInteger _id, @Optional byte[] _data) { - _transfer( - new NetworkAddress(NATIVE_NID, Context.getCaller()), - new NetworkAddress(NATIVE_NID, _to), - _value, - _id.intValue(), - _data); + isDexOn(); + checkStatus(); + if (_data == null) { + _data = new byte[0]; + } + NetworkAddress from = new NetworkAddress(NATIVE_NID, Context.getCaller()); + NetworkAddress to = new NetworkAddress(NATIVE_NID, _to); + _transfer(from, to, _value, _id.intValue(), _data); } @External public void hubTransfer(String _to, BigInteger _value, BigInteger _id, @Optional byte[] _data) { + isDexOn(); + checkStatus(); + if (_data == null) { + _data = new byte[0]; + } _transfer( new NetworkAddress(NATIVE_NID, Context.getCaller()), NetworkAddress.valueOf(_to, NATIVE_NID), @@ -58,7 +67,6 @@ public void hubTransfer(String _to, BigInteger _value, BigInteger _id, @Optional _data); } - public void xHubTransfer(String from, String _to, BigInteger _value, BigInteger _id, byte[] _data) { _transfer( NetworkAddress.valueOf(from), @@ -115,10 +123,6 @@ void _transfer(NetworkAddress _from, NetworkAddress _to, BigInteger _value, Inte Context.call(contractAddress, "onXIRC31Received", _from.toString(), _from.toString(), _id, _value, dataBytes); } - protected boolean isNative(NetworkAddress address) { - return address.net().equals(NATIVE_NID); - } - boolean isLockingPool(Integer id) { return id.equals(SICXICX_POOL_ID); } diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java index 8454cea6b..9f05318a3 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestCore.java @@ -35,7 +35,6 @@ import java.util.Map; import static network.balanced.score.core.dex.utils.Const.*; -import static network.balanced.score.lib.utils.BalancedAddressManager.getDaofund; import static network.balanced.score.lib.utils.Constants.EXA; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -156,15 +155,6 @@ void crossChainLP(){ } - public static byte[] hexStringToByteArray(String hex) { - int length = hex.length(); - byte[] data = new byte[length / 2]; - for (int i = 0; i < length; i += 2) { - data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) - + Character.digit(hex.charAt(i+1), 16)); - } - return data; - } @Test void crossChainLPWithWithdraw(){ @@ -810,10 +800,21 @@ void transfer() { BigInteger initialValue = (BigInteger) dexScore.call("balanceOf", account.getAddress(), poolId); dexScore.invoke(account, "transfer", account1.getAddress(), transferValue, poolId, data.getBytes()); - BigInteger value = (BigInteger) dexScore.call("balanceOf", account.getAddress(), poolId); - assertEquals(value, initialValue.subtract(transferValue)); - value = (BigInteger) dexScore.call("balanceOf", account1.getAddress(), poolId); - assertEquals(value, transferValue); + BigInteger sendersBalanceAfterTransfer = (BigInteger) dexScore.call("balanceOf", account.getAddress(), poolId); + assertEquals(sendersBalanceAfterTransfer, initialValue.subtract(transferValue)); + BigInteger receiversBalance = (BigInteger) dexScore.call("balanceOf", account1.getAddress(), poolId); + assertEquals(receiversBalance, transferValue); + + + //test hub transfer + String toHubAddress = "0x1.ETH/0x123"; + dexScore.invoke(account, "hubTransfer", toHubAddress, transferValue, poolId, data.getBytes()); + + BigInteger sendersBalanceAfterHubTransfer = (BigInteger) dexScore.call("balanceOf", account.getAddress(), poolId); + assertEquals(sendersBalanceAfterHubTransfer, sendersBalanceAfterTransfer.subtract(transferValue)); + BigInteger hubReceiversBalance = (BigInteger) dexScore.call("xBalanceOf", toHubAddress, poolId); + assertEquals(hubReceiversBalance, transferValue); + } @Test diff --git a/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java b/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java index e8f625057..27fb6515c 100644 --- a/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java +++ b/score-lib/src/test/java/network/balanced/score/lib/utils/TokenTransferTest.java @@ -15,8 +15,10 @@ import score.Context; import java.math.BigInteger; +import java.util.EmptyStackException; import static network.balanced.score.lib.utils.Constants.EXA; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -32,12 +34,15 @@ public class TokenTransferTest extends UnitTest { protected static MockedStatic contextMock; protected static MockedStatic addressManagerMock; + protected static MockedStatic tokenTransferMock; + @BeforeAll public static void setup() throws Exception{ dummyScore = sm.deploy(owner, DummyScore.class); MockBalanced mockBalanced = new MockBalanced(sm, owner); contextMock = Mockito.mockStatic(Context.class, Mockito.CALLS_REAL_METHODS); addressManagerMock = MockBalanced.addressManagerMock; + tokenTransferMock = Mockito.mockStatic(TokenTransfer.class, Mockito.CALLS_REAL_METHODS); } @Test @@ -55,9 +60,9 @@ public void crossTransfer(){ contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); // Act - try { - TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); - }catch (Exception ignore){} + assertThrows( + EmptyStackException.class, + () -> TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO) ); contextMock.when(() -> Context.call(any(BigInteger.class), any(Address.class), eq("crossTransfer"), any(String.class), any(BigInteger.class), any(byte[].class))).thenReturn(true); @@ -80,9 +85,9 @@ public void hubTransfer(){ contextMock.when(() -> Context.call(any(Address.class), eq("claimXCallFee"), any(String.class), any(Boolean.class))).thenReturn(EXA); // Act - try { - TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); - }catch (Exception ignore){} + assertThrows( + EmptyStackException.class, + () -> TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO)); contextMock.when(() -> Context.call(any(Address.class), eq("hubTransfer"), any(String.class), any(BigInteger.class), any(byte[].class))).thenReturn(true); @@ -100,10 +105,9 @@ public void transfer(){ contextMock.when(() -> Context.call(any(Address.class), eq("getNetworkId"))).thenReturn("0x2.ICON"); - // Act - try { - TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x2.ICON", user.getAddress()).toString(), BigInteger.TWO); // native nid for transfer - }catch (Exception ignore){} + assertThrows( + EmptyStackException.class, + () -> TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x2.ICON", user.getAddress()).toString(), BigInteger.TWO)); contextMock.when(() -> Context.call(any(Address.class), eq("transfer"), any(Address.class), any(BigInteger.class), any(byte[].class))).thenReturn(true); @@ -131,6 +135,10 @@ public void withdrawTo(){ TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO); }catch (Exception ignore){} + assertThrows( + EmptyStackException.class, + () -> TokenTransfer.transfer(dummyScore.getAddress(), new NetworkAddress("0x1.ETH", user.getAddress()).toString(), BigInteger.TWO)); + contextMock.when(() -> Context.call(any(BigInteger.class), any(Address.class), eq("withdrawTo"), any(Address.class), any(String.class), any(BigInteger.class))).thenReturn(true); // Verify From 911856fb0bf9fcf1a624ca7e90f0cc0a01dd04a0 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 22 Nov 2024 11:14:22 +0545 Subject: [PATCH 18/31] onIRC31Received ib lp transfer method, depositOfUser removed.. --- .../score/core/dex/DexIntegrationTest.java | 4 ++-- .../balanced/score/core/dex/AbstractDex.java | 18 ------------------ .../balanced/score/core/dex/DexImpl.java | 11 ++--------- .../core/dex/IRC31StandardSpokeLpToken.java | 10 +++++++++- .../balanced/score/lib/interfaces/Dex.java | 2 -- 5 files changed, 13 insertions(+), 32 deletions(-) diff --git a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java index 7cc52dbce..97dc444ae 100644 --- a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java +++ b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java @@ -223,11 +223,11 @@ void testWithdraw() { byte[] tokenDeposit = "{\"method\":\"_deposit\",\"params\":{\"none\":\"none\"}}".getBytes(); this.mintAndTransferTestTokens(tokenDeposit); BigInteger withdrawAMount = BigInteger.valueOf(50); - BigInteger balanceBeforeWithdraw = dexUserScoreClient.depositOfUser(userAddress, tokenAAddress); + BigInteger balanceBeforeWithdraw = dexUserScoreClient.getDeposit(userAddress, tokenAAddress); //withdraw test token dexUserScoreClient.withdraw(tokenAAddress, withdrawAMount); - BigInteger balanceAfterWithdraw = dexUserScoreClient.depositOfUser(userAddress, tokenAAddress); + BigInteger balanceAfterWithdraw = dexUserScoreClient.getDeposit(userAddress, tokenAAddress); assert balanceBeforeWithdraw.equals(balanceAfterWithdraw.add(withdrawAMount)); } 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 2f5ee1ac7..8556d1ebc 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 @@ -42,7 +42,6 @@ import static network.balanced.score.lib.utils.BalancedAddressManager.*; import static network.balanced.score.lib.utils.Check.onlyGovernance; import static network.balanced.score.lib.utils.Constants.*; -import static network.balanced.score.lib.utils.Math.pow; public abstract class AbstractDex extends IRC31StandardSpokeLpToken { @@ -97,10 +96,6 @@ public void RemoveV2(BigInteger _id, String _owner, BigInteger _value, BigIntege public void Deposit(Address _token, String _owner, BigInteger _value) { } -// @EventLog(indexed = 2) -// public void Withdraw(Address _token, Address _owner, BigInteger _value) { -// } - @EventLog(indexed = 2) public void Withdraw(Address _token, String _owner, BigInteger _value) { } @@ -500,10 +495,6 @@ public void delegate(PrepDelegations[] prepDelegations) { Context.call(getStaking(), "delegate", (Object) prepDelegations); } - private static BigInteger getPriceInUSD(String symbol) { - return (BigInteger) Context.call(getBalancedOracle(), "getLastPriceInUSD", symbol); - } - protected BigInteger getSicxRate() { return (BigInteger) Context.call(getStaking(), "getTodayRate"); } @@ -729,15 +720,6 @@ void swapIcx(Address sender, BigInteger value) { Context.transfer(sender, orderIcxValue); } - - private BigInteger getUnitValue(Address tokenAddress) { - if (tokenAddress == null) { - return EXA; - } else { - return pow(BigInteger.TEN, tokenPrecisions.get(tokenAddress).intValue()); - } - } - BigInteger snapshotValueAt(BigInteger _snapshot_id, BranchDB> snapshot) { Context.require(_snapshot_id.compareTo(BigInteger.ZERO) >= 0, diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index 1b21ab10b..ca007853a 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -139,7 +139,7 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { require(!unpackedData.equals(""), "Token Fallback: Data can't be empty"); JsonObject json = Json.parse(unpackedData).asObject(); String method = json.get("method").asString(); - Address fromToken = Context.getCaller(); + Address token = Context.getCaller(); require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Invalid token transfer value"); @@ -149,7 +149,7 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { if (params.get("address") != null) { to = params.get("address").asString(); } - deposit(fromToken, NetworkAddress.valueOf(to), _value); + deposit(token, NetworkAddress.valueOf(to), _value); } else { // If no supported method was sent, revert the transaction Context.revert(100, TAG + ": Unsupported method supplied"); @@ -264,13 +264,6 @@ private void _withdraw(NetworkAddress sender, Address _token, BigInteger _value) TokenTransfer.transfer(_token, sender.toString(), _value); } - @External(readonly = true) - public BigInteger depositOfUser(Address _owner, Address _token) { - NetworkAddress owner = new NetworkAddress(NATIVE_NID, _owner); - NetworkAddressDictDB depositDetails = deposit.at(_token); - return depositDetails.getOrDefault(owner, BigInteger.ZERO); - } - public void xRemove(String from, BigInteger id, BigInteger value, @Optional Boolean _withdraw) { NetworkAddress _from = NetworkAddress.valueOf(from); _remove(id, _from, value, _withdraw); diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java index 85833ea18..c965fe45b 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java @@ -120,7 +120,15 @@ void _transfer(NetworkAddress _from, NetworkAddress _to, BigInteger _value, Inte return; } - Context.call(contractAddress, "onXIRC31Received", _from.toString(), _from.toString(), _id, _value, dataBytes); + if(isNative(_from)){ + Context.call(contractAddress, "onIRC31Received", Address.fromString(_from.account()), Address.fromString(_from.account()), _id, _value, dataBytes); + }else { + Context.call(contractAddress, "onXIRC31Received", _from.toString(), _from.toString(), _id, _value, dataBytes); + } + } + + protected boolean isNative(NetworkAddress address) { + return address.net().equals(NATIVE_NID); } boolean isLockingPool(Integer id) { 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 f08ff4f9e..78eb9979d 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,7 +207,5 @@ void xAdd(String from, String _baseToken, String _quoteToken, BigInteger _baseVa @External void addLpAddresses(BigInteger _poolId, Address[] _addresses); - @External(readonly = true) - BigInteger depositOfUser(Address _owner, Address _token); } From 68d6cbf7f9f53db07fadd2a8d4528d08d6d9b484 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 22 Nov 2024 11:25:45 +0545 Subject: [PATCH 19/31] getDeposit method params position updated in dex inttest --- .../network/balanced/score/core/dex/DexIntegrationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java index 97dc444ae..01d10b323 100644 --- a/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java +++ b/core-contracts/Dex/src/intTest/java/network/balanced/score/core/dex/DexIntegrationTest.java @@ -223,11 +223,11 @@ void testWithdraw() { byte[] tokenDeposit = "{\"method\":\"_deposit\",\"params\":{\"none\":\"none\"}}".getBytes(); this.mintAndTransferTestTokens(tokenDeposit); BigInteger withdrawAMount = BigInteger.valueOf(50); - BigInteger balanceBeforeWithdraw = dexUserScoreClient.getDeposit(userAddress, tokenAAddress); + BigInteger balanceBeforeWithdraw = dexUserScoreClient.getDeposit(tokenAAddress, userAddress); //withdraw test token dexUserScoreClient.withdraw(tokenAAddress, withdrawAMount); - BigInteger balanceAfterWithdraw = dexUserScoreClient.getDeposit(userAddress, tokenAAddress); + BigInteger balanceAfterWithdraw = dexUserScoreClient.getDeposit(tokenAAddress, userAddress); assert balanceBeforeWithdraw.equals(balanceAfterWithdraw.add(withdrawAMount)); } From a00b28c4eef4a21cbafbb81d459767e197912742 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 22 Nov 2024 12:36:57 +0545 Subject: [PATCH 20/31] optional data on route methods - Router --- .../score/core/router/RouterImpl.java | 18 +++++-------- .../score/core/router/RouterTest.java | 26 +++++++++---------- .../balanced/score/lib/interfaces/Router.java | 6 ++++- 3 files changed, 25 insertions(+), 25 deletions(-) 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 a653f04c0..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 @@ -131,7 +131,7 @@ private void swapDefault(Address fromToken, Address toToken) { } } - private void route(String from, Address startToken, List _path, BigInteger _minReceive) { + private void route(String from, Address startToken, List _path, BigInteger _minReceive, byte[] data) { Address prevToken = null; Address currentToken = startToken; BigInteger fromAmount; @@ -167,10 +167,6 @@ private void route(String from, Address startToken, List _path, Big BigInteger balance = (BigInteger) Context.call(currentToken, "balanceOf", Context.getAddress()); Context.require(balance.compareTo(_minReceive) >= 0, TAG + ": Below minimum receive amount of " + _minReceive); - byte[] data = new byte[0]; - if (networkAddress.net().equals(nativeNid)) { - data = EMPTY_DATA; - } TokenTransfer.transfer(currentToken, networkAddress.toString(), balance, data); Route(fromAddress, fromAmount, currentToken, balance); @@ -179,7 +175,7 @@ private void route(String from, Address startToken, List _path, Big @Payable @External - public void route(Address[] _path, @Optional BigInteger _minReceive, @Optional String _receiver) { + public void route(Address[] _path, @Optional BigInteger _minReceive, @Optional String _receiver, @Optional byte[] _data) { Context.require(!inRoute); validateRoutePayload(_path.length, _minReceive); @@ -190,12 +186,12 @@ public void route(Address[] _path, @Optional BigInteger _minReceive, @Optional S for (Address path : _path) { routeActions.add(new RouteAction(1, path)); } - route(_receiver, null, routeActions, _minReceive); + route(_receiver, null, routeActions, _minReceive, _data); } @Payable @External - public void routeV2(byte[] _path, @Optional BigInteger _minReceive, @Optional String _receiver) { + public void routeV2(byte[] _path, @Optional BigInteger _minReceive, @Optional String _receiver, @Optional byte[] _data) { Context.require(!inRoute); List actions = Route.fromBytes(_path).actions; validateRoutePayload(actions.size(), _minReceive); @@ -203,7 +199,7 @@ public void routeV2(byte[] _path, @Optional BigInteger _minReceive, @Optional St _receiver = Context.getCaller().toString(); } - route(_receiver, null, actions, _minReceive); + route(_receiver, null, actions, _minReceive, _data); } private void validateRoutePayload(int _pathLength, BigInteger _minReceive) { @@ -266,7 +262,7 @@ private void executeRoute(String _from, byte[] data) { receiver = _from; } - route(receiver, fromToken, routeData.actions, minimumReceive); + route(receiver, fromToken, routeData.actions, minimumReceive, EMPTY_DATA); } private void jsonRoute(String _from, byte[] data) { @@ -312,7 +308,7 @@ private void jsonRoute(String _from, byte[] data) { } Address fromToken = Context.getCaller(); - route(receiver, fromToken, actions, minimumReceive); + route(receiver, fromToken, actions, minimumReceive, EMPTY_DATA); } @Payable diff --git a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java index dd172ab2e..dcd5823fd 100644 --- a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java +++ b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java @@ -80,7 +80,7 @@ void route() { Account balnToken = Account.newScoreAccount(scoreCount++); Address[] pathWithNonSicx = new Address[]{balnToken.getAddress()}; Executable nonSicxTrade = () -> sm.call(owner, icxToTrade, routerScore.getAddress(), "route", pathWithNonSicx, - BigInteger.ZERO, ""); + BigInteger.ZERO, "", "None".getBytes()); String expectedErrorMessage = "Reverted(0): " + TAG + ": ICX can only be traded for sICX"; expectErrorMessage(nonSicxTrade, expectedErrorMessage); @@ -90,7 +90,7 @@ void route() { } Executable maxTradeHops = () -> sm.call(owner, icxToTrade, routerScore.getAddress(), "route", - pathWithMoreHops, BigInteger.ZERO, ""); + pathWithMoreHops, BigInteger.ZERO, "", "None".getBytes()); expectedErrorMessage = "Reverted(0): " + TAG + ": Passed max swaps of " + MAX_NUMBER_OF_ITERATIONS; resetInRoute(); @@ -101,7 +101,7 @@ void route() { routerScore.getAccount().addBalance("ICX", icxToTrade); Executable lessThanMinimumReceivable = () -> sm.call(owner, icxToTrade, routerScore.getAddress(), "route", - path, icxToTrade.multiply(BigInteger.TWO), ""); + path, icxToTrade.multiply(BigInteger.TWO), "", "None".getBytes()); expectedErrorMessage = "Reverted(0): " + TAG + ": Below minimum receive amount of " + icxToTrade.multiply(BigInteger.TWO); @@ -111,11 +111,11 @@ void route() { routerScore.getAccount().addBalance("ICX", icxToTrade); resetInRoute(); sm.call(owner, icxToTrade, routerScore.getAddress(), "route", path, BigInteger.ZERO, - owner.getAddress().toString()); + owner.getAddress().toString(), "None".getBytes()); verify(sicxScore.mock).transfer(owner.getAddress(), icxToTrade, EMPTY_DATA); Executable negativeMinimumBalance = () -> sm.call(owner, icxToTrade, routerScore.getAddress(), - "route", path, icxToTrade.negate(), ""); + "route", path, icxToTrade.negate(), "", "None".getBytes()); expectedErrorMessage = "Reverted(0): " + TAG + ": Must specify a positive number for minimum to receive"; expectErrorMessage(negativeMinimumBalance, expectedErrorMessage); } @@ -243,7 +243,7 @@ void xTrade_WithdrawNotAllowed() throws Exception { routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); // Assert - verify(token.mock).hubTransfer(receiver.toString(), amount, new byte[0]); + verify(token.mock).hubTransfer(receiver.toString(), amount, "None".getBytes()); } @Test @@ -268,7 +268,7 @@ void xTrade_ToNetworkAddressWithDifferentNet() throws Exception { routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); // Assert - verify(token.mock).crossTransfer(receiver.toString(), amount, new byte[0]); + verify(token.mock).crossTransfer(receiver.toString(), amount, "None".getBytes()); } @Test @@ -289,7 +289,7 @@ void xTrade_ToBnUSD() throws Exception { routerScore.invoke(balanced.sicx.account, "tokenFallback", owner.getAddress(), amount, path); // Assert - verify(balanced.bnUSD.mock).crossTransfer(receiver.toString(), amount, new byte[0]); + verify(balanced.bnUSD.mock).crossTransfer(receiver.toString(), amount, "None".getBytes()); } @Test @@ -382,7 +382,7 @@ void routeV2_swap_icxSicx() { // Act Executable nonSicxTrade = () -> sm.call(owner, icxToTrade, routerScore.getAddress(), "routeV2", pathWithNonSicx, - BigInteger.ZERO, ""); + BigInteger.ZERO, "", "none".getBytes()); // Assert String expectedErrorMessage = "Reverted(0): " + TAG + ": ICX can only be traded for sICX"; @@ -402,7 +402,7 @@ void routeV2_swap_pathWithMoreHops() { // Act Executable maxTradeHops = () -> sm.call(owner, icxToTrade, routerScore.getAddress(), "routeV2", - pathWithMoreHops, BigInteger.ZERO, ""); + pathWithMoreHops, BigInteger.ZERO, "", "None".getBytes()); // Assert String expectedErrorMessage = "Reverted(0): " + TAG + ": Passed max swaps of " + MAX_NUMBER_OF_ITERATIONS; @@ -422,7 +422,7 @@ void routeV2_swap_belowMinimumReceive() { // Act Executable lessThanMinimumReceivable = () -> sm.call(owner, icxToTrade, routerScore.getAddress(), "routeV2", - path, icxToTrade.multiply(BigInteger.TWO), ""); + path, icxToTrade.multiply(BigInteger.TWO), "", "None".getBytes()); //Assert String expectedErrorMessage = "Reverted(0): " + TAG + ": Below minimum receive amount of " @@ -441,7 +441,7 @@ void routeV2_swap_positiveMinimumReceive() { // Act Executable negativeMinimumBalance = () -> sm.call(owner, icxToTrade, routerScore.getAddress(), - "routeV2", path, icxToTrade.negate(), ""); + "routeV2", path, icxToTrade.negate(), "", "None".getBytes()); // Assert String expectedErrorMessage = "Reverted(0): " + TAG + ": Must specify a positive number for minimum to receive"; @@ -470,7 +470,7 @@ void routeV2_swapStable() throws Exception { // Act sm.call(owner, icxToTrade, routerScore.getAddress(), "routeV2", - pathWithMoreHops, BigInteger.ZERO, ""); + pathWithMoreHops, BigInteger.ZERO, "", "None".getBytes()); // Assert int i = 0; diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Router.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Router.java index 654e43ccc..91b58b723 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Router.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Router.java @@ -37,5 +37,9 @@ public interface Router extends Name, AddressManager, @Payable @External - void route(Address[] path, @Optional BigInteger _minReceive, @Optional String _receiver); + void route(Address[] path, @Optional BigInteger _minReceive, @Optional String _receiver, @Optional byte[] _data); + + @Payable + @External + void routeV2(byte[] _path, @Optional BigInteger _minReceive, @Optional String _receiver, @Optional byte[] _data); } From 7a326cf081e9b90fee7291c45009bc95185970fa Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 22 Nov 2024 13:07:47 +0545 Subject: [PATCH 21/31] NetworkAddress Improvements --- .../main/java/network/balanced/score/core/dex/AbstractDex.java | 2 +- .../src/main/java/network/balanced/score/core/dex/DexImpl.java | 2 +- .../balanced/score/core/dex/IRC31StandardSpokeLpToken.java | 2 +- .../test/java/network/balanced/score/core/dex/DexTestBase.java | 2 +- .../java/network/balanced/score/core/stakedlp/StakedLPImpl.java | 2 +- .../java/network/balanced/score/lib/utils/TokenTransfer.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) 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 8556d1ebc..eefdbf0e6 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 @@ -264,7 +264,7 @@ public BigInteger getDeposit(Address _tokenAddress, Address _user) { @External(readonly = true) public BigInteger getDepositV2(Address _tokenAddress, String _user) { - NetworkAddress user = NetworkAddress.valueOf(_user); + NetworkAddress user = NetworkAddress.valueOf(_user, NATIVE_NID); return deposit.at(_tokenAddress).getOrDefault(user, BigInteger.ZERO); } diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index ca007853a..79ceee74e 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -340,7 +340,7 @@ public void xAdd(String from, String _baseToken, String _quoteToken, BigInteger checkStatus(); isValidPercent(_slippagePercentage.intValue()); - addInternal(NetworkAddress.parse(from), Address.fromString(_baseToken), Address.fromString(_quoteToken), _baseValue, _quoteValue, + addInternal(NetworkAddress.valueOf(from), Address.fromString(_baseToken), Address.fromString(_quoteToken), _baseValue, _quoteValue, _withdraw_unused, _slippagePercentage); } diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java index c965fe45b..a4285670b 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/IRC31StandardSpokeLpToken.java @@ -36,7 +36,7 @@ public BigInteger balanceOf(Address _owner, BigInteger _id) { @External(readonly = true) public BigInteger xBalanceOf(String _owner, BigInteger _id) { - NetworkAddress address = NetworkAddress.valueOf(_owner); + NetworkAddress address = NetworkAddress.valueOf(_owner, NATIVE_NID); return DexDBVariables.balance.at(_id.intValue()).getOrDefault(address, BigInteger.ZERO); } diff --git a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java index 9a4e5850d..e486e51d9 100644 --- a/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java +++ b/core-contracts/Dex/src/test/java/network/balanced/score/core/dex/DexTestBase.java @@ -118,7 +118,7 @@ protected void xDepositTokenWithoutTo(String depositor, String to, Account token * */ protected void handleCallMessageWithOutProtocols(String from, byte[] data, String[] protocols ) { - NetworkAddress fromNetworkAddress = NetworkAddress.parse(from); + NetworkAddress fromNetworkAddress = NetworkAddress.valueOf(from); contextMock.when(() -> Context.call(eq(BalancedAddressManager.getXCallManager()), eq("verifyProtocols"), eq(fromNetworkAddress.net()), eq(protocols))).thenReturn(true); dexScore.invoke(xcallScore, "handleCallMessage", from, data, protocols); } diff --git a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java index 8521a983f..4d3366ef5 100644 --- a/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java +++ b/core-contracts/StakedLP/src/main/java/network/balanced/score/core/stakedlp/StakedLPImpl.java @@ -130,7 +130,7 @@ public BigInteger balanceOf(Address _owner, BigInteger _id) { @External(readonly = true) public BigInteger xBalanceOf(String _owner, BigInteger _id) { - NetworkAddress owner = NetworkAddress.valueOf(_owner); + NetworkAddress owner = NetworkAddress.valueOf(_owner, NATIVE_NID); return poolStakedDetails.at(owner).getOrDefault(_id, BigInteger.ZERO); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java b/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java index 09561e198..94b65b681 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/TokenTransfer.java @@ -11,8 +11,8 @@ public class TokenTransfer { public static void transfer(Address token, String to, BigInteger amount, byte[] data){ - NetworkAddress toNetworkAddress = NetworkAddress.parse(to); String NATIVE_NID = (String) Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); + NetworkAddress toNetworkAddress = NetworkAddress.valueOf(to, NATIVE_NID); if(!NATIVE_NID.equals(toNetworkAddress.net())) { if(canWithdraw(toNetworkAddress.net())) { String nativeAddress = (String) Context.call(BalancedAddressManager.getAssetManager(), "getNativeAssetAddress", token, toNetworkAddress.net()); From 1f487caecaf1840d43b2a2afb13191491674d55a Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 22 Nov 2024 13:47:40 +0545 Subject: [PATCH 22/31] NetworkAddress missed - fixed --- .../src/main/java/network/balanced/score/core/dex/DexImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java index 79ceee74e..2e101bb50 100644 --- a/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java +++ b/core-contracts/Dex/src/main/java/network/balanced/score/core/dex/DexImpl.java @@ -149,7 +149,7 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { if (params.get("address") != null) { to = params.get("address").asString(); } - deposit(token, NetworkAddress.valueOf(to), _value); + deposit(token, NetworkAddress.valueOf(to, NATIVE_NID), _value); } else { // If no supported method was sent, revert the transaction Context.revert(100, TAG + ": Unsupported method supplied"); From db53648d7be00c357387e64383cb78f272e6d86c Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 26 Nov 2024 11:01:46 +0545 Subject: [PATCH 23/31] RouteData update to add data property, unit tests added for usdc staking --- .../score/core/router/RouterImpl.java | 13 +++- .../score/core/router/RouterTest.java | 67 ++++++++++++++----- .../score/core/savings/SavingsImpl.java | 3 - .../score/lib/interfaces/Savings.java | 1 - .../balanced/score/lib/structs/RouteData.java | 7 +- .../balanced/score/lib/utils/Versions.java | 4 +- 6 files changed, 68 insertions(+), 27 deletions(-) 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 a321f6f53..6f67d8f1b 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,8 +261,11 @@ private void executeRoute(String _from, byte[] data) { } else { receiver = _from; } - - route(receiver, fromToken, routeData.actions, minimumReceive, EMPTY_DATA); + byte[] _data = EMPTY_DATA; + if(routeData.data!=null){ + _data = routeData.data; + } + route(receiver, fromToken, routeData.actions, minimumReceive, _data); } private void jsonRoute(String _from, byte[] data) { @@ -308,7 +311,11 @@ private void jsonRoute(String _from, byte[] data) { } Address fromToken = Context.getCaller(); - route(receiver, fromToken, actions, minimumReceive, EMPTY_DATA); + byte[] _data = EMPTY_DATA; + if(params.get("data")!=null){ + _data = params.get("data").asString().getBytes(); + } + route(receiver, fromToken, actions, minimumReceive, _data); } @Payable diff --git a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java index dcd5823fd..dc21c299d 100644 --- a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java +++ b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java @@ -28,14 +28,10 @@ import network.balanced.score.lib.structs.RouteData; import network.balanced.score.lib.test.mock.MockBalanced; import network.balanced.score.lib.test.mock.MockContract; -import network.balanced.score.lib.tokens.HubTokenImpl; -import network.balanced.score.lib.tokens.IRC2Base; -import network.balanced.score.lib.tokens.IRC2Mintable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; import score.Address; -import score.Context; import scorex.util.ArrayList; import java.math.BigInteger; @@ -44,11 +40,8 @@ import static network.balanced.score.core.router.RouterImpl.*; import static network.balanced.score.lib.test.UnitTest.*; -import static network.balanced.score.lib.utils.Constants.EXA; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -182,14 +175,7 @@ void tokenFallback() throws Exception { when(balanced.baln.mock.balanceOf(routerScore.getAddress())).thenReturn(BigInteger.TEN); when(balanced.sicx.mock.balanceOf(routerScore.getAddress())).thenReturn(BigInteger.TEN); -// byte[] invalidPathWithSicxTerminalToken = tokenData("_swap", Map.of("path", -// new Object[]{balanced.baln.getAddress().toString(), null})); -// Executable nonSicxIcxTrade = () -> routerScore.invoke(sicxScore.account, "tokenFallback", owner.getAddress(), -// BigInteger.TEN, invalidPathWithSicxTerminalToken); -// expectedErrorMessage = "Reverted(0): " + TAG + ": Native swaps not available to icon from " + balanced.baln.getAddress(); -// expectErrorMessage(nonSicxIcxTrade, expectedErrorMessage); -// -// resetInRoute(); + Account newReceiver = sm.createAccount(); byte[] pathWithSicxTerminalToken = tokenData("_swap", Map.of("path", new Object[]{sicxScore.getAddress().toString(), null}, "receiver", @@ -501,7 +487,7 @@ void tokenFallback_swapStable() throws Exception { } Account newReceiver = sm.createAccount(); - byte[] data = new RouteData("_swap", newReceiver.getAddress().toString(), BigInteger.ZERO, actions).toBytes(); + byte[] data = new RouteData("_swap", newReceiver.getAddress().toString(), BigInteger.ZERO, actions, null).toBytes(); // Act routerScore.invoke(balanced.baln.account, "tokenFallback", owner.getAddress(), balnToSwap, @@ -531,7 +517,7 @@ void tokenFallback_swapToICX() throws Exception { routerScore.getAccount().addBalance("ICX", ICXResult); Account newReceiver = sm.createAccount(); - byte[] data = new RouteData("_swap", newReceiver.getAddress().toString(), BigInteger.ZERO, actions).toBytes(); + byte[] data = new RouteData("_swap", newReceiver.getAddress().toString(), BigInteger.ZERO, actions, null).toBytes(); // Act routerScore.invoke(balanced.baln.account, "tokenFallback", owner.getAddress(), USDToSwap, @@ -586,4 +572,51 @@ private void resetInRoute() { // in Production this happens between each tx ((RouterImpl)routerScore.getInstance()).inRoute = false; } + + @Test + void stakeToSavingsWithJSONRoute(){ + // Arrange + //baln as usdc + when(balanced.baln.mock.balanceOf(routerScore.getAddress())).thenReturn(BigInteger.TEN); + when(balanced.bnUSD.mock.balanceOf(routerScore.getAddress())).thenReturn(BigInteger.TEN); + + String data = new String(tokenData("_lock", Map.of())); + Account newReceiver = balanced.savings.account; + byte[] pathWithUSDCBnUSD = tokenData("_swap", Map.of("path", + new Object[]{balanced.bnUSD.getAddress().toString()}, "receiver", + newReceiver.getAddress().toString(), "data", data)); + + // Act + routerScore.invoke(balanced.baln.account, "tokenFallback", owner.getAddress(), BigInteger.TEN, + pathWithUSDCBnUSD); + + + // Verify + verify(balanced.bnUSD.mock).transfer(balanced.savings.getAddress(), BigInteger.TEN, data.getBytes()); + } + + @Test + void stakeToSavingsWithRLPData(){ + // Arrange + //baln as usdc + BigInteger balnToSwap = BigInteger.TEN.multiply(ICX); + when(balanced.baln.mock.balanceOf(routerScore.getAddress())).thenReturn(balnToSwap); + when(balanced.bnUSD.mock.balanceOf(routerScore.getAddress())).thenReturn(balnToSwap); + + List actions = new ArrayList<>(1); + actions.add(new RouteAction(SWAP, balanced.bnUSD.getAddress())); + + byte[] data = tokenData("_lock", Map.of()); + Account newReceiver = balanced.savings.account; + byte[] routeData = new RouteData("_swap", newReceiver.getAddress().toString(), BigInteger.ZERO, actions, data).toBytes(); + + // Act + routerScore.invoke(balanced.baln.account, "tokenFallback", owner.getAddress(), balnToSwap, + routeData); + + + // Verify + verify(balanced.bnUSD.mock).transfer(balanced.savings.getAddress(), balnToSwap, data); + } + } diff --git a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java index 838ba26be..ef5d7149b 100644 --- a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java +++ b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java @@ -23,7 +23,6 @@ import static network.balanced.score.lib.utils.BalancedAddressManager.resetAddress; import static network.balanced.score.lib.utils.Check.checkStatus; import static network.balanced.score.lib.utils.Check.onlyGovernance; -import static network.balanced.score.lib.utils.Constants.EXA; import java.math.BigInteger; import java.util.Map; @@ -45,12 +44,10 @@ import score.annotation.External; public class SavingsImpl extends FloorLimited implements Savings { - public static final String LOCKED_SAVINGS = "Locked savings"; public static final String VERSION = "version"; private static final DictDB totalPayout = Context.newDictDB("TOTAL_PAYOUT", BigInteger.class); private final VarDB currentVersion = Context.newVarDB(VERSION, String.class); - public static final String TAG = Names.SAVINGS; public SavingsImpl(Address _governance) { BalancedAddressManager.setGovernance(_governance); diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java index a92a41635..8fc7e6875 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java @@ -21,7 +21,6 @@ import network.balanced.score.lib.interfaces.addresses.AddressManager; import network.balanced.score.lib.interfaces.base.Name; import network.balanced.score.lib.interfaces.base.Version; -import network.balanced.score.lib.interfaces.tokens.XTokenReceiver; import score.annotation.External; import score.Address; diff --git a/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java b/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java index 8b3194b2d..1c07e7c44 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java +++ b/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java @@ -12,13 +12,16 @@ public class RouteData { public String method; public String receiver; public BigInteger minimumReceive; + public byte[] data; public List actions; + public RouteData(){} - public RouteData(String method, String receiver, BigInteger minimumReceive, List actions) { + public RouteData(String method, String receiver, BigInteger minimumReceive, List actions, byte[] data) { this.method = method; this.receiver = receiver; this.minimumReceive = minimumReceive; + this.data = data; this.actions = actions; } @@ -34,6 +37,7 @@ public static RouteData readObject(ObjectReader reader) { obj.method = reader.readString(); obj.receiver = reader.readNullable(String.class); obj.minimumReceive = reader.readNullable((BigInteger.class)); + obj.data = reader.readNullable(byte[].class); while (reader.hasNext()) { RouteAction data = reader.read(RouteAction.class); actions.add(data); @@ -48,6 +52,7 @@ public static void writeObject(ObjectWriter w, RouteData obj) { w.write(obj.method); w.writeNullable(obj.receiver); w.writeNullable(obj.minimumReceive); + w.writeNullable(obj.data); for (RouteAction action : obj.actions) { w.write(action); } diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java index 6b40dc0c8..24bc3744f 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java @@ -33,7 +33,7 @@ public class Versions { public final static String DEX = "v1.1.8"; public final static String GOVERNANCE = "v1.0.2"; public final static String REBALANCING = "v1.0.0"; - public final static String ROUTER = "v1.1.8"; + public final static String ROUTER = "v1.1.9"; public final static String STAKEDLP = "v1.0.8"; public final static String BOOSTED_BALN = "v1.1.0"; public final static String BRIBING = "v1.0.1"; @@ -42,7 +42,7 @@ public class Versions { public final static String BALANCED_ASSET_MANAGER = "v1.0.6"; public final static String XCALL_MANAGER = "v1.0.2"; public final static String BURNER = "v1.0.0"; - public final static String SAVINGS = "v1.0.0"; + public final static String SAVINGS = "v1.0.1"; public final static String TRICKLER = "v1.0.0"; public final static String SPOKE_ASSET_MANAGER = "v1.0.2"; From 53056e115549696be0c0a25debdef530da1b525d Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 26 Nov 2024 13:39:58 +0545 Subject: [PATCH 24/31] crosschain lp functionalities and unitest --- core-contracts/Savings/build.gradle | 1 + .../score/core/savings/RewardsManager.java | 16 +-- .../score/core/savings/SavingsImpl.java | 37 ++++-- .../score/core/savings/SavingsTest.java | 122 ++++++++++++++++++ .../score/lib/interfaces/Savings.java | 4 + 5 files changed, 160 insertions(+), 20 deletions(-) diff --git a/core-contracts/Savings/build.gradle b/core-contracts/Savings/build.gradle index 4ac6a4273..522cfad9a 100644 --- a/core-contracts/Savings/build.gradle +++ b/core-contracts/Savings/build.gradle @@ -30,6 +30,7 @@ dependencies { implementation Dependencies.javaeeScorex implementation Dependencies.minimalJson implementation project(':score-lib') + implementation 'xyz.venture23:xcall-lib:2.1.0' testImplementation Dependencies.javaeeUnitTest testImplementation Dependencies.javaeeTokens diff --git a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/RewardsManager.java b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/RewardsManager.java index 1a2f6329e..92c44f324 100644 --- a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/RewardsManager.java +++ b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/RewardsManager.java @@ -8,6 +8,7 @@ import network.balanced.score.lib.utils.BalancedFloorLimits; import network.balanced.score.lib.utils.EnumerableSetDB; +import network.balanced.score.lib.utils.TokenTransfer; import score.Address; import score.BranchDB; import score.Context; @@ -74,7 +75,6 @@ public static void addWeight(Address token, BigInteger amount) { } public static void changeLock(String user, BigInteger change) { - checkAddressIsICON(user); BigInteger prevAmount = workingBalance.getOrDefault(user, BigInteger.ZERO); BigInteger prevTotal = totalWorkingBalance.getOrDefault(BigInteger.ZERO); updateAllUserRewards(user, prevAmount); @@ -85,10 +85,10 @@ public static void changeLock(String user, BigInteger change) { totalWorkingBalance.set(prevTotal.add(change)); } - public static void claimRewards(Address user) { - updateAllUserRewards(user.toString()); + public static void claimRewards(String user) { + updateAllUserRewards(user); int numberOfTokens = allowedTokens.length(); - DictDB rewards = userRewards.at(user.toString()); + DictDB rewards = userRewards.at(user); for (int i = 0; i < numberOfTokens; i++) { Address token = allowedTokens.at(i); @@ -96,7 +96,7 @@ public static void claimRewards(Address user) { rewards.set(token, null); BalancedFloorLimits.verifyWithdraw(token, amount); if (!amount.equals(BigInteger.ZERO)) { - Context.call(token, "transfer", user, amount, new byte[0]); + TokenTransfer.transfer(token, user, amount, new byte[0]); } } } @@ -130,10 +130,4 @@ public static void removeToken(Address token) { allowedTokens.remove(token); } - // For now only allow ICON addresses to lock - // But keep as string to allow it in the future easily - private static void checkAddressIsICON(String str) { - Context.require(str.length() == Address.LENGTH * 2, "Only ICON addresses are allowed to lock into the saving account at this time"); - Context.require(str.startsWith("hx") || str.startsWith("cx"), "Only ICON addresses are allowed to lock into the saving account at this time"); - } } diff --git a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java index ef5d7149b..a4fa3c76c 100644 --- a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java +++ b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java @@ -21,8 +21,7 @@ import static network.balanced.score.lib.utils.BalancedAddressManager.getLoans; import static network.balanced.score.lib.utils.BalancedAddressManager.getTrickler; import static network.balanced.score.lib.utils.BalancedAddressManager.resetAddress; -import static network.balanced.score.lib.utils.Check.checkStatus; -import static network.balanced.score.lib.utils.Check.onlyGovernance; +import static network.balanced.score.lib.utils.Check.*; import java.math.BigInteger; import java.util.Map; @@ -30,18 +29,17 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; -import network.balanced.score.lib.utils.BalancedAddressManager; -import network.balanced.score.lib.utils.Names; -import network.balanced.score.lib.utils.Versions; +import network.balanced.score.lib.interfaces.RewardsXCall; +import network.balanced.score.lib.interfaces.SavingsXCall; +import network.balanced.score.lib.utils.*; import network.balanced.score.lib.interfaces.Savings; -import network.balanced.score.lib.utils.FloorLimited; -import network.balanced.score.lib.utils.BalancedFloorLimits; import score.Address; import score.Context; import score.VarDB; import score.DictDB; import score.annotation.External; +import score.annotation.Optional; public class SavingsImpl extends FloorLimited implements Savings { public static final String VERSION = "version"; @@ -104,10 +102,23 @@ public void unlock(BigInteger amount) { Context.call(bnUSD, "transfer", Context.getCaller(), amount, new byte[0]); } + @External + public void handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) { + checkStatus(); + only(BalancedAddressManager.getXCall()); + XCallUtils.verifyXCallProtocols(_from, _protocols); + SavingsXCall.process(this, _from, _data); + } + + public void xClaimRewards(String from) { + gatherRewards(); + RewardsManager.claimRewards(from); + } + @External public void claimRewards() { gatherRewards(); - RewardsManager.claimRewards(Context.getCaller()); + RewardsManager.claimRewards(Context.getCaller().toString()); } @External(readonly = true) @@ -142,6 +153,11 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { handleTokenDeposit(_from.toString(), _value, _data); } + @External + public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { + handleTokenDeposit(_from, _value, _data); + } + private void handleTokenDeposit(String _from, BigInteger _value, byte[] _data) { checkStatus(); Context.require(_value.compareTo(BigInteger.ZERO) > 0, "Zero transfers not allowed"); @@ -156,8 +172,11 @@ private void handleTokenDeposit(String _from, BigInteger _value, byte[] _data) { String unpackedData = new String(_data); Context.require(!unpackedData.equals(""), "Token Fallback: Data can't be empty"); JsonObject json = Json.parse(unpackedData).asObject(); - String method = json.get("method").asString(); + JsonObject params = json.get("params").asObject(); + if(params.get("to")!=null){ + _from = params.get("to").asString(); + } switch (method) { case "_lock": { Context.require(token.equals(getBnusd()), "Only BnUSD can be locked"); diff --git a/core-contracts/Savings/src/test/java/network/balanced/score/core/savings/SavingsTest.java b/core-contracts/Savings/src/test/java/network/balanced/score/core/savings/SavingsTest.java index d4f054a76..d010afdde 100644 --- a/core-contracts/Savings/src/test/java/network/balanced/score/core/savings/SavingsTest.java +++ b/core-contracts/Savings/src/test/java/network/balanced/score/core/savings/SavingsTest.java @@ -19,11 +19,15 @@ import com.iconloop.score.test.Account; import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; +import foundation.icon.xcall.NetworkAddress; import network.balanced.score.lib.test.UnitTest; import network.balanced.score.lib.test.mock.MockBalanced; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; +import score.Address; +import score.ByteArrayObjectWriter; +import score.Context; import java.math.BigInteger; import java.util.Map; @@ -41,15 +45,18 @@ class SavingsTest extends UnitTest { private MockBalanced mockBalanced; private Score savings; + private final String NATIVE_NID = "0x1.ICON"; @BeforeEach void setup() throws Exception { mockBalanced = new MockBalanced(sm, owner); + when(mockBalanced.xCall.mock.getNetworkId()).thenReturn(NATIVE_NID); savings = sm.deploy(owner, SavingsImpl.class, mockBalanced.governance.getAddress()); savings.invoke(mockBalanced.governance.account, "addAcceptedToken", mockBalanced.sicx.getAddress()); savings.invoke(mockBalanced.governance.account, "addAcceptedToken", mockBalanced.baln.getAddress()); savings.invoke(mockBalanced.governance.account, "addAcceptedToken", mockBalanced.bnUSD.getAddress()); + } @Test @@ -208,4 +215,119 @@ void permissions() { assertOnlyCallableBy(mockBalanced.governance.getAddress(), savings, "addAcceptedToken", mockBalanced.sicx.getAddress()); assertOnlyCallableBy(mockBalanced.governance.getAddress(), savings, "removeAcceptedToken", mockBalanced.sicx.getAddress()); } + + @Test + void lockCrosschainBnUSDWithOutTo() { + //Arrange + String user = new NetworkAddress("0x1.ETH", "0x120").toString(); + BigInteger lockAmount = BigInteger.valueOf(100).multiply(EXA); + + // Act + byte[] data = tokenData("_lock", Map.of()); + savings.invoke(mockBalanced.bnUSD.account, "xTokenFallback", user, lockAmount, data); + + // Assert + BigInteger amountLocked = (BigInteger) savings.call("getLockedAmount", user); + assertEquals(lockAmount, amountLocked); + } + + @Test + void lockCrosschainBnUSDWithTo() { + //Arrange + String user = new NetworkAddress("0x1.ETH", "0x120").toString(); + String toUser = new NetworkAddress("0x1.ETH", "0x121").toString(); + BigInteger lockAmount = BigInteger.valueOf(100).multiply(EXA); + + // Act + byte[] data = tokenData("_lock", Map.of("to", toUser )); + savings.invoke(mockBalanced.bnUSD.account, "xTokenFallback", user, lockAmount, data); + + // Assert + BigInteger amountLocked = (BigInteger) savings.call("getLockedAmount", toUser); + assertEquals(lockAmount, amountLocked); + } + + @Test + @SuppressWarnings("unchecked") + void crossChainClaimRewards() { + //Arrange + String user1 = new NetworkAddress("0x1.ETH", "0x120").toString(); + String user2 = new NetworkAddress("0x1.ETH", "0x121").toString(); + String user3 = new NetworkAddress("0x1.ETH", "0x122").toString(); + BigInteger lockAmount1 = BigInteger.valueOf(100).multiply(EXA); + BigInteger lockAmount2 = BigInteger.valueOf(200).multiply(EXA); + BigInteger lockAmount3 = BigInteger.valueOf(200).multiply(EXA); + + byte[] data = tokenData("_lock", Map.of()); + savings.invoke(mockBalanced.bnUSD.account, "xTokenFallback", user1, lockAmount1, data); + savings.invoke(mockBalanced.bnUSD.account, "xTokenFallback", user2, lockAmount2, data); + + // Act + BigInteger balnRewards = BigInteger.valueOf(100).multiply(EXA); + BigInteger sICXRewards = BigInteger.valueOf(100).multiply(EXA); + BigInteger bnUSDRewards = BigInteger.valueOf(2000).multiply(EXA); + savings.invoke(mockBalanced.baln.account, "tokenFallback", mockBalanced.daofund.getAddress(), balnRewards, new byte[0]); + savings.invoke(mockBalanced.sicx.account, "tokenFallback", mockBalanced.daofund.getAddress(), sICXRewards, new byte[0]); + savings.invoke(mockBalanced.bnUSD.account, "tokenFallback", mockBalanced.daofund.getAddress(), bnUSDRewards, new byte[0]); + savings.invoke(mockBalanced.bnUSD.account, "xTokenFallback", user3, lockAmount3, data); + + // Assert + Map rewards1 = (Map) savings.call("getUnclaimedRewards", user1); + Map rewards2 = (Map) savings.call("getUnclaimedRewards", user2); + Map rewards3 = (Map) savings.call("getUnclaimedRewards", user3); + + BigInteger total = lockAmount1.add(lockAmount2); + BigInteger sICXWeight = sICXRewards.multiply(EXA).divide(total); + BigInteger balnWeight = balnRewards.multiply(EXA).divide(total); + BigInteger bnUSDWeight = bnUSDRewards.multiply(EXA).divide(total); + assertEquals(sICXWeight.multiply(lockAmount1).divide(EXA), rewards1.get(mockBalanced.sicx.getAddress().toString())); + assertEquals(balnWeight.multiply(lockAmount1).divide(EXA), rewards1.get(mockBalanced.baln.getAddress().toString())); + assertEquals(bnUSDWeight.multiply(lockAmount1).divide(EXA), rewards1.get(mockBalanced.bnUSD.getAddress().toString())); + assertEquals(sICXWeight.multiply(lockAmount2).divide(EXA), rewards2.get(mockBalanced.sicx.getAddress().toString())); + assertEquals(balnWeight.multiply(lockAmount2).divide(EXA), rewards2.get(mockBalanced.baln.getAddress().toString())); + assertEquals(bnUSDWeight.multiply(lockAmount2).divide(EXA), rewards2.get(mockBalanced.bnUSD.getAddress().toString())); + assertEquals(BigInteger.ZERO, rewards3.get(mockBalanced.sicx.getAddress().toString())); + assertEquals(BigInteger.ZERO, rewards3.get(mockBalanced.baln.getAddress().toString())); + assertEquals(BigInteger.ZERO, rewards3.get(mockBalanced.bnUSD.getAddress().toString())); + + + // Act + savings.invoke(mockBalanced.baln.account, "tokenFallback", mockBalanced.daofund.getAddress(), balnRewards, new byte[0]); + savings.invoke(mockBalanced.sicx.account, "tokenFallback", mockBalanced.daofund.getAddress(), sICXRewards, new byte[0]); + + // Assert + rewards1 = (Map) savings.call("getUnclaimedRewards", user1); + rewards2 = (Map) savings.call("getUnclaimedRewards", user2); + rewards3 = (Map) savings.call("getUnclaimedRewards", user3); + + BigInteger newTotal = lockAmount1.add(lockAmount2).add(lockAmount3); + BigInteger newSICXWeight = sICXWeight.add(sICXRewards.multiply(EXA).divide(newTotal)); + BigInteger newBalnWeight = balnWeight.add(balnRewards.multiply(EXA).divide(newTotal)); + assertEquals(newSICXWeight.multiply(lockAmount1).divide(EXA), rewards1.get(mockBalanced.sicx.getAddress().toString())); + assertEquals(newBalnWeight.multiply(lockAmount1).divide(EXA), rewards1.get(mockBalanced.baln.getAddress().toString())); + assertEquals(newSICXWeight.multiply(lockAmount2).divide(EXA), rewards2.get(mockBalanced.sicx.getAddress().toString())); + assertEquals(newBalnWeight.multiply(lockAmount2).divide(EXA), rewards2.get(mockBalanced.baln.getAddress().toString())); + assertEquals(newSICXWeight.subtract(sICXWeight).multiply(lockAmount3).divide(EXA), rewards3.get(mockBalanced.sicx.getAddress().toString())); + assertEquals(newBalnWeight.subtract(balnWeight).multiply(lockAmount3).divide(EXA), rewards3.get(mockBalanced.baln.getAddress().toString())); + + assertEquals(sICXRewards.multiply(BigInteger.TWO), savings.call("getTotalPayout", mockBalanced.sicx.getAddress())); + assertEquals(balnRewards.multiply(BigInteger.TWO), savings.call("getTotalPayout", mockBalanced.baln.getAddress())); + assertEquals(bnUSDRewards, savings.call("getTotalPayout", mockBalanced.bnUSD.getAddress())); + + // Act + when(mockBalanced.daofund.mock.getXCallFeePermission(any(Address.class), any(String.class))).thenReturn(true); + savings.invoke(mockBalanced.xCall.account, "handleCallMessage", user1, getClaimRewardsData(), new String[0]); + + // Assert + verify(mockBalanced.sicx.mock).crossTransfer(user1, rewards1.get(mockBalanced.sicx.getAddress().toString()), new byte[0]); + verify(mockBalanced.baln.mock).crossTransfer(user1, rewards1.get(mockBalanced.baln.getAddress().toString()), new byte[0]); + } + + static byte[] getClaimRewardsData() { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(1); + writer.write("xclaimrewards"); + writer.end(); + return writer.toByteArray(); + } } \ No newline at end of file diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java index 8fc7e6875..a8597c04e 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java @@ -18,11 +18,13 @@ import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; +import network.balanced.score.lib.annotations.XCall; import network.balanced.score.lib.interfaces.addresses.AddressManager; import network.balanced.score.lib.interfaces.base.Name; import network.balanced.score.lib.interfaces.base.Version; import score.annotation.External; import score.Address; +import score.annotation.Optional; import java.math.BigInteger; import java.util.Map; @@ -39,6 +41,8 @@ public interface Savings extends Name, Version, AddressManager, FloorLimitedInte @External(readonly = true) BigInteger getTotalPayout(Address token); + @XCall + void xClaimRewards(String from); @External void claimRewards(); From b7ea1fcd80e693e642199e8df3e9e70dc311641f Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 29 Nov 2024 11:15:48 +0545 Subject: [PATCH 25/31] int test completed --- .../core/savings/SavingsIntegrationTest.java | 188 +++++++++++++++++- .../score/core/savings/SavingsImpl.java | 33 ++- .../score/core/savings/SavingsTest.java | 28 ++- .../score/lib/interfaces/Savings.java | 3 + 4 files changed, 238 insertions(+), 14 deletions(-) diff --git a/core-contracts/Savings/src/intTest/java/network/balanced/score/core/savings/SavingsIntegrationTest.java b/core-contracts/Savings/src/intTest/java/network/balanced/score/core/savings/SavingsIntegrationTest.java index 2276fe7b9..0b0faec7c 100644 --- a/core-contracts/Savings/src/intTest/java/network/balanced/score/core/savings/SavingsIntegrationTest.java +++ b/core-contracts/Savings/src/intTest/java/network/balanced/score/core/savings/SavingsIntegrationTest.java @@ -24,15 +24,19 @@ import network.balanced.score.lib.test.integration.ScoreIntegrationTest; import network.balanced.score.lib.interfaces.*; + import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import score.Address; import foundation.icon.xcall.NetworkAddress; +import score.ByteArrayObjectWriter; +import score.Context; import java.math.BigInteger; import java.time.Instant; +import java.util.HashMap; import java.util.Map; import static network.balanced.score.lib.test.integration.BalancedUtils.*; @@ -125,6 +129,7 @@ static void setup() throws Exception { // set initial rate to 1 USD updatePrice(rate); + addCollateral(balanced.ethBaseAsset, "ETH"); } @Test @@ -134,7 +139,6 @@ void takeLoanAndLockInSavings() throws Exception { BigInteger loanAmount = BigInteger.TEN.pow(21); user.stakeDepositAndBorrow(collateralAmount, loanAmount); - JsonObject deposit = new JsonObject().add("method", "_deposit"); JsonObject lock = new JsonObject().add("method", "_lock"); user.bnUSD.transfer(balanced.savings._address(), loanAmount, lock.toString().getBytes()); @@ -285,7 +289,7 @@ void depositYieldAssetToStability() throws Exception { @Test @Order(7) - void withdrawYieldAssetFromStability() throws Exception { + void withdrawYieldAssetFromStability() { // Arrange BigInteger collateralAmount = BigInteger.TEN.pow(22); BigInteger amount = BigInteger.TEN.pow(20); @@ -307,6 +311,150 @@ void withdrawYieldAssetFromStability() throws Exception { assertEquals(prevYield, reader.feeHandler.getStabilityFundYieldFeesAccrued()); } + private static void addCollateral(foundation.icon.jsonrpc.Address collateralAddress, String peg) { + BigInteger lockingRatio = BigInteger.valueOf(40_000); + BigInteger debtCeiling = BigInteger.TEN.pow(30); + + BigInteger liquidationRatio = BigInteger.valueOf(14_000); + BigInteger liquidatorFee = BigInteger.valueOf(800); + BigInteger daofundFee = BigInteger.valueOf(200); + + JsonArray addCollateralParameters = new JsonArray() + .add(createParameter(collateralAddress)) + .add(createParameter(true)) + .add(createParameter(peg)) + .add(createParameter(lockingRatio)) + .add(createParameter(debtCeiling)) + .add(createParameter(liquidationRatio)) + .add(createParameter(liquidatorFee)) + .add(createParameter(daofundFee)); + + JsonArray actions = new JsonArray() + .add(createTransaction(balanced.governance._address(), "addCollateral", addCollateralParameters)); + + String symbol = reader.irc2(collateralAddress).symbol(); + owner.governance.execute(actions.toString()); + + assertEquals(lockingRatio, reader.loans.getLockingRatio(symbol)); + assertEquals(debtCeiling, reader.loans.getDebtCeiling(symbol)); + } + + @Test + @Order(8) + void crossChainLock(){ + + // Arrange - prepare accounts + NetworkAddress ethBnUSD = new NetworkAddress(balanced.ETH_NID, balanced.ETH_BNUSD_ADDRESS); + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + String savingsAddress = new NetworkAddress(balanced.ICON_NID, balanced.savings._address()).toString(); + String loanAddress = new NetworkAddress(balanced.ICON_NID, balanced.loans._address()).toString(); + BigInteger loanAmount = BigInteger.valueOf(20).multiply(EXA); + + // Arrange - deposit and borrow bnUSD loan + JsonObject loanData = new JsonObject() + .add("_amount", loanAmount.toString()); + byte[] depositAndBorrowETH = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, "0x123", loanAddress, BigInteger.valueOf(200).multiply(EXA), loanData.toString().getBytes()); + owner.xcall.recvCall(balanced.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), depositAndBorrowETH); + + // Arrange - prepare data + byte[] data = tokenData("_lock", new JsonObject()); + byte[] lockData = getCrossTransferData(ethAccount.toString(), savingsAddress, loanAmount, data); + + // Act + owner.xcall.recvCall(owner.bnUSD._address(), ethBnUSD.toString(), lockData); + + //Verify + BigInteger lockedAmount = owner.savings.getLockedAmount(ethAccount.toString()); + assertEquals(lockedAmount, loanAmount); + + } + + @Test + @Order(9) + void crossChainClaimRewards(){ + + // Arrange - prepare accounts + NetworkAddress ethBnUSD = new NetworkAddress(balanced.ETH_NID, balanced.ETH_BNUSD_ADDRESS); + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + String savingsAddress = new NetworkAddress(balanced.ICON_NID, balanced.savings._address()).toString(); + String loanAddress = new NetworkAddress(balanced.ICON_NID, balanced.loans._address()).toString(); + BigInteger loanAmount = BigInteger.valueOf(20).multiply(EXA); + + // Arrange - deposit and borrow bnUSD loan + JsonObject loanData = new JsonObject() + .add("_amount", loanAmount.toString()); + byte[] depositAndBorrowETH = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, "0x123", loanAddress, BigInteger.valueOf(200).multiply(EXA), loanData.toString().getBytes()); + owner.xcall.recvCall(balanced.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), depositAndBorrowETH); + + // Arrange - prepare data + byte[] data = tokenData("_lock", new JsonObject()); + byte[] lockData = getCrossTransferData(ethAccount.toString(), savingsAddress, loanAmount, data); + + // Arrange - lock bnUSD + owner.xcall.recvCall(owner.bnUSD._address(), ethBnUSD.toString(), lockData); + + // Arrange - set xcall fee permission + JsonArray setXCallFeePermissionParameters = new JsonArray() + .add(createParameter(balanced.savings._address())).add(createParameter(balanced.ETH_NID)).add(createParameter(true)); + JsonArray actions = new JsonArray() + .add(createTransaction(balanced.daofund._address(), "setXCallFeePermission", setXCallFeePermissionParameters)); + owner.governance.execute(actions.toString()); + + // Act + afterNextDays(2); + owner.xcall.recvCall(owner.savings._address(), ethAccount.toString(), getClaimRewardsData()); + + // Verify + + } + + @Test + @Order(10) + void crossChainUnlock(){ + + // Arrange - prepare accounts + NetworkAddress ethBnUSD = new NetworkAddress(balanced.ETH_NID, balanced.ETH_BNUSD_ADDRESS); + NetworkAddress ethAccount = new NetworkAddress(balanced.ETH_NID, "0x123"); + String savingsAddress = new NetworkAddress(balanced.ICON_NID, balanced.savings._address()).toString(); + String loanAddress = new NetworkAddress(balanced.ICON_NID, balanced.loans._address()).toString(); + BigInteger loanAmount = BigInteger.valueOf(20).multiply(EXA); + + // Arrange - deposit and borrow bnUSD loan + JsonObject loanData = new JsonObject() + .add("_amount", loanAmount.toString()); + byte[] depositAndBorrowETH = AssetManagerMessages.deposit(balanced.ETH_TOKEN_ADDRESS, "0x123", loanAddress, BigInteger.valueOf(200).multiply(EXA), loanData.toString().getBytes()); + owner.xcall.recvCall(balanced.assetManager._address(), new NetworkAddress(balanced.ETH_NID, balanced.ETH_ASSET_MANAGER).toString(), depositAndBorrowETH); + + // Arrange - prepare data + byte[] data = tokenData("_lock", new JsonObject()); + byte[] lockData = getCrossTransferData(ethAccount.toString(), savingsAddress, loanAmount, data); + + // Arrange - lock bnUSD + owner.xcall.recvCall(owner.bnUSD._address(), ethBnUSD.toString(), lockData); + + // Arrange - set xcall fee permission + JsonArray setXCallFeePermissionParameters = new JsonArray() + .add(createParameter(balanced.savings._address())).add(createParameter(balanced.ETH_NID)).add(createParameter(true)); + JsonArray actions = new JsonArray() + .add(createTransaction(balanced.daofund._address(), "setXCallFeePermission", setXCallFeePermissionParameters)); + owner.governance.execute(actions.toString()); + + // Act + afterNextDays(2); + BigInteger unlockAmount = loanAmount.divide(BigInteger.TWO); + BigInteger previousLockedAmount = owner.savings.getLockedAmount(ethAccount.toString()); + owner.xcall.recvCall(owner.savings._address(), ethAccount.toString(), getUnlockData(unlockAmount)); + + //Verify + BigInteger lockedAmount = owner.savings.getLockedAmount(ethAccount.toString()); + assertEquals(lockedAmount, previousLockedAmount.subtract(unlockAmount)); + + } + + void afterNextDays(int days) { + balanced.increaseDay(days); + } + private static void depositHyUSDC(String from, String to, BigInteger amount, byte[] data) { byte[] deposit = AssetManagerMessages.deposit(hyUSDCAddress, from, to, amount, data); owner.xcall.recvCall(balanced.assetManager._address(), @@ -319,4 +467,40 @@ private static void updatePrice(BigInteger rate) { owner.xcall.recvCall(balanced.balancedOracle._address(), new NetworkAddress(balanced.ETH_NID, externalOracle).toString(), priceUpdate); } + + public static byte[] tokenData(String method, JsonObject params) { + JsonObject data = new JsonObject(); + data.set("method", method); + data.set("params", params); + return data.toString().getBytes(); + } + + static byte[] getCrossTransferData(String from, String to, BigInteger value, byte[] data) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(5); + writer.write("xcrosstransfer"); + writer.write(from); + writer.write(to); + writer.write(value); + writer.write(data); + writer.end(); + return writer.toByteArray(); + } + + static byte[] getClaimRewardsData() { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(1); + writer.write("xclaimrewards"); + writer.end(); + return writer.toByteArray(); + } + + static byte[] getUnlockData(BigInteger amount) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(2); + writer.write("xunlock"); + writer.write(amount); + writer.end(); + return writer.toByteArray(); + } } diff --git a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java index a4fa3c76c..5fe7bdb3c 100644 --- a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java +++ b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java @@ -29,7 +29,6 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; -import network.balanced.score.lib.interfaces.RewardsXCall; import network.balanced.score.lib.interfaces.SavingsXCall; import network.balanced.score.lib.utils.*; import network.balanced.score.lib.interfaces.Savings; @@ -40,6 +39,7 @@ import score.DictDB; import score.annotation.External; import score.annotation.Optional; +import score.annotation.Payable; public class SavingsImpl extends FloorLimited implements Savings { public static final String VERSION = "version"; @@ -76,10 +76,6 @@ public Address getAddress(String name) { return getAddressByName(name); } - private BigInteger getBnUSDBalance() { - return Context.call(BigInteger.class, getBnusd(), "balanceOf", Context.getAddress()); - } - @External public void gatherRewards() { try { @@ -93,13 +89,21 @@ public void gatherRewards() { @External public void unlock(BigInteger amount) { + unlockInternal(Context.getCaller().toString(), amount); + } + + public void xUnlock(String from, BigInteger amount) { + unlockInternal(from, amount); + } + + private void unlockInternal(String user, BigInteger amount){ Context.require(amount.compareTo(BigInteger.ZERO) > 0, "Cannot unlock a negative or zero amount"); - RewardsManager.changeLock(Context.getCaller().toString(), amount.negate()); + RewardsManager.changeLock(user, amount.negate()); Address bnUSD = getBnusd(); BalancedFloorLimits.verifyWithdraw(bnUSD, amount); BigInteger balance = Context.call(BigInteger.class, bnUSD, "balanceOf", Context.getAddress()); Context.require(RewardsManager.getTotalWorkingbalance().compareTo(balance.subtract(amount)) <= 0, "Sanity check, unauthorized withdrawals"); - Context.call(bnUSD, "transfer", Context.getCaller(), amount, new byte[0]); + TokenTransfer.transfer(bnUSD, user, amount); } @External @@ -171,11 +175,13 @@ private void handleTokenDeposit(String _from, BigInteger _value, byte[] _data) { String unpackedData = new String(_data); Context.require(!unpackedData.equals(""), "Token Fallback: Data can't be empty"); - JsonObject json = Json.parse(unpackedData).asObject(); + JsonObject json = Json.parse(unpackedData).asObject(); String method = json.get("method").asString(); - JsonObject params = json.get("params").asObject(); - if(params.get("to")!=null){ - _from = params.get("to").asString(); + if(json.get("params")!=null) { + JsonObject params = json.get("params").asObject(); + if (params.get("to") != null) { + _from = params.get("to").asString(); + } } switch (method) { case "_lock": { @@ -189,4 +195,9 @@ private void handleTokenDeposit(String _from, BigInteger _value, byte[] _data) { break; } } + + @Payable + public void fallback() { + + } } diff --git a/core-contracts/Savings/src/test/java/network/balanced/score/core/savings/SavingsTest.java b/core-contracts/Savings/src/test/java/network/balanced/score/core/savings/SavingsTest.java index d010afdde..a0b58d3aa 100644 --- a/core-contracts/Savings/src/test/java/network/balanced/score/core/savings/SavingsTest.java +++ b/core-contracts/Savings/src/test/java/network/balanced/score/core/savings/SavingsTest.java @@ -33,7 +33,6 @@ import java.util.Map; import static network.balanced.score.lib.utils.Constants.EXA; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; @@ -323,6 +322,33 @@ void crossChainClaimRewards() { verify(mockBalanced.baln.mock).crossTransfer(user1, rewards1.get(mockBalanced.baln.getAddress().toString()), new byte[0]); } + @Test + void xUnlock() { + //Arrange + String user = new NetworkAddress("0x1.ETH", "0x120").toString(); + BigInteger lockAmount = BigInteger.valueOf(100).multiply(EXA); + byte[] data = tokenData("_lock", Map.of()); + savings.invoke(mockBalanced.bnUSD.account, "xTokenFallback", user, lockAmount, data); + + // Act + BigInteger unlockAmount = lockAmount.divide(BigInteger.TWO); + when(mockBalanced.bnUSD.mock.balanceOf(savings.getAddress())).thenReturn(lockAmount); + when(mockBalanced.daofund.mock.getXCallFeePermission(any(Address.class), any(String.class))).thenReturn(true); + savings.invoke(mockBalanced.xCall.account, "handleCallMessage", user, getUnlockData(unlockAmount), new String[0]); + + // Assert + verify(mockBalanced.bnUSD.mock).crossTransfer(user, unlockAmount, new byte[0]); + } + + static byte[] getUnlockData(BigInteger amount) { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + writer.beginList(2); + writer.write("xunlock"); + writer.write(amount); + writer.end(); + return writer.toByteArray(); + } + static byte[] getClaimRewardsData() { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); writer.beginList(1); diff --git a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java index a8597c04e..c45cd301c 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java +++ b/score-lib/src/main/java/network/balanced/score/lib/interfaces/Savings.java @@ -38,6 +38,9 @@ public interface Savings extends Name, Version, AddressManager, FloorLimitedInte @External void unlock(BigInteger amount); + @XCall + void xUnlock(String from, BigInteger amount); + @External(readonly = true) BigInteger getTotalPayout(Address token); From c97076413eb7b7a3aef3e57561dbdc74a30d021f Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 29 Nov 2024 14:49:17 +0545 Subject: [PATCH 26/31] re-fix the previous update --- .../balanced/score/core/router/RouterImpl.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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 a321f6f53..fd767e3bb 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,8 +261,11 @@ private void executeRoute(String _from, byte[] data) { } else { receiver = _from; } - - route(receiver, fromToken, routeData.actions, minimumReceive, EMPTY_DATA); + byte[] _data = EMPTY_DATA; + if(routeData.data!=null){ + _data = routeData.data; + } + route(receiver, fromToken, routeData.actions, minimumReceive, _data); } private void jsonRoute(String _from, byte[] data) { @@ -308,7 +311,11 @@ private void jsonRoute(String _from, byte[] data) { } Address fromToken = Context.getCaller(); - route(receiver, fromToken, actions, minimumReceive, EMPTY_DATA); + byte[] _data = EMPTY_DATA; + if(params.get("data")!=null){ + _data = params.get("data").asString().getBytes(); + } + route(receiver, fromToken, actions, minimumReceive, _data); } @Payable @@ -318,4 +325,4 @@ public void fallback() { @EventLog(indexed = 1) public void Route(Address from, BigInteger fromAmount, Address to, BigInteger toAmount) { } -} +} \ No newline at end of file From 6f6f668ec07a1cdc2d0e9f0eb19cddd902e44dc1 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Sun, 8 Dec 2024 09:43:46 +0545 Subject: [PATCH 27/31] crosschain savings documentation --- crosschain_savings.md | 123 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 crosschain_savings.md diff --git a/crosschain_savings.md b/crosschain_savings.md new file mode 100644 index 000000000..6f0062ca6 --- /dev/null +++ b/crosschain_savings.md @@ -0,0 +1,123 @@ +## Crosschain Savings Feature Implementation Steps +The Crosschain Savings feature allows users to deposit(lock) their bnUSD balance on any spoke +chain into savings contract on ICON blockchain to receive the savings rewards as per savings rate. + +#### Deposit bnUSD + Depositing bnUSD on spoke chain is the normal process of bnUSD crossTransfer from spoke chain. But + the data field shouldn't be empty in this case. Data should contain a rlp encoded value as specified on + below code for solana spoke chain: +```javascript +let data = tokenData("_lock", {"to":"solana-test/"+withdrawerKeyPair.publicKey}); +function tokenData(method: string, params: Record): Buffer { + const map = { + method: method, + params: params, + }; + + const jsonString = JSON.stringify(map); + + return Buffer.from(jsonString, "utf-8"); +} +``` + Another way of bnUSD deposit from the spoke chain using other supported tokens is deposit token to + Asset Manager contract of the spoke chain. Doing that the `to` field should be the 'ICON Router + Contract Address' and data should be prepared on the following way. +```javascript + function getLockData(method: string, params: Record): Buffer { + const map = { + method: method, + params: params, + }; + const jsonString = JSON.stringify(map); + return Buffer.from(jsonString, "utf-8"); +} + +function getData( +): Uint8Array { + let lockData = getLockData("_lock", {"to": to_netwrok_address}); + const receiver = Buffer.from(icon_savings_network_address, "utf8"); + let rlpInput: rlp.Input = [ + "_swap", + receiver, + "0x00", // minimum amount to receive + lockData, + ["0x01", icon_bn_usd] + ]; + return rlp.encode(rlpInput); +} +``` + ### Claim rewards +To claim the accumulated rewards as per the savings rate, following is the example used from the solana +spooke chain: +```javascript + function getClaimRewardData( +): Uint8Array { + let rlpInput: rlp.Input = [ + "xclaimrewards", + ]; + return rlp.encode(rlpInput); +} + +let sources=xmState.sources; +let destinations=xmState.destinations; +let data = getClaimRewardData(); +let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_savings }; + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to)... +``` +### Unlock +To unlock the locked bnUSD: +```javascript +function getUnlockData( +amount: number, +): Uint8Array { +let rlpInput: rlp.Input = [ + "xunlock", + amount +]; +return rlp.encode(rlpInput); +} + +let sources=xmState.sources; +let destinations=xmState.destinations; +let data = getUnlockData(amount); // amount to unlock +let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_savings }; + console.log(Buffer.from(envelope)); + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to)... + +``` +##USDC Staking feature +USDC staking is a feature in which USDC can be locked to the savings contract to earn the savings +rate rewards. When staking USDC the Route contract is used to convert USDC to bnUSD and then it is transferred +to the savings contract. When unlocking it user will get bnUSD as normal bnUSD unlocking. By crosschain +savings features enabled even spoke chain USDC can be staked now(example is provided above- any supported +token can be staked now from the spoke chain). In ICON chain it can be done by transfering USDC to `Router` +Contract with following data build with java code for example: +```java +public static byte[] tokenData(String method, Map params) { + Map map = new HashMap<>(); + map.put("method", method); + map.put("params", params); + JSONObject data = new JSONObject(map); + return data.toString().getBytes(); +} + +String tokenData = new String(tokenData("_lock", Map.of())); +Account newReceiver = balanced.savings.account; +byte[] data = tokenData("_swap", Map.of("path", +new Object[]{balanced.bnUSD.getAddress().toString()}, "receiver", +newReceiver.getAddress().toString(), "data", tokenData)); +``` \ No newline at end of file From 77dd47ed30eccd87a454358ec8ca0bd07b7d8bd5 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 10 Dec 2024 13:45:30 +0545 Subject: [PATCH 28/31] minor fix --- .../main/java/network/balanced/score/lib/structs/RouteData.java | 2 +- .../main/java/network/balanced/score/lib/utils/Versions.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java b/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java index 1c07e7c44..a7aabb6e2 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java +++ b/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java @@ -48,7 +48,7 @@ public static RouteData readObject(ObjectReader reader) { } public static void writeObject(ObjectWriter w, RouteData obj) { - w.beginList(obj.actions.size()+3); + w.beginList(obj.actions.size()+4); w.write(obj.method); w.writeNullable(obj.receiver); w.writeNullable(obj.minimumReceive); diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java index 24bc3744f..6f8e033e3 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java @@ -33,7 +33,7 @@ public class Versions { public final static String DEX = "v1.1.8"; public final static String GOVERNANCE = "v1.0.2"; public final static String REBALANCING = "v1.0.0"; - public final static String ROUTER = "v1.1.9"; + public final static String ROUTER = "v1.2.3"; public final static String STAKEDLP = "v1.0.8"; public final static String BOOSTED_BALN = "v1.1.0"; public final static String BRIBING = "v1.0.1"; From 251df2897947ac4f2b8fda6da3bec8057911df77 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 10 Dec 2024 14:08:10 +0545 Subject: [PATCH 29/31] RouteData version compatibility issue fixed --- .../score/core/router/RouterImpl.java | 12 ++++++++++- .../balanced/score/lib/structs/RouteData.java | 21 +++++++++++++++++++ .../balanced/score/lib/utils/Versions.java | 2 +- 3 files changed, 33 insertions(+), 2 deletions(-) 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 fd767e3bb..c993301e0 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 @@ -245,8 +245,18 @@ public void xTokenFallback(String _from, BigInteger _value, byte[] _data) { executeRoute(_from, _data); } + private RouteData getRouteData(byte[] data){ + RouteData routeData; + try { + routeData = RouteData.fromBytes(data); + }catch(IllegalStateException ignored ){ + routeData = RouteData.fromBytesOld(data); + } + return routeData; + } + private void executeRoute(String _from, byte[] data) { - RouteData routeData = RouteData.fromBytes(data); + RouteData routeData = getRouteData(data); Context.require(routeData.method.contains("_swap"), TAG + ": Fallback directly not allowed."); Address fromToken = Context.getCaller(); diff --git a/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java b/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java index a7aabb6e2..91f84fda0 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java +++ b/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java @@ -47,6 +47,22 @@ public static RouteData readObject(ObjectReader reader) { return obj; } + public static RouteData readObjectOld(ObjectReader reader) { + RouteData obj = new RouteData(); + reader.beginList(); + List actions = new ArrayList<>(); + obj.method = reader.readString(); + obj.receiver = reader.readNullable(String.class); + obj.minimumReceive = reader.readNullable((BigInteger.class)); + while (reader.hasNext()) { + RouteAction data = reader.read(RouteAction.class); + actions.add(data); + } + obj.actions = actions; + reader.end(); + return obj; + } + public static void writeObject(ObjectWriter w, RouteData obj) { w.beginList(obj.actions.size()+4); w.write(obj.method); @@ -64,6 +80,11 @@ public static RouteData fromBytes(byte[] bytes) { return RouteData.readObject(reader); } + public static RouteData fromBytesOld(byte[] bytes) { + ObjectReader reader = Context.newByteArrayObjectReader("RLPn", bytes); + return RouteData.readObjectOld(reader); + } + public byte[] toBytes() { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); RouteData.writeObject(writer, this); diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java index 6f8e033e3..dd994239d 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java @@ -33,7 +33,7 @@ public class Versions { public final static String DEX = "v1.1.8"; public final static String GOVERNANCE = "v1.0.2"; public final static String REBALANCING = "v1.0.0"; - public final static String ROUTER = "v1.2.3"; + public final static String ROUTER = "v1.2.4"; public final static String STAKEDLP = "v1.0.8"; public final static String BOOSTED_BALN = "v1.1.0"; public final static String BRIBING = "v1.0.1"; From 4eb125430a874b1151ddcac1365b00ca84554879 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 18 Dec 2024 14:20:29 +0545 Subject: [PATCH 30/31] unit test for old routerData struct, use of contains, sicx version fix --- .../score/core/router/RouterImpl.java | 2 +- .../score/core/router/RouterTest.java | 58 ++++++ .../score/core/savings/SavingsImpl.java | 2 +- crosschain_savings.md | 180 +++++++++--------- .../balanced/score/lib/structs/RouteData.java | 16 ++ .../balanced/score/lib/utils/Versions.java | 2 +- 6 files changed, 167 insertions(+), 93 deletions(-) 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 c993301e0..36395a7cc 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 @@ -322,7 +322,7 @@ private void jsonRoute(String _from, byte[] data) { Address fromToken = Context.getCaller(); byte[] _data = EMPTY_DATA; - if(params.get("data")!=null){ + if(params.contains("data")){ _data = params.get("data").asString().getBytes(); } route(receiver, fromToken, actions, minimumReceive, _data); diff --git a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java index dc21c299d..f16e7764e 100644 --- a/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java +++ b/core-contracts/Router/src/test/java/network/balanced/score/core/router/RouterTest.java @@ -504,6 +504,41 @@ void tokenFallback_swapStable() throws Exception { } } + @Test + void tokenFallback_swapStableOldRouteData() throws Exception { + // Arrange + BigInteger balnToSwap = BigInteger.TEN.multiply(ICX); + List actions = new ArrayList<>(MAX_NUMBER_OF_ITERATIONS); + List> tokens = new ArrayList<>(MAX_NUMBER_OF_ITERATIONS - 1); + for (int i = 0; i < MAX_NUMBER_OF_ITERATIONS; i++) { + if (i == 0) { + actions.add(new RouteAction(SWAP, balanced.sicx.getAddress())); + continue; + } + MockContract token = new MockContract<>(IRC2ScoreInterface.class, IRC2.class, sm, owner); + when(token.mock.balanceOf(routerScore.getAddress())).thenReturn(balnToSwap); + actions.add(new RouteAction(STABILITY_SWAP, token.getAddress())); + tokens.add(token); + } + + Account newReceiver = sm.createAccount(); + byte[] data = new RouteData("_swap", newReceiver.getAddress().toString(), BigInteger.ZERO, actions, null).toBytesOld(); + + // Act + routerScore.invoke(balanced.baln.account, "tokenFallback", owner.getAddress(), balnToSwap, + data); + + // Assert + int i = 0; + for (MockContract token : tokens) { + if (i < tokens.size() - 1) { + byte[] d = tokens.get(i + 1).getAddress().toString().getBytes(); + verify(token.mock).transfer(balanced.stability.getAddress(), balnToSwap, d); + } + i++; + } + } + @Test void tokenFallback_swapToICX() throws Exception { // Arrange @@ -527,6 +562,29 @@ void tokenFallback_swapToICX() throws Exception { assertEquals(ICXResult, newReceiver.getBalance()); } + @Test + void tokenFallback_swapToICXOldRouteData() throws Exception { + // Arrange + BigInteger USDToSwap = BigInteger.TEN.multiply(ICX); + BigInteger sICXResult = BigInteger.valueOf(100).multiply(ICX); + BigInteger ICXResult = BigInteger.valueOf(110).multiply(ICX); + List actions = new ArrayList<>(2); + actions.add(new RouteAction(SWAP, balanced.sicx.getAddress())); + actions.add(new RouteAction(SWAP, null)); + when(balanced.sicx.mock.balanceOf(routerScore.getAddress())).thenReturn(sICXResult); + routerScore.getAccount().addBalance("ICX", ICXResult); + + Account newReceiver = sm.createAccount(); + byte[] data = new RouteData("_swap", newReceiver.getAddress().toString(), BigInteger.ZERO, actions, null).toBytesOld(); + + // Act + routerScore.invoke(balanced.baln.account, "tokenFallback", owner.getAddress(), USDToSwap, + data); + + // Assert + assertEquals(ICXResult, newReceiver.getBalance()); + } + @Test void tokenFallback_swapStableWithoutOptField_AndMixedSwapTypes() throws Exception { // Arrange diff --git a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java index 5fe7bdb3c..93adf7e0b 100644 --- a/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java +++ b/core-contracts/Savings/src/main/java/network/balanced/score/core/savings/SavingsImpl.java @@ -177,7 +177,7 @@ private void handleTokenDeposit(String _from, BigInteger _value, byte[] _data) { Context.require(!unpackedData.equals(""), "Token Fallback: Data can't be empty"); JsonObject json = Json.parse(unpackedData).asObject(); String method = json.get("method").asString(); - if(json.get("params")!=null) { + if(json.contains("params")) { JsonObject params = json.get("params").asObject(); if (params.get("to") != null) { _from = params.get("to").asString(); diff --git a/crosschain_savings.md b/crosschain_savings.md index 6f0062ca6..090678989 100644 --- a/crosschain_savings.md +++ b/crosschain_savings.md @@ -7,99 +7,99 @@ chain into savings contract on ICON blockchain to receive the savings rewards as the data field shouldn't be empty in this case. Data should contain a rlp encoded value as specified on below code for solana spoke chain: ```javascript -let data = tokenData("_lock", {"to":"solana-test/"+withdrawerKeyPair.publicKey}); -function tokenData(method: string, params: Record): Buffer { - const map = { - method: method, - params: params, - }; - - const jsonString = JSON.stringify(map); - - return Buffer.from(jsonString, "utf-8"); -} + let data = tokenData("_lock", {"to":"solana-test/"+withdrawerKeyPair.publicKey}); + function tokenData(method: string, params: Record): Buffer { + const map = { + method: method, + params: params, + }; + + const jsonString = JSON.stringify(map); + + return Buffer.from(jsonString, "utf-8"); + } ``` Another way of bnUSD deposit from the spoke chain using other supported tokens is deposit token to Asset Manager contract of the spoke chain. Doing that the `to` field should be the 'ICON Router Contract Address' and data should be prepared on the following way. ```javascript - function getLockData(method: string, params: Record): Buffer { - const map = { - method: method, - params: params, - }; - const jsonString = JSON.stringify(map); - return Buffer.from(jsonString, "utf-8"); -} - -function getData( -): Uint8Array { - let lockData = getLockData("_lock", {"to": to_netwrok_address}); - const receiver = Buffer.from(icon_savings_network_address, "utf8"); - let rlpInput: rlp.Input = [ - "_swap", - receiver, - "0x00", // minimum amount to receive - lockData, - ["0x01", icon_bn_usd] - ]; - return rlp.encode(rlpInput); -} + function getLockData(method: string, params: Record): Buffer { + const map = { + method: method, + params: params, + }; + const jsonString = JSON.stringify(map); + return Buffer.from(jsonString, "utf-8"); + } + + function getData( + ): Uint8Array { + let lockData = getLockData("_lock", {"to": to_netwrok_address}); + const receiver = Buffer.from(icon_savings_network_address, "utf8"); + let rlpInput: rlp.Input = [ + "_swap", + receiver, + "0x00", // minimum amount to receive + lockData, + ["0x01", icon_bn_usd] + ]; + return rlp.encode(rlpInput); + } ``` - ### Claim rewards +### Claim rewards To claim the accumulated rewards as per the savings rate, following is the example used from the solana spooke chain: ```javascript function getClaimRewardData( -): Uint8Array { - let rlpInput: rlp.Input = [ - "xclaimrewards", - ]; - return rlp.encode(rlpInput); -} - -let sources=xmState.sources; -let destinations=xmState.destinations; -let data = getClaimRewardData(); -let envelope = new Envelope( - MessageType.CallMessage, - new CallMessage(data).encode(), - sources, - destinations - ).encode(); - const to = { "0": "0x2.icon/"+icon_savings }; - let sendCallIx = await xcall_program.methods - .sendCall(Buffer.from(envelope), to)... + ): Uint8Array { + let rlpInput: rlp.Input = [ + "xclaimrewards", + ]; + return rlp.encode(rlpInput); + } + + let sources=xmState.sources; + let destinations=xmState.destinations; + let data = getClaimRewardData(); + let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_savings }; + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to)... ``` ### Unlock To unlock the locked bnUSD: ```javascript -function getUnlockData( -amount: number, -): Uint8Array { -let rlpInput: rlp.Input = [ - "xunlock", - amount -]; -return rlp.encode(rlpInput); -} - -let sources=xmState.sources; -let destinations=xmState.destinations; -let data = getUnlockData(amount); // amount to unlock -let envelope = new Envelope( - MessageType.CallMessage, - new CallMessage(data).encode(), - sources, - destinations - ).encode(); - const to = { "0": "0x2.icon/"+icon_savings }; - console.log(Buffer.from(envelope)); - let sendCallIx = await xcall_program.methods - .sendCall(Buffer.from(envelope), to)... + function getUnlockData( + amount: number, + ): Uint8Array { + let rlpInput: rlp.Input = [ + "xunlock", + amount + ]; + return rlp.encode(rlpInput); + } + + let sources=xmState.sources; + let destinations=xmState.destinations; + let data = getUnlockData(amount); // amount to unlock + let envelope = new Envelope( + MessageType.CallMessage, + new CallMessage(data).encode(), + sources, + destinations + ).encode(); + const to = { "0": "0x2.icon/"+icon_savings }; + console.log(Buffer.from(envelope)); + let sendCallIx = await xcall_program.methods + .sendCall(Buffer.from(envelope), to)... ``` -##USDC Staking feature +## USDC Staking feature USDC staking is a feature in which USDC can be locked to the savings contract to earn the savings rate rewards. When staking USDC the Route contract is used to convert USDC to bnUSD and then it is transferred to the savings contract. When unlocking it user will get bnUSD as normal bnUSD unlocking. By crosschain @@ -107,17 +107,17 @@ savings features enabled even spoke chain USDC can be staked now(example is prov token can be staked now from the spoke chain). In ICON chain it can be done by transfering USDC to `Router` Contract with following data build with java code for example: ```java -public static byte[] tokenData(String method, Map params) { - Map map = new HashMap<>(); - map.put("method", method); - map.put("params", params); - JSONObject data = new JSONObject(map); - return data.toString().getBytes(); -} - -String tokenData = new String(tokenData("_lock", Map.of())); -Account newReceiver = balanced.savings.account; -byte[] data = tokenData("_swap", Map.of("path", -new Object[]{balanced.bnUSD.getAddress().toString()}, "receiver", -newReceiver.getAddress().toString(), "data", tokenData)); + public static byte[] tokenData(String method, Map params) { + Map map = new HashMap<>(); + map.put("method", method); + map.put("params", params); + JSONObject data = new JSONObject(map); + return data.toString().getBytes(); + } + + String tokenData = new String(tokenData("_lock", Map.of())); + Account newReceiver = balanced.savings.account; + byte[] data = tokenData("_swap", Map.of("path", + new Object[]{balanced.bnUSD.getAddress().toString()}, "receiver", + newReceiver.getAddress().toString(), "data", tokenData)); ``` \ No newline at end of file diff --git a/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java b/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java index 91f84fda0..43d091b8a 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java +++ b/score-lib/src/main/java/network/balanced/score/lib/structs/RouteData.java @@ -75,6 +75,17 @@ public static void writeObject(ObjectWriter w, RouteData obj) { w.end(); } + public static void writeObjectOld(ObjectWriter w, RouteData obj) { + w.beginList(obj.actions.size()+3); + w.write(obj.method); + w.writeNullable(obj.receiver); + w.writeNullable(obj.minimumReceive); + for (RouteAction action : obj.actions) { + w.write(action); + } + w.end(); + } + public static RouteData fromBytes(byte[] bytes) { ObjectReader reader = Context.newByteArrayObjectReader("RLPn", bytes); return RouteData.readObject(reader); @@ -91,4 +102,9 @@ public byte[] toBytes() { return writer.toByteArray(); } + public byte[] toBytesOld() { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + RouteData.writeObjectOld(writer, this); + return writer.toByteArray(); + } } diff --git a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java index dd994239d..804c8b5c4 100644 --- a/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java +++ b/score-lib/src/main/java/network/balanced/score/lib/utils/Versions.java @@ -21,7 +21,7 @@ public class Versions { public final static String DIVIDENDS = "v1.0.0"; public final static String LOANS = "v1.2.3"; public final static String RESERVE = "v1.0.0"; - public final static String SICX = "v1.1.0"; + public final static String SICX = "v1.1.1"; public final static String STAKING = "v1.0.1"; public final static String WORKERTOKEN = "v1.0.0"; public final static String BNUSD = "v1.1.1"; From 3d864ecb16e40bfee55afe9b926755002ad739a4 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 26 Dec 2024 13:12:35 +0545 Subject: [PATCH 31/31] data structure added on docs --- crosschain_savings.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/crosschain_savings.md b/crosschain_savings.md index 090678989..26059a6b3 100644 --- a/crosschain_savings.md +++ b/crosschain_savings.md @@ -70,6 +70,14 @@ spooke chain: const to = { "0": "0x2.icon/"+icon_savings }; let sendCallIx = await xcall_program.methods .sendCall(Buffer.from(envelope), to)... + + function getClaimRewardData( + ): Uint8Array { + let rlpInput: rlp.Input = [ + "xclaimrewards", + ]; + return rlp.encode(rlpInput); + } ``` ### Unlock To unlock the locked bnUSD: @@ -97,7 +105,15 @@ To unlock the locked bnUSD: console.log(Buffer.from(envelope)); let sendCallIx = await xcall_program.methods .sendCall(Buffer.from(envelope), to)... - + function getUnlockData( + amount: number, + ): Uint8Array { + let rlpInput: rlp.Input = [ + "xunlock", + amount + ]; + return rlp.encode(rlpInput); + } ``` ## USDC Staking feature USDC staking is a feature in which USDC can be locked to the savings contract to earn the savings @@ -106,7 +122,7 @@ to the savings contract. When unlocking it user will get bnUSD as normal bnUSD u savings features enabled even spoke chain USDC can be staked now(example is provided above- any supported token can be staked now from the spoke chain). In ICON chain it can be done by transfering USDC to `Router` Contract with following data build with java code for example: -```java +```javascript public static byte[] tokenData(String method, Map params) { Map map = new HashMap<>(); map.put("method", method);