From b3cf4d2f8f66fce12218c229c2947839d1f1aef1 Mon Sep 17 00:00:00 2001 From: AntonAndell Date: Thu, 5 Dec 2024 08:22:41 +0100 Subject: [PATCH] Remove staking from the Balanced token --- .../dividends/DividendsIntegrationTest.java | 36 -- .../governance/utils/GovernanceConstants.java | 2 - .../score/lib/interfaces/BalancedToken.java | 72 +-- .../balanced/score/lib/utils/Versions.java | 2 +- .../score/lib/test/integration/Balanced.java | 3 - .../BalancedTokenImplIntTest.java | 71 --- .../balancedtoken/BalancedTokenImpl.java | 559 +----------------- .../balancedtoken/BalancedTokenVariables.java | 39 -- .../score/tokens/balancedtoken/Constants.java | 37 +- .../balancedtoken/BalancedTokenImplTest.java | 469 +-------------- 10 files changed, 57 insertions(+), 1233 deletions(-) diff --git a/core-contracts/Dividends/src/intTest/java/network/balanced/score/core/dividends/DividendsIntegrationTest.java b/core-contracts/Dividends/src/intTest/java/network/balanced/score/core/dividends/DividendsIntegrationTest.java index 528995c61..e4a871a91 100644 --- a/core-contracts/Dividends/src/intTest/java/network/balanced/score/core/dividends/DividendsIntegrationTest.java +++ b/core-contracts/Dividends/src/intTest/java/network/balanced/score/core/dividends/DividendsIntegrationTest.java @@ -169,7 +169,6 @@ void testBBaln_lock() { Map unclaimedDividendsBeforeBob = reader.dividends.getUnclaimedDividends(addressBob); // user unstakes all the baln token - alice.baln.stake(BigInteger.ZERO); BigInteger availableBalnBalance = alice.baln.availableBalanceOf(addressAlice); long unlockTime = @@ -257,35 +256,7 @@ void testBBaln_claimOnly() { assertEquals(unclaimedDividendsAfterEve, BigInteger.ZERO); } - @Test - @Order(6) - void testBBaln_claimAfterUnstake() { - /* Ferry claims the dividends after unstaking baln token. */ - Address addressFerry = Ferry.getAddress(); - BigInteger unclaimedDividendsBeforeFerry = - owner.dividends.getUnclaimedDividends(addressFerry).get(balanced.bnusd._address().toString()); - BigInteger bnusdBeforeFerry = Ferry.bnUSD.balanceOf(addressFerry); - // Ferry unstakes baln token - Ferry.baln.stake(BigInteger.ZERO); - Ferry.dividends.claimDividends(); - BigInteger unclaimedDividendsAfterFerry = - owner.dividends.getUnclaimedDividends(addressFerry).get(balanced.bnusd._address().toString()); - BigInteger bnusdAfterFerry = Eve.bnUSD.balanceOf(addressFerry); - // unclaimed dividends become 0 after claiming - assertEquals(unclaimedDividendsAfterFerry, BigInteger.ZERO); - // unclaimed dividends should go to Eve's wallet after claiming - assertEquals(bnusdBeforeFerry.add(unclaimedDividendsBeforeFerry), bnusdAfterFerry); - BigInteger collateral = BigInteger.valueOf(500).multiply(BigInteger.TEN.pow(18)); - BigInteger loanAmount = BigInteger.valueOf(100).multiply(BigInteger.TEN.pow(18)); - owner.stakeDepositAndBorrow(collateral, loanAmount); - unclaimedDividendsAfterFerry = - owner.dividends.getUnclaimedDividends(addressFerry).get(balanced.bnusd._address().toString()); - - // unclaimed dividends remains 0 for that user - assertEquals(unclaimedDividendsAfterFerry, BigInteger.ZERO); - - } @Test @Order(7) @@ -520,13 +491,6 @@ void createNewUserForBBaln() { owner.baln.transfer(addressEve, collateral, new byte[0]); owner.baln.transfer(addressFerry, collateral, new byte[0]); - // staking baln token with multiple different users. - BigInteger stakedAmount = BigInteger.valueOf(50).multiply(BigInteger.TEN.pow(18)); - alice.baln.stake(stakedAmount); - bob.baln.stake(stakedAmount); - Eve.baln.stake(stakedAmount); - Ferry.baln.stake(stakedAmount); - // loan taken to send some dividends to contract owner.stakeDepositAndBorrow(collateral, loanAmount); } diff --git a/core-contracts/Governance/src/main/java/network/balanced/score/core/governance/utils/GovernanceConstants.java b/core-contracts/Governance/src/main/java/network/balanced/score/core/governance/utils/GovernanceConstants.java index e1c06c2d8..631d73adf 100644 --- a/core-contracts/Governance/src/main/java/network/balanced/score/core/governance/utils/GovernanceConstants.java +++ b/core-contracts/Governance/src/main/java/network/balanced/score/core/governance/utils/GovernanceConstants.java @@ -56,13 +56,11 @@ public class GovernanceConstants extends Constants { public static Map> ADDRESSES = Map.ofEntries( entry("rewards", List.of("reserve", "baln", "bwt", "daofund", "stakedLp", "bBaln")), entry("bnUSD", List.of("oracle")), - entry("baln", List.of("dividends", "oracle", "dex", "bnUSD")), entry("bwt", List.of("baln")), entry("stakedLp", List.of("dex", "rewards")) ); public static Map ADMIN_ADDRESSES = Map.ofEntries( - entry("baln", "rewards"), entry("bwt", "governance") ); 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 bf3f35b87..7b622942f 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 @@ -33,36 +33,11 @@ @ScoreClient @ScoreInterface -public interface BalancedToken extends HubToken, IRC2BurnableInterface, GovernanceAddress, AdminAddress, - BnusdAddress, OracleAddress, DexAddress, DividendsAddress, Version { - - @External - void setOracleName(String _name); - - @External(readonly = true) - String getOracleName(); +public interface BalancedToken extends HubToken, IRC2BurnableInterface, Version { @External(readonly = true) String getPeg(); - @External - void setMinInterval(BigInteger _interval); - - @External(readonly = true) - BigInteger getMinInterval(); - - @External(readonly = true) - BigInteger getPriceUpdateTime(); - - @External - BigInteger priceInLoop(); - - @External(readonly = true) - BigInteger lastPriceInLoop(); - - @External(readonly = true) - Map detailsBalanceOf(Address _owner); - @External(readonly = true) BigInteger unstakedBalanceOf(Address _owner); @@ -72,54 +47,9 @@ public interface BalancedToken extends HubToken, IRC2BurnableInterface, Governan @External(readonly = true) BigInteger availableBalanceOf(Address _owner); - @External(readonly = true) - boolean getStakingEnabled(); - @External(readonly = true) BigInteger totalStakedBalance(); - @External(readonly = true) - BigInteger getMinimumStake(); - - @External(readonly = true) - BigInteger getUnstakingPeriod(); - - @External - void toggleEnableSnapshot(); - - @External(readonly = true) - boolean getSnapshotEnabled(); - - @External - void toggleStakingEnabled(); - - @External - void stake(BigInteger _value); - - @External - void setMinimumStake(BigInteger _amount); - - @External - void setUnstakingPeriod(BigInteger _time); - - @External - void setTimeOffset(); - - @External(readonly = true) - BigInteger getTimeOffset(); - - @External(readonly = true) - BigInteger getDay(); - - @External(readonly = true) - BigInteger stakedBalanceOfAt(Address _account, BigInteger _day); - - @External(readonly = true) - BigInteger totalStakedBalanceOfAt(BigInteger _day); - - @EventLog(indexed = 3) - void OraclePrice(String market, String oracle_name, Address oracle_address, BigInteger price); - @External void setMinter(Address _address); 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 4603f0633..87544241d 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 @@ -17,7 +17,7 @@ package network.balanced.score.lib.utils; public class Versions { - public final static String BALN = "v1.1.0"; + public final static String BALN = "v1.1.2"; public final static String DIVIDENDS = "v1.0.0"; public final static String LOANS = "v1.2.3"; public final static String RESERVE = "v1.0.0"; 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 1d47edca0..8a2df916d 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 @@ -297,8 +297,5 @@ public void syncDistributions() { public void increaseDay(int nrOfDays) { ownerClient.governance.setTimeOffset(ownerClient.governance.getTimeOffset().subtract(MICRO_SECONDS_IN_A_DAY.multiply(BigInteger.valueOf(nrOfDays)))); - JsonArray setTimeOffset = createSingleTransaction(baln._address(), "setTimeOffset", new JsonArray()); - - ownerClient.governance.execute(setTimeOffset.toString()); } } diff --git a/token-contracts/BalancedToken/src/intTest/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImplIntTest.java b/token-contracts/BalancedToken/src/intTest/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImplIntTest.java index 92c3448b7..91c43859f 100644 --- a/token-contracts/BalancedToken/src/intTest/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImplIntTest.java +++ b/token-contracts/BalancedToken/src/intTest/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImplIntTest.java @@ -59,77 +59,6 @@ void testName() { assertEquals("Balance Token", balnScore.name()); } - @Test - @Order(2) - void ShouldAUserMintAndTransferAndMakeStake() { - BigInteger loanAmount = BigInteger.valueOf(50).multiply(BigInteger.TEN.pow(18)); - // take loans - BigInteger collateral = BigInteger.valueOf(500).multiply(BigInteger.TEN.pow(18)); - balanced.ownerClient.stakeDepositAndBorrow(collateral, loanAmount); - balanced.increaseDay(1); - balanced.syncDistributions(); - - // balance token is minted in owner address - balanced.ownerClient.rewards.claimRewards(null); - BigInteger amountToMint = balnScore.balanceOf(Address.fromString(owner.getAddress().toString())); - - //transfer some tokens to another user - BigInteger amountToTransferToReceiver = amountToMint.divide(BigInteger.TWO); - BigInteger amountRemaining = amountToMint.subtract(amountToTransferToReceiver); - - balnScore.transfer(Address.fromString(tester.getAddress().toString()), amountToTransferToReceiver, - "mole".getBytes()); - assertEquals(amountRemaining, - balnScore.balanceOf(Address.fromString(owner.getAddress().toString()))); - assertEquals(amountToTransferToReceiver, - balnScore.balanceOf(Address.fromString(tester.getAddress().toString()))); - - BigInteger amountToStake = amountRemaining.divide(BigInteger.TWO); - BigInteger unstakedBalance = amountRemaining.subtract(amountToStake); - - // stake some token - balnScore.stake(amountToStake); - - Map detailsBalanceOf = - balnScore.detailsBalanceOf(Address.fromString(owner.getAddress().toString())); - - // assert if balance is staked or not. - assertEquals(detailsBalanceOf.get("Staked balance"), amountToStake); - assertEquals(detailsBalanceOf.get("Available balance"), unstakedBalance); - assertEquals(detailsBalanceOf.get("Unstaking balance"), BigInteger.ZERO); - - //unstake some tokens - BigInteger remainingStake = amountToStake.divide(BigInteger.TWO); - BigInteger unstakeAmount = amountToStake.subtract(remainingStake); - balnScore.stake(remainingStake); - - detailsBalanceOf = balnScore.detailsBalanceOf(Address.fromString(owner.getAddress().toString())); - - // assert if balance is unstaked or not. - assertEquals(detailsBalanceOf.get("Staked balance"), remainingStake); - assertEquals(detailsBalanceOf.get("Available balance"), unstakedBalance); - assertEquals(detailsBalanceOf.get("Unstaking balance"), unstakeAmount); - - BigInteger totalBalance = balnScore.totalStakedBalance(); - // assert totalStakedBalance - assertEquals(amountToStake.divide(BigInteger.TWO), totalBalance); - - // unstake completely - - // wait for few days - balanced.increaseDay(4); - balanced.syncDistributions(); - - // unstake completely - balnScore.stake(BigInteger.ZERO); - - detailsBalanceOf = balnScore.detailsBalanceOf(Address.fromString(owner.getAddress().toString())); - - // assert if balance is unstaked or not. - assertEquals(detailsBalanceOf.get("Staked balance"), BigInteger.ZERO); - assertEquals(detailsBalanceOf.get("Unstaking balance"), amountToStake); - } - @Test @Order(3) void mint() { diff --git a/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImpl.java b/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImpl.java index a59838bde..a9c4f297f 100644 --- a/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImpl.java +++ b/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImpl.java @@ -20,6 +20,7 @@ import network.balanced.score.lib.tokens.HubTokenImpl; import network.balanced.score.lib.utils.BalancedAddressManager; import network.balanced.score.lib.utils.Versions; +import network.balanced.score.lib.utils.Names; import score.*; import score.annotation.EventLog; import score.annotation.External; @@ -44,31 +45,16 @@ public class BalancedTokenImpl extends HubTokenImpl implements BalancedToken { public BalancedTokenImpl(Address _governance) { super("", TOKEN_NAME, SYMBOL_NAME, null); - if (governance.get() != null && admin.get() == null) { - admin.set(_governance); - } - - if (governance.get() == null) { + if (BalancedAddressManager.getAddressByName(Names.GOVERNANCE) == null) { BalancedAddressManager.setGovernance(_governance); - governance.set(_governance); - stakingEnabled.set(true); - oracleName.set(DEFAULT_ORACLE_NAME); - lastPrice.set(INITIAL_PRICE_ESTIMATE); - minInterval.set(MIN_UPDATE_TIME); - minimumStake.set(MINIMUM_STAKE_AMOUNT); - unstakingPeriod.set(DEFAULT_UNSTAKING_PERIOD); - enableSnapshots.set(true); } - if (currentVersion.getOrDefault("").equals("v1.0.1") ) { - DictDB stakingDetail = - stakedBalances.at(BalancedAddressManager.getDaofund()); - stakingDetail.set(Status.AVAILABLE.code, - balanceOf(BalancedAddressManager.getDaofund())); - } + NATIVE_NID = (String)Context.call(BalancedAddressManager.getXCall(), "getNetworkId"); + if (currentVersion.getOrDefault("").equals(Versions.BALN)) { - Context.revert("Can't Update same version of code"); + Context.revert("Can't Update same version of code"); } + currentVersion.set(Versions.BALN); } @@ -77,466 +63,86 @@ public String version() { return currentVersion.getOrDefault(""); } - @EventLog(indexed = 3) - public void OraclePrice(String market, String oracle_name, Address oracle_address, BigInteger price) { - } @External(readonly = true) public String getPeg() { return TAG; } - @External - public void setGovernance(Address _address) { - onlyOwner(); - governance.set(_address); - } - - @External(readonly = true) - public Address getGovernance() { - return governance.get(); - } - - @External - public void setAdmin(Address _address) { - only(governance); - admin.set(_address); - } - - @External(readonly = true) - public Address getAdmin() { - return admin.get(); - } - - @External - public void setBnusd(Address _address) { - only(governance); - isContract(_address); - bnusdScore.set(_address); - } - - @External(readonly = true) - public Address getBnusd() { - return bnusdScore.get(); - } - - @External - public void setOracle(Address _address) { - only(governance); - isContract(_address); - oracle.set(_address); - } - - @External(readonly = true) - public Address getOracle() { - return oracle.get(); - } - - @External - public void setDex(Address _address) { - only(governance); - isContract(_address); - dexScore.set(_address); - } - - @External(readonly = true) - public Address getDex() { - return dexScore.get(); - } - - @External - public void setDividends(Address _address) { - only(governance); - isContract(_address); - dividendsScore.set(_address); - } - - @External(readonly = true) - public Address getDividends() { - return dividendsScore.get(); - } - - @External - public void setOracleName(String _name) { - only(governance); - oracleName.set(_name); - } - - @External(readonly = true) - public String getOracleName() { - return oracleName.get(); - } - - @External - public void setMinInterval(BigInteger _interval) { - only(governance); - minInterval.set(_interval); - } - - @External(readonly = true) - public BigInteger getMinInterval() { - return minInterval.get(); - } - - @External(readonly = true) - public BigInteger getPriceUpdateTime() { - return priceUpdateTime.getOrDefault(BigInteger.ZERO); - } - - /** - * Returns the price of the asset in loop. Makes a call to the oracle if the - * last recorded price is not recent - * enough. - **/ - @External - public BigInteger priceInLoop() { - BigInteger currentTime = BigInteger.valueOf(Context.getBlockTimestamp()); - BigInteger lastPriceUpdateTime = priceUpdateTime.getOrDefault(BigInteger.ZERO); - BigInteger interval = minInterval.getOrDefault(BigInteger.ZERO); - if (currentTime.subtract(lastPriceUpdateTime).compareTo(interval) > 0) { - this.updateAssetValue(); - } - return lastPrice.get(); - } - - /** - * Returns the latest price of the asset in loop. - **/ - @SuppressWarnings("unchecked") - @External(readonly = true) - public BigInteger lastPriceInLoop() { - Address dexScore = BalancedTokenVariables.dexScore.get(); - Address oracleAddress = oracle.get(); - - BigInteger balnPriceInUsd = Context.call(BigInteger.class, dexScore, "getBalnPrice"); - Map priceData = (Map) Context.call(oracleAddress, "get_reference_data", - "USD", "ICX"); - - return balnPriceInUsd.multiply(priceData.get("rate")).divide(EXA); - } - - /** - * Calls the oracle method for the asset and updates the asset value in loop. - **/ - private void updateAssetValue() { - String base = "BALN"; - String quote = "ICX"; - - BigInteger newPrice = lastPriceInLoop(); - - lastPrice.set(newPrice); - priceUpdateTime.set(BigInteger.valueOf(Context.getBlockTimestamp())); - this.OraclePrice(base + quote, oracleName.get(), dexScore.get(), newPrice); - } @External - public void setMinimumStake(BigInteger _amount) { - only(governance); - Context.require(_amount.compareTo(BigInteger.ZERO) >= 0, TAG + ": Amount cannot be less than zero."); - - BigInteger totalAmount = _amount.multiply(pow(BigInteger.TEN, decimals().intValue())); - minimumStake.set(totalAmount); - } - - @External(readonly = true) - public BigInteger getMinimumStake() { - return minimumStake.getOrDefault(BigInteger.ZERO); - } - - @External - public void setUnstakingPeriod(BigInteger _time) { - only(governance); - Context.require(_time.compareTo(BigInteger.ZERO) >= 0, TAG + ": Time cannot be negative."); - - BigInteger totalTime = _time.multiply(MICRO_SECONDS_IN_A_DAY); - unstakingPeriod.set(totalTime); - } - - @External(readonly = true) - public BigInteger getUnstakingPeriod() { - BigInteger timeInMicroseconds = unstakingPeriod.getOrDefault(BigInteger.ZERO); - return timeInMicroseconds.divide(MICRO_SECONDS_IN_A_DAY); - } - - @External - public void toggleStakingEnabled() { - only(governance); - stakingEnabled.set(!stakingEnabled.getOrDefault(false)); - } - - @External(readonly = true) - public boolean getStakingEnabled() { - return stakingEnabled.getOrDefault(false); - } - - @External - public void toggleEnableSnapshot() { - onlyOwner(); - enableSnapshots.set(!enableSnapshots.getOrDefault(false)); - } - - @External(readonly = true) - public boolean getSnapshotEnabled() { - return enableSnapshots.getOrDefault(false); - } - - @External - public void setTimeOffset() { + public void setMinter(Address _address) { onlyOwner(); - - Address dexScore = BalancedTokenVariables.dexScore.get(); - Context.require(dexScore != null, TAG + ": Dex score address must be set first"); - - BigInteger deltaTime = Context.call(BigInteger.class, dexScore, "getTimeOffset"); - timeOffset.set(deltaTime); - } - - @External(readonly = true) - public BigInteger getTimeOffset() { - return timeOffset.getOrDefault(BigInteger.ZERO); - } - - /** - * Returns the current day (floored). Used for snapshotting, paying rewards, and - * paying dividends. - **/ - @External(readonly = true) - public BigInteger getDay() { - return BigInteger.valueOf(Context.getBlockTimestamp()).subtract(timeOffset.getOrDefault(BigInteger.ZERO)) - .divide(MICRO_SECONDS_IN_A_DAY); + minter.set(_address); } @External(readonly = true) - public Map detailsBalanceOf(Address _owner) { - DictDB stakingDetail = stakedBalances.at(_owner); - BigInteger unstakingTime = stakingDetail.getOrDefault(Status.UNSTAKING_PERIOD.code, BigInteger.ZERO); - BigInteger currUnstaked = stakingDetail.getOrDefault(Status.UNSTAKING.code, BigInteger.ZERO); - BigInteger availableBalance = stakingDetail.getOrDefault(Status.AVAILABLE.code, BigInteger.ZERO); - BigInteger stakedBalance = stakingDetail.getOrDefault(Status.STAKED.code, BigInteger.ZERO); - - if (unstakingTime.compareTo(BigInteger.valueOf(Context.getBlockTimestamp())) >= 0) { - currUnstaked = BigInteger.ZERO; - } - - BigInteger unstakingAmount = stakingDetail.getOrDefault(Status.UNSTAKING.code, BigInteger.ZERO) - .subtract(currUnstaked); - - if (unstakingAmount.equals(BigInteger.ZERO)) { - unstakingTime = BigInteger.ZERO; - } - - if (this.firstTime(_owner)) { - availableBalance = this.balanceOf(_owner); - } - - return Map.of( - "Total balance", this.balanceOf(_owner), - "Available balance", availableBalance.add(currUnstaked), - "Staked balance", stakedBalance, - "Unstaking balance", unstakingAmount, - "Unstaking time (in microseconds)", unstakingTime); - } - - private boolean firstTime(Address from) { - DictDB stakingDetail = stakedBalances.at(from); - return (stakingDetail.getOrDefault(Status.AVAILABLE.code, BigInteger.ZERO).equals(BigInteger.ZERO) - && stakingDetail.getOrDefault(Status.STAKED.code, BigInteger.ZERO).equals(BigInteger.ZERO) - && stakingDetail.getOrDefault(Status.UNSTAKING.code, BigInteger.ZERO).equals(BigInteger.ZERO) - && !this.balanceOf(from).equals(BigInteger.ZERO)); + public Address getMinter() { + return minter.get(); } @External(readonly = true) public BigInteger unstakedBalanceOf(Address _owner) { - Map detailBalance = this.detailsBalanceOf(_owner); - return detailBalance.get("Unstaking balance"); + return this.balanceOf(_owner); } @External(readonly = true) public BigInteger stakedBalanceOf(Address _owner) { - return stakedBalances.at(_owner).getOrDefault(Status.STAKED.code, BigInteger.ZERO); + return BigInteger.ZERO; } @External(readonly = true) public BigInteger availableBalanceOf(Address _owner) { - Map detailBalance = this.detailsBalanceOf(_owner); - return detailBalance.get("Available balance"); + return this.balanceOf(_owner); } @External(readonly = true) public BigInteger totalStakedBalance() { - return totalStakedBalance.getOrDefault(BigInteger.ZERO); - } - - private void checkFirstTime(Address from) { - // If first time copy the balance to available staked balances - if (this.firstTime(from)) { - stakedBalances.at(from).set(Status.AVAILABLE.code, this.balanceOf(from)); - } - } - - private void stakingEnabledOnly() { - Context.require(stakingEnabled.getOrDefault(false), TAG + ": Staking must first be enabled."); - } - - private void makeAvailable(Address from) { - DictDB stakingDetail = stakedBalances.at(from); - - BigInteger unstakingTime = stakingDetail.getOrDefault(Status.UNSTAKING_PERIOD.code, BigInteger.ZERO); - if (unstakingTime.compareTo(BigInteger.valueOf(Context.getBlockTimestamp())) <= 0) { - BigInteger currUnstaked = stakingDetail.getOrDefault(Status.UNSTAKING.code, BigInteger.ZERO); - stakingDetail.set(Status.UNSTAKING.code, null); - stakingDetail.set(Status.AVAILABLE.code, stakingDetail.getOrDefault(Status.AVAILABLE.code, - BigInteger.ZERO).add(currUnstaked)); - } - } - - @External - public void stake(BigInteger _value) { - checkStatus(); - this.stakingEnabledOnly(); - Address from = Context.getCaller(); - - Context.require(_value.compareTo(BigInteger.ZERO) >= 0, TAG + ": Staked BALN value can't be less than zero"); - Context.require(_value.compareTo(this.balanceOf(from)) <= 0, TAG + ": Out of BALN balance."); - if ((_value.compareTo(minimumStake.getOrDefault(BigInteger.ZERO)) < 0) - && !(_value.equals(BigInteger.ZERO))) { - throw new UserRevertedException(TAG + ": Staked BALN must be greater than the minimum stake amount and " + - "non zero"); - } - - this.checkFirstTime(from); - this.makeAvailable(from); - - DictDB stakingDetail = stakedBalances.at(from); - BigInteger stakedAmount = stakingDetail.getOrDefault(Status.STAKED.code, BigInteger.ZERO); - - BigInteger oldStake = stakedAmount.add(stakingDetail.getOrDefault(Status.UNSTAKING.code, BigInteger.ZERO)); - BigInteger stakeIncrement = _value.subtract(stakedAmount); - BigInteger unstakeAmount = BigInteger.ZERO; - - if (_value.compareTo(oldStake) > 0) { - BigInteger offset = _value.subtract(oldStake); - stakingDetail.set(Status.AVAILABLE.code, stakingDetail.getOrDefault(Status.AVAILABLE.code, - BigInteger.ZERO).subtract(offset)); - } else { - unstakeAmount = oldStake.subtract(_value); - } - - stakingDetail.set(Status.STAKED.code, _value); - stakingDetail.set(Status.UNSTAKING.code, unstakeAmount); - stakingDetail.set(Status.UNSTAKING_PERIOD.code, BigInteger.valueOf(Context.getBlockTimestamp()) - .add(unstakingPeriod.getOrDefault(BigInteger.ZERO))); - - BigInteger newTotal = totalStakedBalance.getOrDefault(BigInteger.ZERO).add(stakeIncrement); - totalStakedBalance.set(newTotal); - - if (enableSnapshots.getOrDefault(false)) { - this.updateSnapshotForAddress(Context.getCaller(), _value); - this.updateTotalStakedSnapshot(newTotal); - } - - Context.call(dividendsScore.get(), "updateBalnStake", from, stakedAmount, newTotal); + return BigInteger.ZERO; } @External public void govTransfer(Address _from, Address _to, BigInteger _value, @Optional byte[] _data) { onlyGovernance(); - Address from = _from; - this.checkFirstTime(from); - this.checkFirstTime(_to); - this.makeAvailable(from); - this.makeAvailable(_to); - - DictDB stakingDetailOfSender = stakedBalances.at(from); - BigInteger availableAmountOfSender = stakingDetailOfSender.getOrDefault(Status.AVAILABLE.code, BigInteger.ZERO); - - Context.require(availableAmountOfSender.compareTo(_value) >= 0, TAG + ": Out of available balance. Please " + - "check staked and total balance."); + super._transfer(new NetworkAddress(NATIVE_NID, _from), new NetworkAddress(NATIVE_NID, _to), _value, _data); + } - stakingDetailOfSender.set(Status.AVAILABLE.code, availableAmountOfSender.subtract(_value)); - DictDB stakingDetailOfReceiver = stakedBalances.at(_to); - stakingDetailOfReceiver.set(Status.AVAILABLE.code, - stakingDetailOfReceiver.getOrDefault(Status.AVAILABLE.code, BigInteger.ZERO).add(_value)); - super.transfer(_to, _value, _data); - } - @Override @External public void transfer(Address _to, BigInteger _value, @Optional byte[] _data) { checkStatus(); - Address from = Context.getCaller(); - this.checkFirstTime(from); - this.checkFirstTime(_to); - this.makeAvailable(from); - this.makeAvailable(_to); - - DictDB stakingDetailOfSender = stakedBalances.at(from); - BigInteger availableAmountOfSender = stakingDetailOfSender.getOrDefault(Status.AVAILABLE.code, BigInteger.ZERO); - - Context.require(availableAmountOfSender.compareTo(_value) >= 0, TAG + ": Out of available balance. Please " + - "check staked and total balance."); - - stakingDetailOfSender.set(Status.AVAILABLE.code, availableAmountOfSender.subtract(_value)); - DictDB stakingDetailOfReceiver = stakedBalances.at(_to); - stakingDetailOfReceiver.set(Status.AVAILABLE.code, - stakingDetailOfReceiver.getOrDefault(Status.AVAILABLE.code, BigInteger.ZERO).add(_value)); - super.transfer(_to, _value, _data); } - @Override + @External + public void hubTransfer(String _to, BigInteger _value, @Optional byte[] _data) { + checkStatus(); + super.hubTransfer(_to, _value, _data); + } @External public void mint(BigInteger _amount, @Optional byte[] _data) { Address to = Context.getCaller(); this.mintTo(to, _amount, _data); } - @Override @External public void mintTo(Address _account, BigInteger _amount, @Optional byte[] _data) { checkStatus(); - this.checkFirstTime(_account); - this.makeAvailable(_account); - DictDB stakingDetailOfReceiver = stakedBalances.at(_account); - stakingDetailOfReceiver.set(Status.AVAILABLE.code, - stakingDetailOfReceiver.getOrDefault(Status.AVAILABLE.code, BigInteger.ZERO).add(_amount)); + only(minter); mintWithTokenFallback(_account, _amount, _data); } - @Override @External public void burn(BigInteger _amount) { Address from = Context.getCaller(); this.burnFrom(from, _amount); } - @Override - public BigInteger getHopFee(String net) { - if (!canWithdraw(net)) { - return BigInteger.ONE.negate(); - } - return Context.call(BigInteger.class, BalancedAddressManager.getDaofund(), "claimXCallFee", net, false); - } - - private boolean canWithdraw(String net) { - return Context.call(Boolean.class, BalancedAddressManager.getDaofund(), "getXCallFeePermission", Context.getAddress(), net); - } - - @Override @External public void burnFrom(Address _account, BigInteger _amount) { - this.checkFirstTime(_account); - this.makeAvailable(_account); - - DictDB stakingDetail = stakedBalances.at(_account); - BigInteger availableBalance = stakingDetail.getOrDefault(Status.AVAILABLE.code, BigInteger.ZERO); - - Context.require(availableBalance.compareTo(_amount) >= 0, TAG + ": Out of available balance. Please check " + - "staked and total balance."); - stakingDetail.set(Status.AVAILABLE.code, availableBalance.subtract(_amount)); - + only(minter); super.burn(new NetworkAddress(NATIVE_NID, _account), _amount); } @@ -548,120 +154,17 @@ protected void mintWithTokenFallback(Address _to, BigInteger _amount, byte[] _da } } - // ---------------------------------------------------------- - // Snapshots - // ---------------------------------------------------------- - - private void updateSnapshotForAddress(Address account, BigInteger amount) { - if (timeOffset.getOrDefault(BigInteger.ZERO).equals(BigInteger.ZERO)) { - this.setTimeOffset(); - } - - BigInteger currentId = this.getDay(); - int totalSnapshotsTaken = totalSnapshots.getOrDefault(account, 0); - - BranchDB> stakeSnapshots = BalancedTokenVariables.stakeSnapshots.at(account); - if (totalSnapshotsTaken > 0 && stakeSnapshots.at(totalSnapshotsTaken - 1).getOrDefault(IDS, BigInteger.ZERO) - .equals(currentId)) { - stakeSnapshots.at(totalSnapshotsTaken - 1).set(AMOUNT, amount); - } else { - stakeSnapshots.at(totalSnapshotsTaken).set(IDS, currentId); - stakeSnapshots.at(totalSnapshotsTaken).set(AMOUNT, amount); - totalSnapshots.set(account, totalSnapshotsTaken + 1); - } - } - - private void updateTotalStakedSnapshot(BigInteger amount) { - - if (timeOffset.getOrDefault(BigInteger.ZERO).equals(BigInteger.ZERO)) { - this.setTimeOffset(); - } - - BigInteger currentId = this.getDay(); - int totalSnapshotsTaken = totalStakedSnapshotCount.getOrDefault(0); - - if (totalSnapshotsTaken > 0 && totalStakedSnapshot.at(totalSnapshotsTaken - 1).getOrDefault(IDS, - BigInteger.ZERO).equals(currentId)) { - totalStakedSnapshot.at(totalSnapshotsTaken - 1).set(AMOUNT, amount); - } else { - totalStakedSnapshot.at(totalSnapshotsTaken).set(IDS, currentId); - totalStakedSnapshot.at(totalSnapshotsTaken).set(AMOUNT, amount); - totalStakedSnapshotCount.set(totalSnapshotsTaken + 1); - } - } - - @External(readonly = true) - public BigInteger stakedBalanceOfAt(Address _account, BigInteger _day) { - BigInteger currentDay = this.getDay(); - if (_day.compareTo(currentDay) > 0) { - Context.revert(TAG + ": Asked _day is greater than current day"); - } - - int totalSnapshotsTaken = totalSnapshots.getOrDefault(_account, 0); - if (totalSnapshotsTaken == 0) { - return BigInteger.ZERO; - } - - BranchDB> stakeSnapshotDetail = stakeSnapshots.at(_account); - if (stakeSnapshotDetail.at(totalSnapshotsTaken - 1).getOrDefault(IDS, BigInteger.ZERO).compareTo(_day) <= 0) { - return stakeSnapshotDetail.at(totalSnapshotsTaken - 1).getOrDefault(AMOUNT, BigInteger.ZERO); - } - - return getSnapshotAmount(_day, totalSnapshotsTaken, stakeSnapshotDetail); - } - - private BigInteger getSnapshotAmount(BigInteger _day, int totalSnapshotsTaken, - BranchDB> stakeSnapshotDetail) { - if (stakeSnapshotDetail.at(0).getOrDefault(IDS, BigInteger.ZERO).compareTo(_day) > 0) { - return BigInteger.ZERO; - } - - int low = 0; - int high = totalSnapshotsTaken - 1; - while (high > low) { - int mid = high - (high - low) / 2; - DictDB midValue = stakeSnapshotDetail.at(mid); - if (midValue.getOrDefault(IDS, BigInteger.ZERO).equals(_day)) { - return midValue.getOrDefault(AMOUNT, BigInteger.ZERO); - } else if (midValue.getOrDefault(IDS, BigInteger.ZERO).compareTo(_day) < 0) { - low = mid; - } else { - high = mid - 1; - } + @Override + public BigInteger getHopFee(String net) { + if (!canWithdraw(net)) { + return BigInteger.ONE.negate(); } - - return stakeSnapshotDetail.at(low).getOrDefault(AMOUNT, BigInteger.ZERO); + return Context.call(BigInteger.class, BalancedAddressManager.getDaofund(), "claimXCallFee", net, false); } - @External(readonly = true) - public BigInteger totalStakedBalanceOfAt(BigInteger _day) { - BigInteger currentDay = this.getDay(); - if (_day.compareTo(currentDay) > 0) { - Context.revert(TAG + ": Asked _day is greater than current day"); - } - - int totalSnapshotsTaken = totalStakedSnapshotCount.getOrDefault(0); - if (totalSnapshotsTaken == 0) { - return BigInteger.ZERO; - } - - BranchDB> totalStakedSnapshot = BalancedTokenVariables.totalStakedSnapshot; - BigInteger id = totalStakedSnapshot.at(totalSnapshotsTaken - 1).getOrDefault(IDS, BigInteger.ZERO); - if (id.compareTo(_day) <= 0) { - return totalStakedSnapshot.at(totalSnapshotsTaken - 1).getOrDefault(AMOUNT, BigInteger.ZERO); - } - - return getSnapshotAmount(_day, totalSnapshotsTaken, totalStakedSnapshot); + private boolean canWithdraw(String net) { + return Context.call(Boolean.class, BalancedAddressManager.getDaofund(), "getXCallFeePermission", Context.getAddress(), net); } +} - @External - public void setMinter(Address _address) { - onlyOwner(); - minter.set(_address); - } - @External(readonly = true) - public Address getMinter() { - return minter.get(); - } -} diff --git a/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/BalancedTokenVariables.java b/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/BalancedTokenVariables.java index b2b9e7ae4..ce7dc2063 100644 --- a/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/BalancedTokenVariables.java +++ b/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/BalancedTokenVariables.java @@ -1,50 +1,11 @@ package network.balanced.score.tokens.balancedtoken; -import java.math.BigInteger; -import score.Address; import score.Context; -import score.DictDB; import score.VarDB; -import score.BranchDB; import static network.balanced.score.tokens.balancedtoken.Constants.*; public class BalancedTokenVariables { - static final VarDB
dexScore = Context.newVarDB(DEX_SCORE, Address.class); - static final VarDB
bnusdScore = Context.newVarDB(BNUSD_SCORE, Address.class); - static final VarDB
governance = Context.newVarDB(GOVERNANCE, Address.class); - static final VarDB
oracle = Context.newVarDB(ORACLE, Address.class); - - static final VarDB oracleName = Context.newVarDB(ORACLE_NAME, String.class); - static final VarDB priceUpdateTime = Context.newVarDB(PRICE_UPDATE_TIME, BigInteger.class); - static final VarDB lastPrice = Context.newVarDB(LAST_PRICE, BigInteger.class); - static final VarDB minInterval = Context.newVarDB(MIN_INTERVAL, BigInteger.class); - - static final VarDB stakingEnabled = Context.newVarDB(STAKING_ENABLED, Boolean.class); - static final BranchDB> stakedBalances = Context.newBranchDB(STAKED_BALANCES, - BigInteger.class); - static final VarDB minimumStake = Context.newVarDB(MINIMUM_STAKE, BigInteger.class); - static final VarDB unstakingPeriod = Context.newVarDB(UNSTAKING_PERIOD, BigInteger.class); - static final VarDB totalStakedBalance = Context.newVarDB(TOTAL_STAKED_BALANCE, BigInteger.class); - - static final VarDB
dividendsScore = Context.newVarDB(DIVIDENDS_SCORE, Address.class); - static final VarDB timeOffset = Context.newVarDB(TIME_OFFSET, BigInteger.class); - - // [address][snapshot_id]["ids" || "amount"] - static final BranchDB>> stakeSnapshots = Context - .newBranchDB(STAKE_SNAPSHOTS, BigInteger.class); - // [address] = total_number_of_snapshots_taken - static final DictDB totalSnapshots = Context.newDictDB(TOTAL_SNAPSHOTS, Integer.class); - - // [snapshot_id]["ids" || "amount"] - static final BranchDB> totalStakedSnapshot = Context - .newBranchDB(TOTAL_STAKED_SNAPSHOT, BigInteger.class); - static final VarDB totalStakedSnapshotCount = Context.newVarDB(TOTAL_STAKED_SNAPSHOT_COUNT, - Integer.class); - - static final VarDB enableSnapshots = Context.newVarDB(ENABLE_SNAPSHOTS, Boolean.class); - static final VarDB
admin = Context.newVarDB(ADMIN, Address.class); - static final VarDB currentVersion = Context.newVarDB(VERSION, String.class); } diff --git a/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/Constants.java b/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/Constants.java index 61ed65886..318735c1c 100644 --- a/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/Constants.java +++ b/token-contracts/BalancedToken/src/main/java/network/balanced/score/tokens/balancedtoken/Constants.java @@ -25,46 +25,13 @@ public interface Constants { - BigInteger INITIAL_PRICE_ESTIMATE = pow(BigInteger.TEN, 17); //# loop BigInteger MIN_UPDATE_TIME = BigInteger.TWO.multiply(MICRO_SECONDS_IN_A_SECOND); //2 seconds - BigInteger MINIMUM_STAKE_AMOUNT = EXA; - BigInteger DEFAULT_UNSTAKING_PERIOD = BigInteger.valueOf(3).multiply(MICRO_SECONDS_IN_A_DAY); - - String IDS = "ids"; - String AMOUNT = "amount"; + // String IDS = "ids"; + // String AMOUNT = "amount"; String TAG = "BALN"; String TOKEN_NAME = Names.BALN; String SYMBOL_NAME = "BALN"; - String DEFAULT_ORACLE_NAME = "Balanced DEX"; - - String PRICE_UPDATE_TIME = "price_update_time"; - String LAST_PRICE = "last_price"; - String MIN_INTERVAL = "min_interval"; - - String STAKING_ENABLED = "staking_enabled"; - - String STAKED_BALANCES = "staked_balances"; - String MINIMUM_STAKE = "minimum_stake"; - String UNSTAKING_PERIOD = "unstaking_period"; - String TOTAL_STAKED_BALANCE = "total_staked_balance"; - - String DIVIDENDS_SCORE = "dividends_score"; - String GOVERNANCE = "governance"; - - String DEX_SCORE = "dex_score"; - String BNUSD_SCORE = "bnUSD_score"; - String ORACLE = "oracle"; - String ORACLE_NAME = "oracle_name"; - - String TIME_OFFSET = "time_offset"; - String STAKE_SNAPSHOTS = "stake_snapshots"; - String TOTAL_SNAPSHOTS = "total_snapshots"; - String TOTAL_STAKED_SNAPSHOT = "total_staked_snapshot"; - String TOTAL_STAKED_SNAPSHOT_COUNT = "total_staked_snapshot_count"; - - String ENABLE_SNAPSHOTS = "enable_snapshots"; - String ADMIN = "admin_address"; String VERSION = "version"; String MINTER = "admin"; diff --git a/token-contracts/BalancedToken/src/test/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImplTest.java b/token-contracts/BalancedToken/src/test/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImplTest.java index 67914d27c..3e8450dc3 100644 --- a/token-contracts/BalancedToken/src/test/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImplTest.java +++ b/token-contracts/BalancedToken/src/test/java/network/balanced/score/tokens/balancedtoken/BalancedTokenImplTest.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; import org.mockito.MockedStatic; import org.mockito.Mockito; import score.Address; @@ -38,6 +39,7 @@ import static java.math.BigInteger.*; import static network.balanced.score.lib.test.UnitTest.*; import static network.balanced.score.lib.utils.Constants.MICRO_SECONDS_IN_A_DAY; +import static network.balanced.score.lib.test.UnitTest.expectErrorMessage; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.eq; @@ -64,21 +66,16 @@ class BalancedTokenImplTest extends TestBase { private final Account bnusdScore = Account.newScoreAccount(scoreCount++); private final Account dividendsScore = Account.newScoreAccount(scoreCount++); - private final MockedStatic contextMock = Mockito.mockStatic(Context.class, Mockito.CALLS_REAL_METHODS); private static MockBalanced mockBalanced; private static Account governanceScore; - private static Account xCall; @BeforeEach void deploy() throws Exception { mockBalanced = new MockBalanced(sm, owner); governanceScore = mockBalanced.governance.account; - xCall = mockBalanced.xCall.account; - contextMock.when(() -> Context.call(eq(governanceScore.getAddress()), eq("checkStatus"), any(String.class))) - .thenReturn(null); - contextMock.when(() -> Context.call(eq(xCall.getAddress()), eq("getNetworkId"), any(String.class))) - .thenReturn("0x1.icon"); + + when(mockBalanced.xCall.mock.getNetworkId()).thenReturn("0x1.icon"); balancedToken = sm.deploy(owner, BalancedTokenImpl.class, governanceScore.getAddress()); mockDexScore = sm.deploy(owner, MockDexScore.class); @@ -86,507 +83,85 @@ void deploy() throws Exception { balancedToken.setInstance(balancedTokenSpy); } - private void setup() { - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); - balancedToken.invoke(governanceScore, "setBnusd", bnusdScore.getAddress()); - balancedToken.invoke(governanceScore, "setOracle", oracleScore.getAddress()); - balancedToken.invoke(governanceScore, "setDex", dexScore.getAddress()); - balancedToken.invoke(governanceScore, "setDividends", dividendsScore.getAddress()); - } - - private void mockUpdateBalnStake(Address from, BigInteger oldStake, BigInteger newTotal) { - contextMock.when(() -> Context.call(dividendsScore.getAddress(), "updateBalnStake", from, oldStake, newTotal)) - .thenReturn(null); - } - @Test void getPeg() { assertEquals("BALN", balancedToken.call("getPeg")); } - @Test - void setAndGetGovernance() { - testGovernance(balancedToken, governanceScore, owner); - } - - @Test - void setAndGetAdmin() { - testAdmin(balancedToken, governanceScore, adminAccount); - } - - @Test - void setAndGetBnusd() { - testContractSettersAndGetters(balancedToken, governanceScore, governanceScore, "setBnusd", - bnusdScore.getAddress(), - "getBnusd"); - } - - @Test - void setAndGetOracle() { - testContractSettersAndGetters(balancedToken, governanceScore, governanceScore, "setOracle", - oracleScore.getAddress(), - "getOracle"); - } - - @Test - void setAndGetDex() { - testContractSettersAndGetters(balancedToken, governanceScore, governanceScore, "setDex", dexScore.getAddress(), - "getDex"); - } - - @Test - void setAndGetDividends() { - testContractSettersAndGetters(balancedToken, governanceScore, governanceScore, "setDividends", - dividendsScore.getAddress(), "getDividends"); - } - - @Test - void setAndGetOracleName() { - assertEquals("Balanced DEX", balancedToken.call("getOracleName")); - - String newOracleName = "ChainLink"; - testAdminControlMethods(balancedToken, governanceScore, governanceScore, "setOracleName", newOracleName, - "getOracleName"); - } - - @Test - void setAndGetMinIntervalTime() { - BigInteger TWO_SECONDS = BigInteger.valueOf(2_000_000); - assertEquals(TWO_SECONDS, balancedToken.call("getMinInterval")); - BigInteger newMinInterval = BigInteger.valueOf(20_000_000); - // balancedToken.invoke(owner, "removeGovernance"); - testAdminControlMethods(balancedToken, governanceScore, governanceScore, "setMinInterval", newMinInterval, - "getMinInterval"); - } - - @Test - void priceInLoop() { - setup(); - BigInteger newBalnPriceInUsd = BigInteger.valueOf(250).multiply(BigInteger.TEN.pow(16)); - BigInteger newUsdPriceInIcx = BigInteger.valueOf(120).multiply(BigInteger.TEN.pow(16)); - - BigInteger newBalnPriceInIcx = newBalnPriceInUsd.multiply(newUsdPriceInIcx).divide(ICX); - - Map priceData = Map.of("last_update_base", "0x5dd26d3bd5dcf", "last_update_quote", - "0x5dd26cb9b4680", "rate", newUsdPriceInIcx); - contextMock - .when(() -> Context.call(eq(oracleScore.getAddress()), eq("get_reference_data"), eq("USD"), eq("ICX"))) - .thenReturn(priceData); - contextMock.when(() -> Context.call(BigInteger.class, dexScore.getAddress(), "getBalnPrice")) - .thenReturn(newBalnPriceInUsd); - - balancedToken.invoke(owner, "priceInLoop"); - verify(balancedTokenSpy).OraclePrice("BALNICX", "Balanced DEX", dexScore.getAddress(), newBalnPriceInIcx); - assertEquals(BigInteger.valueOf(sm.getBlock().getTimestamp()), balancedToken.call("getPriceUpdateTime")); - assertEquals(newBalnPriceInIcx, balancedToken.call("priceInLoop")); - - assertEquals(newBalnPriceInIcx, balancedToken.call("lastPriceInLoop")); - } - - @Test - void setAndGetMinimumStake() { - BigInteger minStake = (BigInteger) balancedToken.call("getMinimumStake"); - - assertNotNull(minStake); - assertEquals(BigInteger.valueOf(1000000000000000000L), minStake); - - BigInteger newMinStake = TEN.add(TWO).add(ONE); - balancedToken.invoke(governanceScore, "setAdmin", governanceScore.getAddress()); - - balancedToken.invoke(governanceScore, "setMinimumStake", newMinStake); - - minStake = (BigInteger) balancedToken.call("getMinimumStake"); - - assertNotNull(minStake); - assertEquals(new BigInteger("13000000000000000000"), minStake); - } @SuppressWarnings("unchecked") @Test void ShouldMint() { - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); BigInteger amount = BigInteger.valueOf(10000L); balancedToken.invoke(adminAccount, "mint", amount, "init gold".getBytes()); - Map balanceDetails = (Map) balancedToken.call("detailsBalanceOf", - adminAccount.getAddress()); + BigInteger balance = (BigInteger) balancedToken.call("balanceOf", adminAccount.getAddress()); - assertNotNull(balanceDetails); - assertEquals(amount, balanceDetails.get("Total balance")); - assertEquals(amount, balanceDetails.get("Available balance")); + assertEquals(amount, balance); } @SuppressWarnings("unchecked") @Test void ShouldMintToSomeone() { Account accountToMint = sm.createAccount(); - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); - BigInteger amount = BigInteger.valueOf(10000L); balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); balancedToken.invoke(adminAccount, "mintTo", accountToMint.getAddress(), amount, "init gold".getBytes()); - Map balanceDetails = (Map) balancedToken.call("detailsBalanceOf", - accountToMint.getAddress()); - assertNotNull(balanceDetails); - assertEquals(amount, balanceDetails.get("Total balance")); - assertEquals(amount, balanceDetails.get("Available balance")); - } - - @SuppressWarnings("unchecked") - @Test - void ShouldMintAndStake() { - // mint some tokens - BigInteger amountToMint = BigInteger.valueOf(10000L).multiply(ICX); - balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); - balancedToken.invoke(governanceScore, "setAdmin", governanceScore.getAddress()); - balancedToken.invoke(governanceScore, "setDividends", dividendsScore.getAddress()); - - balancedToken.invoke(adminAccount, "mint", amountToMint, "init gold".getBytes()); - - BigInteger stakedAmount = amountToMint.divide(TWO); - balancedToken.invoke(governanceScore, "setDex", mockDexScore.getAddress()); - contextMock.when(() -> Context.call(BigInteger.class, mockDexScore.getAddress(), "getTimeOffset")) - .thenReturn(BigInteger.valueOf(500)); - balancedToken.invoke(owner, "setTimeOffset"); - - // stake - mockUpdateBalnStake(adminAccount.getAddress(), BigInteger.ZERO, stakedAmount); - balancedToken.invoke(adminAccount, "stake", stakedAmount); - - Map balanceDetails = (Map) balancedToken.call("detailsBalanceOf", - adminAccount.getAddress()); - - assertNotNull(balanceDetails); - assertEquals(amountToMint, balanceDetails.get("Total balance")); - assertEquals(amountToMint.divide(TWO), balanceDetails.get("Available balance")); - assertEquals(amountToMint.divide(TWO), balanceDetails.get("Staked balance")); - } - - @SuppressWarnings("unchecked") - @Test - void ShouldGetATransferAndStake() { - // set admin - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); - balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); - balancedToken.invoke(governanceScore, "setDividends", dividendsScore.getAddress()); - - // mint some tokens - BigInteger amountToMint = BigInteger.valueOf(10000L).multiply(ICX); - balancedToken.invoke(adminAccount, "mint", amountToMint, "init gold".getBytes()); - - // transfer - Account user = sm.createAccount(); - BigInteger amountToTransfer = amountToMint.divide(TWO).divide(TWO); - balancedToken.invoke(adminAccount, "transfer", user.getAddress(), amountToTransfer, "quezadillas".getBytes()); - - BigInteger stakedAmount = amountToTransfer.divide(TWO); - balancedToken.invoke(governanceScore, "setDex", mockDexScore.getAddress()); - contextMock.when(() -> Context.call(BigInteger.class, mockDexScore.getAddress(), "getTimeOffset")) - .thenReturn(BigInteger.valueOf(500)); - balancedToken.invoke(owner, "setTimeOffset"); - // stake - mockUpdateBalnStake(user.getAddress(), BigInteger.ZERO, stakedAmount); - balancedToken.invoke(user, "stake", stakedAmount); - - Map balanceDetails = (Map) balancedToken.call("detailsBalanceOf", - user.getAddress()); - - assertNotNull(balanceDetails); - assertEquals(amountToTransfer, balanceDetails.get("Total balance")); - - assertEquals(amountToTransfer.divide(TWO), balancedToken.call("availableBalanceOf", user.getAddress())); - assertEquals(amountToTransfer.divide(TWO), balancedToken.call("stakedBalanceOf", user.getAddress())); - assertEquals(ZERO, balancedToken.call("unstakedBalanceOf", user.getAddress())); - - } - - @SuppressWarnings("unchecked") - @Test - void ShouldTransfer() { - // set admin - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); - balancedToken.invoke(governanceScore, "setDividends", dividendsScore.getAddress()); - - // mint some tokens - BigInteger amountToMint = BigInteger.valueOf(10000L).multiply(ICX); - balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); - - balancedToken.invoke(adminAccount, "mint", amountToMint, "init gold".getBytes()); - - BigInteger stakedAmount = amountToMint.divide(TWO); - - balancedToken.invoke(governanceScore, "setDex", mockDexScore.getAddress()); - - contextMock.when(() -> Context.call(BigInteger.class, mockDexScore.getAddress(), "getTimeOffset")) - .thenReturn(BigInteger.valueOf(500)); - balancedToken.invoke(owner, "setTimeOffset"); - - // Stake - mockUpdateBalnStake(adminAccount.getAddress(), BigInteger.ZERO, stakedAmount); - balancedToken.invoke(adminAccount, "stake", stakedAmount); - - // transfer - Account user = sm.createAccount(); - BigInteger amountToTransfer = amountToMint.divide(TWO).divide(TWO); - balancedToken.invoke(adminAccount, "transfer", user.getAddress(), amountToTransfer, "tacos".getBytes()); - - Map balanceDetails = (Map) balancedToken.call("detailsBalanceOf", - user.getAddress()); - - assertNotNull(balanceDetails); - assertEquals(amountToTransfer, balanceDetails.get("Total balance")); - assertEquals(amountToTransfer, balanceDetails.get("Available balance")); + BigInteger balance = (BigInteger) balancedToken.call("balanceOf", accountToMint.getAddress()); + assertEquals(amount, balance); } @SuppressWarnings("unchecked") @Test void ShouldBurn() { - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); BigInteger amount = BigInteger.valueOf(10000L); balancedToken.invoke(adminAccount, "mint", amount, "init gold".getBytes()); - Map balanceDetails = (Map) balancedToken.call("detailsBalanceOf", - adminAccount.getAddress()); - - assertNotNull(balanceDetails); - assertEquals(amount, balanceDetails.get("Total balance")); - assertEquals(amount, balanceDetails.get("Available balance")); BigInteger balanceToBurn = amount.divide(TWO); balancedToken.invoke(adminAccount, "burn", balanceToBurn); - balanceDetails = (Map) balancedToken.call("detailsBalanceOf", adminAccount.getAddress()); + BigInteger balance = (BigInteger) balancedToken.call("balanceOf", adminAccount.getAddress()); - assertNotNull(balanceDetails); - assertEquals(balanceToBurn, balanceDetails.get("Total balance")); - assertEquals(balanceToBurn, balanceDetails.get("Available balance")); + assertEquals(amount.subtract(balanceToBurn), balance); } @SuppressWarnings("unchecked") @Test void ShouldBurnFrom() { Account accountToMint = sm.createAccount(); - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); BigInteger amount = BigInteger.valueOf(10000L); balancedToken.invoke(adminAccount, "mintTo", accountToMint.getAddress(), amount, "init gold".getBytes()); - Map balanceDetails = (Map) balancedToken.call("detailsBalanceOf", - accountToMint.getAddress()); - - assertNotNull(balanceDetails); - assertEquals(amount, balanceDetails.get("Total balance")); - assertEquals(amount, balanceDetails.get("Available balance")); - BigInteger balanceToBurn = amount.divide(TWO); balancedToken.invoke(adminAccount, "burnFrom", accountToMint.getAddress(), balanceToBurn); - balanceDetails = (Map) balancedToken.call("detailsBalanceOf", accountToMint.getAddress()); - - assertNotNull(balanceDetails); - assertEquals(balanceToBurn, balanceDetails.get("Total balance")); - assertEquals(balanceToBurn, balanceDetails.get("Available balance")); - } - - @SuppressWarnings("unchecked") - @Test - void ShouldGetStakedBalanceOfAt() { - balancedToken.invoke(governanceScore, "setDividends", dividendsScore.getAddress()); - boolean snapshotEnabled = (boolean) balancedToken.call("getSnapshotEnabled"); - if (!snapshotEnabled) { - // enable snapshot of staked balances - balancedToken.invoke(owner, "toggleEnableSnapshot"); - } - - // set admin - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); - balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); - - // mint some tokens - BigInteger amountToMint = BigInteger.valueOf(10000L).multiply(ICX); - balancedToken.invoke(adminAccount, "mintTo", owner.getAddress(), amountToMint, "init gold".getBytes()); - - // enable staking - if (!(boolean) balancedToken.call("getStakingEnabled")) { - balancedToken.invoke(governanceScore, "toggleStakingEnabled"); - } - - balancedToken.invoke(governanceScore, "setDex", mockDexScore.getAddress()); - BigInteger stakedAmount = amountToMint.divide(TWO); - - // staked balance when there is no stake for this address - BigInteger day = BigInteger.valueOf(Context.getBlockTimestamp()).divide(MICRO_SECONDS_IN_A_DAY); - BigInteger stakedBalance = (BigInteger) balancedToken.call("stakedBalanceOfAt", owner.getAddress(), day); - - assertNotNull(stakedBalance); - assertEquals(ZERO, stakedBalance); - - contextMock.when(() -> Context.call(BigInteger.class, mockDexScore.getAddress(), "getTimeOffset")) - .thenReturn(BigInteger.valueOf(500)); - // stake - mockUpdateBalnStake(owner.getAddress(), BigInteger.ZERO, stakedAmount); - balancedToken.invoke(owner, "stake", stakedAmount); - - day = BigInteger.valueOf(Context.getBlockTimestamp()).divide(MICRO_SECONDS_IN_A_DAY); - stakedBalance = (BigInteger) balancedToken.call("stakedBalanceOfAt", owner.getAddress(), day); - - assertNotNull(stakedBalance); - assertEquals(stakedAmount, stakedBalance); - - balancedToken.invoke(owner, "setTimeOffset"); - - // move the day, so there are 2 snapshots - sm.getBlock().increase(100_000_000_000L); - - // stake at next day - BigInteger stakedAmountAtSecondDay = stakedAmount.divide(TWO); - mockUpdateBalnStake(owner.getAddress(), stakedAmount, stakedAmountAtSecondDay); - balancedToken.invoke(owner, "stake", stakedAmountAtSecondDay); - - day = BigInteger.valueOf(Context.getBlockTimestamp()).divide(MICRO_SECONDS_IN_A_DAY); - // ask for staked balance of snapshot 1 - stakedBalance = (BigInteger) balancedToken.call("stakedBalanceOfAt", owner.getAddress(), day); - - assertNotNull(stakedBalance); - assertEquals(stakedAmountAtSecondDay, stakedBalance); - // get stake amount of 1st snapshot at 2nd day - day = BigInteger.valueOf(Context.getBlockTimestamp()).subtract(MICRO_SECONDS_IN_A_DAY) - .divide(MICRO_SECONDS_IN_A_DAY); - // ask for staked balance of snapshot 1 - stakedBalance = (BigInteger) balancedToken.call("stakedBalanceOfAt", owner.getAddress(), day); + BigInteger balance = (BigInteger) balancedToken.call("balanceOf", accountToMint.getAddress()); - assertNotNull(stakedBalance); - assertEquals(stakedAmount, stakedBalance); - - Map balanceDetails = (Map) balancedToken.call("detailsBalanceOf", - owner.getAddress()); - assertNotNull(balanceDetails); - - assertEquals(amountToMint, balanceDetails.get("Total balance")); - assertEquals(stakedAmount, balanceDetails.get("Available balance")); - assertEquals(stakedAmountAtSecondDay, balanceDetails.get("Staked balance")); - - balanceDetails = (Map) balancedToken.call("detailsBalanceOf", owner.getAddress()); - - assertEquals(stakedAmountAtSecondDay, balanceDetails.get("Unstaking balance")); + assertEquals(amount.subtract(balanceToBurn), balance); } @Test - void ShouldGetTotalStakedBalanceOfAt() { - balancedToken.invoke(governanceScore, "setDividends", dividendsScore.getAddress()); - Account staker = sm.createAccount(); - boolean snapshotEnabled = (boolean) balancedToken.call("getSnapshotEnabled"); - if (!snapshotEnabled) { - // enable snapshot of staked balances - balancedToken.invoke(owner, "toggleEnableSnapshot"); - } - - // set admin - balancedToken.invoke(governanceScore, "setAdmin", adminAccount.getAddress()); + void mintBurnPermissions() { + Account nonMinter = sm.createAccount(); balancedToken.invoke(owner, "setMinter", adminAccount.getAddress()); - // mint some tokens - BigInteger amountToMint = BigInteger.valueOf(10000L).multiply(ICX); - balancedToken.invoke(adminAccount, "mintTo", owner.getAddress(), amountToMint, "init gold".getBytes()); - balancedToken.invoke(adminAccount, "mintTo", staker.getAddress(), amountToMint, "init gold".getBytes()); - - // enable staking - if (!(boolean) balancedToken.call("getStakingEnabled")) { - balancedToken.invoke(governanceScore, "toggleStakingEnabled"); - } - - balancedToken.invoke(governanceScore, "setDex", mockDexScore.getAddress()); - BigInteger stakedAmount = amountToMint.divide(TWO); - - // staked balance when there is no stake for this address - BigInteger day1 = BigInteger.valueOf(Context.getBlockTimestamp()).divide(MICRO_SECONDS_IN_A_DAY); - BigInteger expectedTotalStakeDay1 = BigInteger.ZERO; - - contextMock.when(() -> Context.call(BigInteger.class, mockDexScore.getAddress(), "getTimeOffset")) - .thenReturn(BigInteger.valueOf(500)); - sm.getBlock().increase(DAY); - - // stake - mockUpdateBalnStake(owner.getAddress(), BigInteger.ZERO, stakedAmount); - balancedToken.invoke(owner, "stake", stakedAmount); + Executable wrongMinter = () -> balancedToken.invoke(nonMinter, "mint", BigInteger.ONE, new byte[0]); + expectErrorMessage(wrongMinter, "Authorization Check: Authorization failed."); - BigInteger day2 = BigInteger.valueOf(Context.getBlockTimestamp()).divide(MICRO_SECONDS_IN_A_DAY); - BigInteger expectedTotalStakeDay2 = stakedAmount; - balancedToken.invoke(owner, "setTimeOffset"); + wrongMinter = () -> balancedToken.invoke(nonMinter, "mintTo", adminAccount.getAddress(), BigInteger.ONE, new byte[0]); + expectErrorMessage(wrongMinter, "Authorization Check: Authorization failed."); - sm.getBlock().increase(DAY); - - // stake at next day - mockUpdateBalnStake(staker.getAddress(), BigInteger.ZERO, stakedAmount.add(amountToMint)); - balancedToken.invoke(staker, "stake", amountToMint); - - BigInteger day3 = BigInteger.valueOf(Context.getBlockTimestamp()).divide(MICRO_SECONDS_IN_A_DAY); - BigInteger expectedTotalStakeDay3 = expectedTotalStakeDay2.add(amountToMint); - - sm.getBlock().increase(DAY); - - mockUpdateBalnStake(staker.getAddress(), amountToMint, expectedTotalStakeDay3.subtract(stakedAmount)); - balancedToken.invoke(staker, "stake", stakedAmount); - BigInteger day4 = BigInteger.valueOf(Context.getBlockTimestamp()).divide(MICRO_SECONDS_IN_A_DAY); - BigInteger expectedTotalStakeDay4 = expectedTotalStakeDay3.subtract(stakedAmount); - sm.getBlock().increase(DAY); - - BigInteger totalStakeDay1 = (BigInteger) balancedToken.call("totalStakedBalanceOfAt", day1); - BigInteger totalStakeDay2 = (BigInteger) balancedToken.call("totalStakedBalanceOfAt", day2); - BigInteger totalStakeDay3 = (BigInteger) balancedToken.call("totalStakedBalanceOfAt", day3); - BigInteger totalStakeDay4 = (BigInteger) balancedToken.call("totalStakedBalanceOfAt", day4); - assertEquals(expectedTotalStakeDay1, totalStakeDay1); - assertEquals(expectedTotalStakeDay2, totalStakeDay2); - assertEquals(expectedTotalStakeDay3, totalStakeDay3); - assertEquals(expectedTotalStakeDay4, totalStakeDay4); - } - - @Test - void ShouldGetUnstakingPeriod() { - BigInteger unstakingPeriod = (BigInteger) balancedToken.call("getUnstakingPeriod"); - - assertNotNull(unstakingPeriod); - assertEquals(TWO.add(ONE), unstakingPeriod); - } - - @Test - void ShouldSetUnstakingPeriod() { - balancedToken.invoke(governanceScore, "setAdmin", governanceScore.getAddress()); - - balancedToken.invoke(governanceScore, "setUnstakingPeriod", TEN); - - BigInteger unstakingPeriod = (BigInteger) balancedToken.call("getUnstakingPeriod"); - - assertNotNull(unstakingPeriod); - assertEquals(TEN, unstakingPeriod); - - balancedToken.invoke(governanceScore, "setUnstakingPeriod", ZERO); - - unstakingPeriod = (BigInteger) balancedToken.call("getUnstakingPeriod"); - - assertNotNull(unstakingPeriod); - assertEquals(ZERO, unstakingPeriod); - } - - @Test - void ShouldSetDividends() { - // set admin - balancedToken.invoke(governanceScore, "setAdmin", governanceScore.getAddress()); - balancedToken.invoke(governanceScore, "setDividends", dividendsScore.getAddress()); - - Address dividendsAddress = (Address) balancedToken.call("getDividends"); - - assertNotNull(dividendsAddress); - assertEquals(dividendsScore.getAddress(), dividendsAddress); - } + wrongMinter = () -> balancedToken.invoke(nonMinter, "burn", BigInteger.ONE); + expectErrorMessage(wrongMinter, "Authorization Check: Authorization failed."); - @AfterEach - void contextClose() { - contextMock.close(); + wrongMinter = () -> balancedToken.invoke(nonMinter, "burnFrom", adminAccount.getAddress(), BigInteger.ONE); + expectErrorMessage(wrongMinter, "Authorization Check: Authorization failed."); } }