Skip to content

Commit 87b526c

Browse files
committed
feat: add logic to close to balanced Dao
1 parent d96c95e commit 87b526c

File tree

11 files changed

+170
-2
lines changed

11 files changed

+170
-2
lines changed

core-contracts/Governance/src/main/java/network/balanced/score/core/governance/GovernanceImpl.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public class GovernanceImpl implements Governance {
5454
public static final VarDB<BigInteger> bnusdVoteDefinitionFee = Context.newVarDB(DEFINITION_FEE, BigInteger.class);
5555
public static final VarDB<BigInteger> quorum = Context.newVarDB(QUORUM, BigInteger.class);
5656
private final VarDB<String> currentVersion = Context.newVarDB(VERSION, String.class);
57+
public static final VarDB<Boolean> isShutdown = Context.newVarDB("IS_SHUTDOWN", Boolean.class);
5758

5859
public GovernanceImpl() {
5960
if (launched.getOrDefault(null) == null) {
@@ -95,6 +96,23 @@ public void changeScoreOwner(Address score, Address newOwner) {
9596
Context.call(SYSTEM_SCORE_ADDRESS, "setScoreOwner", score, newOwner);
9697
}
9798

99+
@External
100+
public void setIsShutdown(boolean _isShutdown) {
101+
onlyOwnerOrContract();
102+
isShutdown.set(_isShutdown);
103+
}
104+
105+
@External(readonly = true)
106+
public boolean getIsShutdown() {
107+
return isShutdown.getOrDefault(false);
108+
}
109+
110+
protected void checkShutdownPermission() {
111+
if (isShutdown.getOrDefault(false)) {
112+
onlyOwnerOrContract();
113+
}
114+
}
115+
98116
@External
99117
public void setVoteDurationLimits(BigInteger min, BigInteger max) {
100118
onlyOwnerOrContract();
@@ -167,12 +185,14 @@ public BigInteger getBalnVoteDefinitionCriterion() {
167185
@External
168186
public void defineVote(String name, String description, BigInteger vote_start, BigInteger duration,
169187
String forumLink, @Optional String transactions) {
188+
checkShutdownPermission();
170189
transactions = optionalDefault(transactions, "[]");
171190
ProposalManager.defineVote(name, description, vote_start, duration, forumLink, transactions);
172191
}
173192

174193
@External
175194
public void cancelVote(BigInteger vote_index) {
195+
checkShutdownPermission();
176196
ProposalManager.cancelVote(vote_index);
177197
}
178198

@@ -201,6 +221,7 @@ public void castVote(BigInteger vote_index, boolean vote) {
201221

202222
@External
203223
public void evaluateVote(BigInteger vote_index) {
224+
checkShutdownPermission();
204225
ProposalManager.evaluateVote(vote_index);
205226
}
206227

core-contracts/Governance/src/test/java/network/balanced/score/core/governance/GovernanceVotingTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,26 @@ void defineVote() {
111111
assertEquals(ProposalStatus.STATUS[ProposalStatus.ACTIVE], vote.get("status"));
112112
}
113113

114+
@Test
115+
void defineVote_isShutdown() {
116+
// Arrange
117+
Account account = sm.createAccount();
118+
BigInteger day = (BigInteger) governance.call("getDay");
119+
String name = "test";
120+
String forumLink = "https://gov.balanced.network/";
121+
String description = "test vote";
122+
BigInteger voteStart = day.add(BigInteger.TWO);
123+
BigInteger voteDuration = BigInteger.TWO;
124+
String actions = "[]";
125+
String expectedErrorMessage;
126+
governance.invoke(owner, "setIsShutdown", true);
127+
128+
Executable whenShutdown = () -> governance.invoke(account, "defineVote", name, description, voteStart,
129+
voteDuration, forumLink, actions);
130+
expectErrorMessage(whenShutdown, "SenderNotScoreOwnerOrContract");
131+
132+
}
133+
114134
@Test
115135
void cancelVote_Owner() {
116136
// Arrange

core-contracts/Loans/src/main/java/network/balanced/score/core/loans/LoansImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import com.eclipsesource.json.Json;
2020
import com.eclipsesource.json.JsonObject;
2121
import com.eclipsesource.json.JsonValue;
22+
23+
import foundation.icon.xcall.NetworkAddress;
2224
import network.balanced.score.core.loans.collateral.CollateralDB;
2325
import network.balanced.score.core.loans.debt.DebtDB;
2426
import network.balanced.score.core.loans.positions.Position;

core-contracts/Loans/src/main/java/network/balanced/score/core/loans/debt/DebtDB.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ public static void claimInterest() {
215215
}
216216

217217
accumulatedInterest.set(BigInteger.ZERO);
218+
if (Context.call(Boolean.class, BalancedAddressManager.getGovernance(), "getIsShutdown")) {
219+
TokenUtils.mintAssetTo(BalancedAddressManager.getFeehandler(), accumulatedAmount);
220+
return;
221+
}
222+
218223
BigInteger savingsRateAmount = savingsShare.get().multiply(accumulatedAmount).divide(POINTS);
219224
TokenUtils.mintAssetTo(BalancedAddressManager.getSavings(), savingsRateAmount);
220225
TokenUtils.mintAssetTo(BalancedAddressManager.getFeehandler(), accumulatedAmount.subtract(savingsRateAmount));

core-contracts/Loans/src/test/java/network/balanced/score/core/loans/LoansTestInterest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,36 @@ void claimInterest() {
191191
assertRoundedEquals(expectedDebt.add(interest), debt);
192192
}
193193

194+
@Test
195+
void claimInterest_isShutdown() {
196+
// Arrange
197+
when(mockBalanced.governance.mock.getIsShutdown()).thenReturn(true);
198+
199+
Account account = sm.createAccount();
200+
BigInteger collateral = BigInteger.valueOf(1000000).multiply(EXA);
201+
BigInteger loan = BigInteger.valueOf(100000).multiply(EXA);
202+
BigInteger expectedFee = calculateFee(loan);
203+
BigInteger expectedDebt = loan.add(expectedFee);
204+
BigInteger timePassed = BigInteger.valueOf(20000);
205+
BigInteger savingsShare = BigInteger.valueOf(4000);
206+
loans.invoke(mockBalanced.governance.account, "setSavingsRateShare", savingsShare);
207+
208+
// Act
209+
takeLoanICX(account, "bnUSD", collateral, loan);
210+
sm.getBlock().increase(timePassed.longValue()/2);
211+
loans.invoke(mockBalanced.governance.account, "applyInterest");
212+
BigInteger debt = getUserDebt(account, "sICX");
213+
loans.invoke(account, "claimInterest");
214+
215+
// Assert
216+
BigInteger expectedInterest = expectedDebt.multiply(SICX_INTEREST).multiply(timePassed.multiply(MICRO_SECONDS_IN_A_SECOND))
217+
.divide(YEAR_IN_MICRO_SECONDS.multiply(POINTS));
218+
BigInteger interest = debt.subtract(expectedDebt);
219+
assertTrue(expectedInterest.compareTo(EXA) > 0);
220+
verify(mockBalanced.bnUSD.mock).mintTo(mockBalanced.feehandler.getAddress(), interest, new byte[0]);
221+
assertRoundedEquals(expectedDebt.add(interest), debt);
222+
}
223+
194224
@Test
195225
void permissions() {
196226
assertOnlyCallableBy(mockBalanced.governance.getAddress(), loans, "setSavingsRateShare", BigInteger.ONE);

core-contracts/Rewards/src/main/java/network/balanced/score/core/rewards/RewardsImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,12 @@ public boolean distribute() {
355355
}
356356

357357
private boolean mintAndAllocateBalnReward(BigInteger platformDay) {
358+
if (Context.call(Boolean.class, BalancedAddressManager.getGovernance(), "getIsShutdown")) {
359+
dailyVotableDistribution.set(platformDay, BigInteger.ZERO);
360+
RewardsImpl.platformDay.set(platformDay.add(BigInteger.ONE));
361+
return false;
362+
}
363+
358364
BigInteger distribution = dailyDistribution(platformDay);
359365
Context.call(getBaln(), "mint", distribution, new byte[0]);
360366

core-contracts/Rewards/src/test/java/network/balanced/score/core/rewards/RewardsTestRewards.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,26 @@ void distribute() {
6161
defaultPlatformDist.multiply(emission).divide(EXA), new byte[0]);
6262
}
6363

64+
@Test
65+
void distribute_shutdown() {
66+
// Act
67+
when(mockBalanced.governance.mock.getIsShutdown()).thenReturn(true);
68+
69+
sm.getBlock().increase(DAY);
70+
syncDistributions();
71+
int day = ((BigInteger) rewardsScore.call("getDay")).intValue();
72+
73+
// Assert
74+
BigInteger emission = (BigInteger) rewardsScore.call("getEmission", BigInteger.valueOf(-1));
75+
76+
verify(baln.mock, times(0)).transfer(bwt.getAddress(),
77+
BigInteger.ZERO, new byte[0]);
78+
verify(baln.mock, times(0)).transfer(daoFund.getAddress(),
79+
BigInteger.ZERO, new byte[0]);
80+
verify(baln.mock, times(0)).transfer(reserve.getAddress(),
81+
BigInteger.ZERO, new byte[0]);
82+
}
83+
6484
@Test
6585
void claimRewards_updateRewardsData() {
6686
// Arrange
@@ -101,6 +121,31 @@ void claimRewards_updateRewardsData() {
101121
verifyBalnReward(account.getAddress(), expectedRewards);
102122
}
103123

124+
125+
@Test
126+
void claimRewards_updateRewardsData_isShutdown() {
127+
// Arrange
128+
Account account = sm.createAccount();
129+
BigInteger loansBalance = BigInteger.ONE.multiply(EXA);
130+
BigInteger loansTotalSupply = BigInteger.TEN.multiply(EXA);
131+
BigInteger swapBalance = BigInteger.TWO.multiply(EXA);
132+
BigInteger swapTotalSupply = BigInteger.TEN.multiply(EXA);
133+
when(mockBalanced.governance.mock.getIsShutdown()).thenReturn(true);
134+
135+
// Act
136+
mockBalanceAndSupply(loans, "Loans", account.getAddress(), loansBalance, loansTotalSupply);
137+
mockBalanceAndSupply(dex, "sICX/ICX", account.getAddress(), swapBalance, swapTotalSupply);
138+
rewardsScore.invoke(loans.account, "updateRewardsData", "Loans", loansTotalSupply.subtract(loansBalance),
139+
account.getAddress(), BigInteger.ZERO);
140+
rewardsScore.invoke(dex.account, "updateRewardsData", "sICX/ICX", swapTotalSupply.subtract(swapBalance),
141+
account.getAddress(), BigInteger.ZERO);
142+
143+
sm.getBlock().increase(DAY*2);
144+
145+
// Assert
146+
verify(baln.mock, times(0)).transfer(any(), any(), any());
147+
}
148+
104149
@Test
105150
void claimRewards_updateBalanceAndSupply() {
106151
// Arrange

score-lib/src/main/java/network/balanced/score/lib/interfaces/Governance.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,13 @@ public interface Governance extends
4040
Fallback,
4141
Version {
4242

43+
4344
@External(readonly = true)
4445
BigInteger getDay();
4546

47+
@External(readonly = true)
48+
public boolean getIsShutdown();
49+
4650
@External(readonly = true)
4751
Map<String, BigInteger> getVotersCount(BigInteger vote_index);
4852

token-contracts/bBaln/src/main/java/network/balanced/score/tokens/BoostedBalnImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ public void withdrawEarly() {
243243
BigInteger maxPenalty = value.divide(BigInteger.TWO);
244244
BigInteger variablePenalty = balanceOf(sender, null);
245245
BigInteger penaltyAmount = variablePenalty.min(maxPenalty);
246+
if (Context.call(Boolean.class, BalancedAddressManager.getGovernance(), "getIsShutdown")) {
247+
penaltyAmount = BigInteger.ZERO;
248+
}
246249
BigInteger returnAmount = value.subtract(penaltyAmount);
247250

248251
LockedBalance oldLocked = locked.newLockedBalance();
@@ -255,8 +258,10 @@ public void withdrawEarly() {
255258
this.checkpoint(sender, oldLocked, locked);
256259

257260

261+
if( penaltyAmount.compareTo(BigInteger.ZERO) > 0) {
258262
Context.call(getBaln(), "transfer", this.penaltyAddress.get(), penaltyAmount,
259263
"withdrawPenalty".getBytes());
264+
}
260265
Context.call(getBaln(), "transfer", sender, returnAmount, "withdrawEarly".getBytes());
261266

262267
users.remove(sender);

token-contracts/bBaln/src/test/java/network/balanced/score/tokens/StateMachineTest.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import static org.mockito.ArgumentMatchers.any;
3535
import static org.mockito.Mockito.doNothing;
3636
import static org.mockito.Mockito.spy;
37+
import static org.mockito.Mockito.when;
3738

3839
@DisplayName("Statemachine Tests")
3940
public class StateMachineTest extends AbstractBoostedBalnTest {
@@ -46,7 +47,7 @@ public class StateMachineTest extends AbstractBoostedBalnTest {
4647
private final ArrayList<Account> accounts = new ArrayList<>();
4748
private final long MAXIMUM_LOCK_WEEKS = 208;
4849
private final long BLOCK_TIME = 2 * 1_000_000;
49-
50+
protected MockBalanced mockBalanced;
5051
private Score bBalnScore;
5152
private BoostedBalnImpl scoreSpy;
5253

@@ -81,7 +82,7 @@ private void setupAccounts() {
8182

8283
@BeforeEach
8384
public void setup() throws Exception {
84-
MockBalanced mockBalanced = new MockBalanced(sm, owner);
85+
mockBalanced = new MockBalanced(sm, owner);
8586
MockBalanced.addressManagerMock.when(() -> BalancedAddressManager.getBaln()).thenReturn(tokenScore.getAddress());
8687

8788
bBalnScore = sm.deploy(owner, BoostedBalnImpl.class, mockBalanced.governance.getAddress(), "bBALN");
@@ -434,6 +435,20 @@ void unlockEarlyBeforeExpiry_belowMaxPenalty() {
434435
tokenScore.invoke(penaltyAddress, "transfer", accounts.get(0).getAddress(), penalty, new byte[0]);
435436
}
436437

438+
@DisplayName("early before the expiry, when shutdown")
439+
@Test
440+
void unlockEarlyBeforeExpiry_isShutdown() {
441+
when(mockBalanced.governance.mock.getIsShutdown()).thenReturn(true);
442+
long increasedUnlockTime = addWeeksToCurrentTimestamp(180);
443+
increaseUnlockTime(accounts.get(0), BigInteger.valueOf(increasedUnlockTime));
444+
bBalnScore.invoke(accounts.get(0), "withdrawEarly");
445+
446+
assertEquals(MINT_AMOUNT, tokenScore.call("balanceOf",
447+
accounts.get(0).getAddress()));
448+
votingBalances.put(accounts.get(0), new VotingBalance());
449+
450+
}
451+
437452
@DisplayName("early before the expiry, with max penalty")
438453
@Test
439454
void unlockEarlyBeforeExpiry_aboveMaxPenalty() {

0 commit comments

Comments
 (0)