diff --git a/.gitignore b/.gitignore
index 6151cd4b..68f9b533 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,3 +36,6 @@ gradle.properties
.classpath
.settings
**/bin/
+
+*.ipynb
+*.csv
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..e2636d58
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "cps-gochain-local"]
+ path = cps-gochain-local
+ url = git@github.com:naneey/cps-gochain-local.git
diff --git a/CPFTreasury/build.gradle b/CPFTreasury/build.gradle
index cbfe0f77..fdbdfcef 100644
--- a/CPFTreasury/build.gradle
+++ b/CPFTreasury/build.gradle
@@ -1,18 +1,21 @@
-version = '1.2.0'
+version = '1.5.0'
dependencies {
- compileOnly 'foundation.icon:javaee-api:0.9.1'
- implementation project(':score-lib')
-
- implementation 'com.github.sink772:javaee-tokens:0.6.1'
- implementation 'com.github.sink772:minimal-json:0.9.6'
+// compileOnly 'foundation.icon:javaee-api:0.9.1'
+// implementation project(':score-lib')
+//
+// implementation 'com.github.sink772:javaee-tokens:0.6.1'
+// implementation 'com.github.sink772:minimal-json:0.9.6'
+//
+// testImplementation 'foundation.icon:javaee-unittest:0.9.2'
+// implementation 'org.mockito:mockito-core:4.3.1'
+// testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
+// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
+ testImplementation('org.mockito:mockito-inline:4.8.0')
+// implementation 'foundation.icon:javaee-scorex:0.5.2'
- testImplementation 'foundation.icon:javaee-unittest:0.9.2'
- implementation 'org.mockito:mockito-core:4.3.1'
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
- testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
- testImplementation('org.mockito:mockito-inline:4.3.1')
- implementation 'foundation.icon:javaee-scorex:0.5.2'
+ implementation project(':score-lib')
+ testImplementation project(':test-lib')
}
@@ -28,27 +31,29 @@ deployJar {
lisbon {
uri = 'https://lisbon.net.solidwallet.io/api/v3'
nid = 0x2
- to = 'cx3d4182c0e783b7ef97ba63409c4bdf808853bd9f'
- }
- local {
- uri = 'http://localhost:9082/api/v3'
- nid = 0x3
- }
- berlin {
- uri = 'https://berlin.net.solidwallet.io/api/v3'
- nid = 0x7
+ to = "cxd19ed92de2050a87c709097b6297aadf5f8d7432"
}
+
mainnet {
uri = 'https://ctz.solidwallet.io/api/v3'
nid = 0x1
to = 'cxdca1178010b5368aea929ad5c06abee64b91acc2'
}
+ devnet{
+ uri = "https://tt.net.solidwallet.io/api/v3"
+ nid = 0x3
+ to = "cx0d0638e5764ede3ed2c9eadd179bc67785868842"
+ }
}
keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : ''
password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : ''
+ parameters {
+ arg("cpsScore", "cx5100c8b221cc373939d8a720ecfbd90440c75ed3")
+ }
}
+
test {
useJUnitPlatform()
}
diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java
index abbbe140..3e4d6415 100644
--- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java
+++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java
@@ -26,10 +26,14 @@ public class CPFTreasury extends SetterGetter implements CPFTreasuryInterface {
public static final VarDB
sICXScore = Context.newVarDB(SICX_SCORE, Address.class);
public static final VarDB routerScore = Context.newVarDB(ROUTER_SCORE, Address.class);
public static final VarDB oracleAddress = Context.newVarDB(ORACLE_ADDRESS, Address.class);
+
private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class);
private final DictDB proposalBudgets = Context.newDictDB(PROPOSAL_BUDGETS, BigInteger.class);
+
private final VarDB treasuryFund = Context.newVarDB(TREASURY_FUND, BigInteger.class);
private final VarDB emergencyFund = Context.newVarDB(EMERGENCY_FUND, BigInteger.class);
+ public static final DictDB rewardPool = Context.newDictDB(REWARD_POOL, BigInteger.class);
+
private final VarDB treasuryFundbnUSD = Context.newVarDB(TREASURY_FUND_BNUSD, BigInteger.class);
private final VarDB swapState = Context.newVarDB(SWAP_STATE, Integer.class);
@@ -39,13 +43,29 @@ public class CPFTreasury extends SetterGetter implements CPFTreasuryInterface {
private final VarDB swapFlag = Context.newVarDB(SWAP_FLAG, Boolean.class);
private final VarDB swapLimitAmount = Context.newVarDB(SWAP_LIMIT_AMOUNT, BigInteger.class);
- public CPFTreasury() {
+ public static final VarDB councilFlag = Context.newVarDB(COUNCIL_FLAG, Boolean.class);
+ public static final ArrayDB councilManagers = Context.newArrayDB(COUNCIL_MANAGERS, Address.class);
+
+ public static final VarDB councilManagerRewardPercentage = Context.newVarDB(COUNCIL_MANAGERS_REWARD_PERCENTAGE, Integer.class);
+ public static final DictDB councilManagersReward = Context.newDictDB(COUNCIL_MANAGERS_REWARD, BigInteger.class);
+
+
+ public CPFTreasury(@Optional Address cpsScore) {
if (treasuryFund.get() == null) {
- treasuryFund.set(BigInteger.valueOf(1000000).multiply(EXA));
+ treasuryFund.set(BigInteger.valueOf(5000000).multiply(EXA));
swapCount.set(SwapReset);
swapState.set(SwapReset);
swapFlag.set(false);
+ treasuryFundbnUSD.set(BigInteger.valueOf(5000000).multiply(EXA));
+ CPFTreasury.cpsScore.set(cpsScore);
}
+
+ councilFlag.set(true);
+ councilManagers.add(Address.fromString("hxd4eb0a6c591b5e7a76e9a6677da055ebfdd897da"));
+ councilManagers.add(Address.fromString("hx9fa9d224306b0722099d30471b3c2306421aead7"));
+ councilManagers.add(Address.fromString("hx03907c67a68e8d6948cff58f49d39b3d7c8d95ad"));
+ councilManagerRewardPercentage.set(0);
+
}
private boolean proposalExists(String ipfsKey) {
@@ -102,8 +122,7 @@ private void burn(BigInteger amount) {
@Override
@External(readonly = true)
public Map getTotalFunds() {
- return Map.of(ICX, Context.getBalance(Context.getAddress()),
- bnUSD, getBNUSDAvailableBalance());
+ return Map.of(ICX, Context.getBalance(Context.getAddress()), bnUSD, getBNUSDAvailableBalance());
}
@External(readonly = true)
@@ -116,22 +135,32 @@ public BigInteger getEmergencyFund() {
return getTotalFundBNUSD().get(EMERGENCY_FUND);
}
+ @External
+ public void setFundManagersRewards(int paymentPercentage) {
+// validateGovernanceContract();
+ validateAdmins();
+ Context.require(paymentPercentage >= 0 && paymentPercentage <= 100, TAG + " :InvalidPercentage");
+ councilManagerRewardPercentage.set(paymentPercentage);
+ setRewardPool(INITIAL_FUND);
+ }
+
+ @External(readonly = true)
+ public int getFundManagersRewards() {
+ return councilManagerRewardPercentage.getOrDefault(0);
+ }
private Map getTotalFundBNUSD() {
BigInteger bnusdBalance = (BigInteger) Context.call(balancedDollar.get(), "balanceOf", Context.getAddress());
BigInteger emergencyFund = this.emergencyFund.getOrDefault(BigInteger.ZERO);
BigInteger availableBalance = bnusdBalance.subtract(emergencyFund);
- return Map.of(BNUSD_BALANCE, bnusdBalance,
- EMERGENCY_FUND, emergencyFund,
- AVAILABLE_BALANCE, availableBalance);
+ return Map.of(BNUSD_BALANCE, bnusdBalance, EMERGENCY_FUND, emergencyFund, AVAILABLE_BALANCE, availableBalance);
}
@Override
@External(readonly = true)
public Map getRemainingSwapAmount() {
BigInteger maxCap = treasuryFundbnUSD.get();
- return Map.of(MAX_CAP, maxCap,
- REMAINING_TO_SWAP, maxCap.subtract(getBNUSDAvailableBalance()));
+ return Map.of(MAX_CAP, maxCap, REMAINING_TO_SWAP, maxCap.subtract(getBNUSDAvailableBalance()));
}
private void returnFundAmount(Address address, BigInteger value) {
@@ -142,9 +171,7 @@ private void returnFundAmount(Address address, BigInteger value) {
@Override
@External
- public void transferProposalFundToCpsTreasury(String ipfsKey, int projectDuration,
- Address sponsorAddress, Address contributorAddress,
- String tokenFlag, BigInteger totalBudget) {
+ public void transferProposalFundToCpsTreasury(String ipfsKey, int projectDuration, Address sponsorAddress, Address contributorAddress, String tokenFlag, BigInteger totalBudget) {
validateCpsScore();
Context.require(!proposalExists(ipfsKey), TAG + ": Project already exists. Invalid IPFS Hash");
Context.require(tokenFlag.equals(bnUSD), TAG + ": " + tokenFlag + " is not supported. Only " + bnUSD + " token available.");
@@ -176,8 +203,7 @@ public void transferProposalFundToCpsTreasury(String ipfsKey, int projectDuratio
@Override
@External
- public void updateProposalFund(String ipfsKey, @Optional String flag, @Optional BigInteger addedBudget,
- @Optional int totalInstallmentCount) {
+ public void updateProposalFund(String ipfsKey, @Optional String flag, @Optional BigInteger addedBudget, @Optional int totalInstallmentCount) {
validateCpsScore();
Context.require(proposalExists(ipfsKey), TAG + ": IPFS hash does not exist.");
Context.require(flag != null && flag.equals(bnUSD), TAG + ": Unsupported token. " + flag);
@@ -273,7 +299,7 @@ private void swapIcxBnusd(BigInteger amount, BigInteger _minReceive) {
}
Context.call(amount, routerScore.get(), "route", path, _minReceive);
} catch (Exception e) {
- Context.println("Ignoring Errors from Router. Error Message: " + e.getMessage());
+ Context.println("Ignoring Errors from Router. Error Message: " + e.getMessage());
}
}
}
@@ -331,7 +357,7 @@ public void withdrawFromEmergencyFund(BigInteger value, Address address, String
Address balancedDollar = CPFTreasury.balancedDollar.get();
Context.call(balancedDollar, TRANSFER, address, value, "".getBytes());
- EmergencyFundTransferred(address, value,purpose);
+ EmergencyFundTransferred(address, value, purpose);
}
@@ -394,6 +420,66 @@ public void setOraclePercentageDifference(int value) {
oraclePerDiff.set(value);
}
+ @External
+ public void setRewardPool(String key) {
+ validateCpsScore();
+ Context.require(key.equals(INITIAL_FUND) || key.equals(FINAL_FUND), TAG + ": incorrectKeyForPool");
+ rewardPool.set(key, getTotalFundBNUSD().get(AVAILABLE_BALANCE));
+ }
+
+ @External(readonly = true)
+ public Map getRewardPool() {
+ BigInteger finalFund = rewardPool.getOrDefault(FINAL_FUND, BigInteger.ZERO);
+ BigInteger initialFund = rewardPool.getOrDefault(INITIAL_FUND, BigInteger.ZERO);
+ BigInteger fundDiff = finalFund.subtract(initialFund);
+ BigInteger rewardPool = fundDiff.multiply(BigInteger.valueOf(getFundManagersRewards())).divide(BigInteger.valueOf(100));
+ return Map.of(INITIAL_FUND, initialFund, FINAL_FUND, finalFund, REWARD_POOL, rewardPool);
+ }
+
+ @External
+ public void distributeRewardToFundManagers() {
+ validateCpsScore();
+ if (getFundManagersRewards() > 0) {
+ try {
+ Map rewardPool = getRewardPool();
+ BigInteger initialFund = rewardPool.get(INITIAL_FUND);
+ BigInteger finalFund = rewardPool.get(FINAL_FUND);
+
+ Context.require((initialFund.compareTo(BigInteger.ZERO) > 0 && finalFund.compareTo(BigInteger.ZERO) > 0), TAG + ": RewardPoolIsEmpty");
+
+ BigInteger rewardPoolAmount = rewardPool.get(REWARD_POOL);
+ int len = councilManagers.size();
+ BigInteger rewardAmount = rewardPoolAmount.divide(BigInteger.valueOf(len));
+
+ for (int i = 0; i < len; i++) {
+ Address manager = councilManagers.get(i);
+ councilManagersReward.set(manager, councilManagersReward.getOrDefault(manager, BigInteger.ZERO).add(rewardAmount));
+ FundManagerRewardSet(manager, rewardAmount);
+ }
+
+ } catch (Exception e) {
+ Context.println("Error in distributeRewardToFundManagers: " + e.getMessage());
+ }
+ setRewardPool(INITIAL_FUND);
+ }
+ }
+
+ @External(readonly = true)
+ public BigInteger getRewardAmountForManager(Address manager) {
+ return councilManagersReward.getOrDefault(manager, BigInteger.ZERO);
+ }
+
+ @External
+ public void claimFundManagerReward() {
+ Address manager = Context.getCaller();
+ BigInteger rewardAmount = councilManagersReward.getOrDefault(manager, BigInteger.ZERO);
+ Context.require(rewardAmount.compareTo(BigInteger.ZERO) > 0, TAG + ": No reward to claim.");
+
+ councilManagersReward.set(manager, BigInteger.ZERO);
+ Context.call(balancedDollar.get(), TRANSFER, manager, rewardAmount, "".getBytes());
+ FundManagerRewardClaimed(manager, rewardAmount);
+ }
+
@Override
@External(readonly = true)
public Map getProposalDetails(@Optional int startIndex, @Optional int endIndex) {
@@ -433,8 +519,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) {
Address sICX = sICXScore.get();
Address caller = Context.getCaller();
- Context.require(caller.equals(bnUSDScore) || caller.equals(sICX), TAG +
- " Only " + bnUSDScore + " and " + sICX + " can send tokens to CPF Treasury.");
+ Context.require(caller.equals(bnUSDScore) || caller.equals(sICX), TAG + " Only " + bnUSDScore + " and " + sICX + " can send tokens to CPF Treasury.");
if (caller.equals(sICX)) {
if (_from.equals(dexScore.get())) {
JsonObject swapICX = new JsonObject();
@@ -444,7 +529,6 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) {
Context.revert(TAG + ": sICX can be approved only from Balanced DEX.");
}
} else {
-
if (_data == null || new String(_data).equalsIgnoreCase("none")) {
_data = "{}".getBytes();
}
@@ -484,7 +568,7 @@ public void fallback() {
}
@External
- public void migrateOldHashToNewHash(String oldHash, String newHash){
+ public void migrateOldHashToNewHash(String oldHash, String newHash) {
validateCpsScore();
int size = proposalsKeys.size();
for (int i = 0; i < size; i++) {
@@ -494,8 +578,8 @@ public void migrateOldHashToNewHash(String oldHash, String newHash){
}
BigInteger totalBudget = proposalBudgets.get(oldHash);
- proposalBudgets.set(oldHash,null);
- proposalBudgets.set(newHash,totalBudget);
+ proposalBudgets.set(oldHash, null);
+ proposalBudgets.set(newHash, totalBudget);
}
@@ -523,4 +607,12 @@ public void FundReceived(Address _sponsor_address, String note) {
@EventLog(indexed = 1)
public void EmergencyFundTransferred(Address _address, BigInteger _value, String _purpose) {
}
+
+ @EventLog(indexed = 1)
+ public void FundManagerRewardSet(Address _address, BigInteger _value) {
+ }
+
+ @EventLog(indexed = 1)
+ public void FundManagerRewardClaimed(Address _address, BigInteger _value) {
+ }
}
diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java
index a440ebdb..ff084bda 100644
--- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java
+++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java
@@ -17,6 +17,11 @@ public class Constants {
public static final String PROPOSALS_KEYS = "_proposals_keys";
public static final String TREASURY_FUND = "treasury_fund";
public static final String EMERGENCY_FUND = "emergencyFund";
+ public static final String REWARD_POOL = "rewardPool";
+
+ public static final String INITIAL_FUND = "initialFund";
+ public static final String FINAL_FUND = "finalFund";
+
public static final String AVAILABLE_BALANCE = "availableBalance";
public static final String TREASURY_FUND_BNUSD = "treasury_fund_bnusd";
@@ -49,6 +54,11 @@ public class Constants {
public static final String STATE = "state";
public static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000");
+ public static final String COUNCIL_FLAG = "council_flag";
+ public static final String COUNCIL_MANAGERS = "council_managers";
+ public static final String COUNCIL_MANAGERS_REWARD = "councilManagersReward";
+ public static final String COUNCIL_MANAGERS_REWARD_PERCENTAGE = "councilManagersRewardPercentage";
+
public static final int sICXICXPoolID = 1;
public static final int sICXBNUSDPoolID = 2;
diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/SetterGetter.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/SetterGetter.java
index 41808227..1698c965 100644
--- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/SetterGetter.java
+++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/SetterGetter.java
@@ -1,11 +1,18 @@
package community.icon.cps.score.cpftreasury;
import score.Address;
+import score.ArrayDB;
import score.Context;
import score.annotation.External;
+import scorex.util.ArrayList;
import java.math.BigInteger;
+import java.util.List;
+import static community.icon.cps.score.cpftreasury.CPFTreasury.councilFlag;
+import static community.icon.cps.score.cpftreasury.CPFTreasury.councilManagers;
+import static community.icon.cps.score.cpftreasury.Constants.TAG;
+import static community.icon.cps.score.cpftreasury.Validations.validateAdmins;
import static community.icon.cps.score.cpftreasury.Validations.validateGovernanceContract;
public class SetterGetter {
@@ -153,20 +160,67 @@ public Address getOracleAddress() {
@External
public void setSponsorBondPercentage(BigInteger bondValue) {
- validateGovernanceContract();
- Context.call( getCpsScore(), "setSponsorBondPercentage",bondValue);
+ validateAdmins();
+ Context.call(getCpsScore(), "setSponsorBondPercentage", bondValue);
}
@External
public void setPeriod(BigInteger applicationPeriod) {
validateGovernanceContract();
- Context.call(getCpsScore(), "setPeriod",applicationPeriod);
+ Context.call(getCpsScore(), "setPeriod", applicationPeriod);
}
@External
public void setOnsetPayment(BigInteger paymentPercentage) {
validateGovernanceContract();
- Context.call(getCpsTreasuryScore(), "setOnsetPayment",paymentPercentage);
+ Context.call(getCpsTreasuryScore(), "setOnsetPayment", paymentPercentage);
+ }
+
+ @External
+ public void toggleCouncilFlag() {
+ validateGovernanceContract();
+ councilFlag.set(!councilFlag.getOrDefault(false));
+ }
+
+ @External(readonly = true)
+ public boolean getCouncilFlag() {
+ return councilFlag.getOrDefault(false);
+ }
+
+ @External
+ public void setCouncilManagers(Address[] newCouncilManagers) {
+ validateGovernanceContract();
+ int sizeOfCouncilManagers = newCouncilManagers.length;
+ Context.require(sizeOfCouncilManagers >= 3, TAG + ":: council managers should be greater than 3");
+ Context.require(sizeOfCouncilManagers % 2 == 1, TAG + ":: council managers should be an odd number");
+ if (councilManagers.size() > 0) {
+ clearArrayDb(councilManagers);
+ }
+ for (Address newCouncilManager : newCouncilManagers) {
+ councilManagers.add(newCouncilManager);
+ }
+ }
+
+ @External(readonly = true)
+ public List getCouncilManagers() {
+ return arrayDBtoList(councilManagers);
+ }
+
+
+ List arrayDBtoList(ArrayDB arraydb) {
+ List list = new ArrayList<>();
+ for (int i = 0; i < arraydb.size(); i++) {
+ list.add(arraydb.get(i));
+ }
+ return list;
+ }
+
+ void clearArrayDb(ArrayDB> array_db) {
+ int size = array_db.size();
+ for (int i = 0; i < size; i++) {
+ array_db.pop();
+ }
+
}
}
diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java
index d3defdab..3fd3d6eb 100644
--- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java
+++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java
@@ -3,7 +3,6 @@
import score.Address;
import score.Context;
-import static community.icon.cps.score.cpftreasury.Constants.SYSTEM_ADDRESS;
import static community.icon.cps.score.cpftreasury.Constants.TAG;
public class Validations {
@@ -14,7 +13,9 @@ public static void validateAdmins() {
}
public static void validateGovernanceContract() {
- Context.require(Context.getCaller().equals(SYSTEM_ADDRESS),
+ Address caller = Context.getCaller();
+ Address owner = Context.getOwner();
+ Context.require(caller.equals(owner),
TAG + ": Only Admins can call this method");
}
diff --git a/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java b/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java
index 86629044..2cc6a6af 100644
--- a/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java
+++ b/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java
@@ -15,15 +15,27 @@
import score.Context;
import score.DictDB;
import score.VarDB;
+import scorex.util.HashMap;
+import java.util.Arrays;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class CPFTTreasuryTest extends TestBase {
private static final Address score_address = Address.fromString("cx0000000000000000000000000000000000000000");
@@ -36,6 +48,8 @@ public class CPFTTreasuryTest extends TestBase {
public static final String TAG = "CPF_TREASURY";
private static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000");
+ VarDB cpsScore = mock(VarDB.class);
+
private static final ServiceManager sm = getServiceManager();
private static final Account owner = sm.createAccount();
@@ -49,7 +63,7 @@ public class CPFTTreasuryTest extends TestBase {
@BeforeEach
public void setup() throws Exception {
- tokenScore = sm.deploy(owner, CPFTreasury.class);
+ tokenScore = sm.deploy(owner, CPFTreasury.class,cpsScore.get());
}
@Test
@@ -76,7 +90,6 @@ public void setMaximumTreasuryFundBNUSDExceptions(Account address) {
@Test
void setCPSScore() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setCpsScore", score_address);
@@ -86,7 +99,6 @@ void setCPSScore() {
@Test
void setCPSTreasuryScore() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setCpsTreasuryScore", score_address);
@@ -96,7 +108,6 @@ void setCPSTreasuryScore() {
@Test
void setBMUSDScore() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setBnUSDScore", score_address);
@@ -106,7 +117,6 @@ void setBMUSDScore() {
@Test
void setSICXScore() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setSicxScore", score_address);
@@ -116,7 +126,6 @@ void setSICXScore() {
@Test
void setDEXScore() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setDexScore", score_address);
@@ -126,7 +135,6 @@ void setDEXScore() {
@Test
void setRouterScore() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setRouterScore", score_address);
@@ -175,7 +183,6 @@ void setDEXScoreExceptions(Account address, Address _score) {
}
void setRouterScoreExceptions(Account address, Address _score) {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(false);
tokenScore.invoke(address, "setRouterScore", _score);
@@ -186,7 +193,6 @@ void setRouterScoreExceptions(Account address, Address _score) {
@Test
void setCPSScoreNotAdmin() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)){
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(false);
tokenScore.invoke(testing_account, "setCpsScore", score_address);
@@ -290,7 +296,6 @@ void updateProposalFund() {
}
void setMaxCapIcxAndBnusd() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER));
@@ -301,7 +306,6 @@ void setMaxCapIcxAndBnusd() {
@Test
void setMaxCapIcxAndBnusdTest() {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER));
@@ -313,7 +317,6 @@ void setMaxCapIcxAndBnusdTest() {
void swapIcxBnusd() {
setSICXScoreMethod(sicxScore);
setBNUSDScoreMethod(bnUSDScore);
- VarDB cpsScore = mock(VarDB.class);
VarDB routerScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
@@ -687,7 +690,6 @@ void fallbackSenderIsNotDex() {
@Test
void toggleSwapFlag(){
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner,"toggleSwapFlag");
@@ -697,7 +699,6 @@ void toggleSwapFlag(){
@Test
void transferToEmergencyFund(){
- VarDB cpsScore = mock(VarDB.class);
VarDB balanceDollar = mock(VarDB.class);
BigInteger emergencyFund = BigInteger.valueOf(10).multiply(ICX);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)){
@@ -712,7 +713,6 @@ void transferToEmergencyFund(){
@Test
void withdrawFromEmergencyFund(){
transferToEmergencyFund();
- VarDB cpsScore = mock(VarDB.class);
VarDB balanceDollar = mock(VarDB.class);
BigInteger withdrawAmount = BigInteger.valueOf(4).multiply(ICX);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)){
@@ -727,7 +727,6 @@ void withdrawFromEmergencyFund(){
@Test
void slippagePercentage() {
- VarDB cpsScore = mock(VarDB.class);
int value = 10;
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
@@ -739,6 +738,120 @@ void slippagePercentage() {
}
}
+ @Test
+ void toggleCouncilFlag(){
+ try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
+ theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
+ tokenScore.invoke(owner,"toggleCouncilFlag");
+ assertEquals(true,tokenScore.call("getCouncilFlag"));
+ }
+ }
+
+ @Test
+void setCouncilManagers() {
+ Address A = Address.fromString("hx0000000000000000000000000000000000000007");
+ Address B = Address.fromString("hx0000000000000000000000000000000000000008");
+ Address C = Address.fromString("hx0000000000000000000000000000000000000009");
+
+ Address[] CManagers = {A, B, C};
+
+ try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
+ theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
+ tokenScore.invoke(owner, "setCouncilManagers", (Object) CManagers);
+
+ List returnedManagers = (List) tokenScore.call("getCouncilManagers");
+
+ for (int i = 0; i < CManagers.length; i++) {
+ assertEquals(CManagers[i], returnedManagers.get(i));
+ }
+ }
+}
+
+@Test
+public void testSetRewardPool() {
+ setCPSScoreMethod(score_address);
+
+ final String AVAILABLE_BALANCE = "availableBalance";
+
+ String initialFundKey = "INITIAL_FUND";
+ String finalFundKey = "FINAL_FUND";
+ String invalidKey = "INVALID_KEY";
+ BigInteger availableBalance = BigInteger.valueOf(1000);
+
+ Map totalFund = new HashMap<>();
+ totalFund.put(AVAILABLE_BALANCE, availableBalance);
+
+ VarDB rewardPoolMock = mock(VarDB.class);
+
+ CPFTreasury cpsScore = mock(CPFTreasury.class);
+
+ when(rewardPoolMock.get()).thenReturn(availableBalance);
+
+ cpsScore.setRewardPool(initialFundKey);
+
+ assertEquals(availableBalance, rewardPoolMock.get());
+
+ cpsScore.setRewardPool(finalFundKey);
+
+ assertEquals(availableBalance, rewardPoolMock.get());
+
+ // IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+ // cpsScore.setRewardPool(invalidKey);
+ // });
+ // assertTrue(exception.getMessage().contains("incorrectKeyForPool"));
+}
+
+
+public class RewardVoteTest {
+
+ private final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L);
+
+ @Test
+ public void testRewardVote() {
+ setCPSScoreMethod(score_address);
+ MockedStatic contextMock = mockStatic(Context.class);
+
+ BigInteger newFunds = BigInteger.valueOf(400).multiply(EXA);
+
+ contextMock.when(() -> getRemainingFund()).thenReturn(newFunds);
+
+ Address A = Address.fromString("hx0000000000000000000000000000000000000001");
+ Address B = Address.fromString("hx0000000000000000000000000000000000000002");
+ List councilManagers = Arrays.asList(A, B);
+ contextMock.when(() -> getCouncilManagers()).thenReturn(councilManagers);
+
+ rewardVote();
+
+ BigInteger expectedRewardPerManager = BigInteger.valueOf(4).multiply(EXA);
+ contextMock.verify(() -> Context.call(A, "distributeRewardToFundManagers", expectedRewardPerManager));
+ contextMock.verify(() -> Context.call(B, "distributeRewardToFundManagers", expectedRewardPerManager));
+
+ contextMock.close();
+ }
+
+ private BigInteger getRemainingFund() {
+ return BigInteger.ZERO;
+ }
+
+ private List getCouncilManagers() {
+ return Arrays.asList();
+ }
+
+ private void rewardVote() {
+ BigInteger initialFund = getRemainingFund();
+ BigInteger finalFund = BigInteger.valueOf(400).multiply(EXA);
+
+ BigInteger rewardPool = finalFund.subtract(initialFund).multiply(BigInteger.valueOf(2)).divide(BigInteger.valueOf(100));
+ List councilManagers = getCouncilManagers();
+ BigInteger rewardPerManager = rewardPool.divide(BigInteger.valueOf(councilManagers.size()));
+
+ for (Address manager : councilManagers) {
+ Context.call(manager, "distributeRewardToFundManagers", rewardPerManager);
+ }
+ }
+}
+
+
public void expectErrorMessage(Executable contractCall, String errorMessage) {
AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall);
@@ -746,7 +859,6 @@ public void expectErrorMessage(Executable contractCall, String errorMessage) {
}
void setCPSScoreMethod(Address scoreAddress) {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setCpsScore", scoreAddress);
@@ -754,7 +866,6 @@ void setCPSScoreMethod(Address scoreAddress) {
}
void setCPSTreasuryScoreMetod(Address scoreAddress) {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setCpsTreasuryScore", scoreAddress);
@@ -762,7 +873,6 @@ void setCPSTreasuryScoreMetod(Address scoreAddress) {
}
void setBNUSDScoreMethod(Address scoreAddress) {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setBnUSDScore", scoreAddress);
@@ -770,7 +880,6 @@ void setBNUSDScoreMethod(Address scoreAddress) {
}
void setOracleAddressMethod(Address scoreAddress) {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setOracleAddress", scoreAddress);
@@ -778,7 +887,6 @@ void setOracleAddressMethod(Address scoreAddress) {
}
void setSICXScoreMethod(Address scoreAddress) {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setSicxScore", scoreAddress);
@@ -786,7 +894,6 @@ void setSICXScoreMethod(Address scoreAddress) {
}
void setDEXScoreMethod(Address scoreAddress) {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setDexScore", scoreAddress);
@@ -794,7 +901,6 @@ void setDEXScoreMethod(Address scoreAddress) {
}
void setRouterScoreMethod(Address scoreAddress) {
- VarDB cpsScore = mock(VarDB.class);
try (MockedStatic theMock = Mockito.mockStatic(Context.class)) {
theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true);
tokenScore.invoke(owner, "setRouterScore", score_address);
diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle
index d09e2b15..bcacd745 100644
--- a/CPSCore/build.gradle
+++ b/CPSCore/build.gradle
@@ -1,21 +1,25 @@
-version = '1.3.9'
+version = '1.5.5'
dependencies {
- compileOnly 'foundation.icon:javaee-api:0.9.2'
- implementation 'com.github.sink772:minimal-json:0.9.7'
- implementation 'foundation.icon:javaee-scorex:0.5.3'
+
+
+// compileOnly 'foundation.icon:javaee-api:0.9.2'
+// implementation 'com.github.sink772:minimal-json:0.9.7'
+// implementation 'foundation.icon:javaee-scorex:0.5.3'
implementation project(':score-lib')
testImplementation project(':test-lib')
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
- testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
testImplementation('org.mockito:mockito-inline:4.8.0')
- testImplementation 'foundation.icon:javaee-unittest:0.9.7'
- intTestImplementation 'foundation.icon:icon-sdk:2.2.0'
- intTestImplementation project(":score-client")
- intTestAnnotationProcessor project(":score-client")
- testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
+
+// testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
+// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
+// testImplementation('org.mockito:mockito-inline:4.8.0')
+// testImplementation 'foundation.icon:javaee-unittest:0.9.7'
+// intTestImplementation 'foundation.icon:icon-sdk:2.2.0'
+//// intTestImplementation project(":score-client")
+//// intTestAnnotationProcessor project(":score-client")
+// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
}
optimizedJar {
@@ -23,6 +27,7 @@ optimizedJar {
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
+ enableDebug = false
}
deployJar {
@@ -30,31 +35,25 @@ deployJar {
lisbon {
uri = 'https://lisbon.net.solidwallet.io/api/v3'
nid = 0x2
- to = 'cx8e21d3b7a70aeeaca45d4a70c31a6b959f5823bd'
- }
- local {
- uri = 'http://localhost:9082/api/v3'
- nid = 0x3
- }
- berlin {
- uri = 'https://berlin.net.solidwallet.io/api/v3'
- nid = 0x7
- }
- sejong {
- uri = 'https://sejong.net.solidwallet.io/api/v3'
- nid = 0x53
- to = 'cx2b214d56805531b9c878c4d4ff0e53d961c60834'
+ to = "cx1a7a9bde78fe14e2aeea03966c6d7260575627f5"
}
mainnet {
uri = 'https://ctz.solidwallet.io/api/v3'
nid = 0x1
to = 'cx9f4ab72f854d3ccdc59aa6f2c3e2215dd62e879f'
}
-
+ devnet{
+ uri = "https://tt.net.solidwallet.io/api/v3"
+ nid = 0x3
+ to = "cx5100c8b221cc373939d8a720ecfbd90440c75ed3"
+ }
}
keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : ''
password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : ''
parameters {
+ arg("applicationPeriod", "15")
+ arg("bondValue", "15")
+
}
}
@@ -65,3 +64,24 @@ test {
repositories {
mavenCentral()
}
+
+task integrationTest(type: Test) {
+ useJUnitPlatform()
+
+
+ rootProject.allprojects {
+ if (it.getTasks().findByName('optimizedJar')) {
+ dependsOn(it.getTasks().getByName('optimizedJar'))
+ }
+ }
+
+ options {
+ testLogging.showStandardStreams = true
+ description = 'Runs integration tests.'
+ group = 'verification'
+
+ testClassesDirs = sourceSets.intTest.output.classesDirs
+ classpath = sourceSets.intTest.runtimeClasspath
+ }
+
+}
diff --git a/CPSCore/src/intTest/java/community/icon/cps/integration/CPSCoreIntegration.java b/CPSCore/src/intTest/java/community/icon/cps/integration/CPSCoreIntegration.java
new file mode 100644
index 00000000..98993b3c
--- /dev/null
+++ b/CPSCore/src/intTest/java/community/icon/cps/integration/CPSCoreIntegration.java
@@ -0,0 +1,1784 @@
+package community.icon.cps.integration;
+
+import com.eclipsesource.json.JsonObject;
+import community.icon.cps.score.lib.interfaces.CPSCoreInterface;
+import community.icon.cps.score.lib.interfaces.CPSCoreInterface.MilestonesAttributes;
+import community.icon.cps.score.lib.interfaces.CPSCoreInterface.MilestoneVoteAttributes;
+import community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes;
+import community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes;
+import community.icon.cps.score.test.integration.scores.CPSCoreInterfaceScoreClient;
+import community.icon.cps.score.test.integration.CPS;
+import community.icon.cps.score.test.integration.CPSClient;
+import community.icon.cps.score.test.integration.ScoreIntegrationTest;
+import community.icon.cps.score.test.integration.config.BaseConfig;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import score.Address;
+
+import static community.icon.cps.score.cpscore.utils.Constants.*;
+import static community.icon.cps.score.test.AssertRevertedException.assertUserRevert;
+import static community.icon.cps.score.test.integration.Environment.godClient;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static community.icon.cps.score.test.integration.Environment.preps;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import community.icon.cps.score.test.integration.scores.SystemInterfaceScoreClient;
+import score.UserRevertException;
+import score.annotation.Optional;
+
+public class CPSCoreIntegration implements ScoreIntegrationTest {
+
+ private static CPSClient ownerClient;
+ private static CPSClient testClient;
+ private static CPSClient readerClient;
+ static Set> prepSet = preps.entrySet();
+
+ private final BigInteger ICX = BigInteger.valueOf(10).pow(18);
+
+ private static Map addressMap;
+ public static Map cpsClients = new HashMap<>();
+
+ @BeforeAll
+ public static void setup() throws Exception {
+ String contracts = "conf/contracts.json";
+ CPS cps = new CPS(contracts);
+
+ cps.setupCPS();
+ addressMap = cps.getAddresses();
+ ownerClient = cps.defaultClient();
+ readerClient = cps.newClient(BigInteger.TEN.pow(24));
+ testClient = cps.testClient();
+ BaseConfig config = new BaseConfig(ownerClient);
+ config.call();
+
+ for (int i = 0; i < 7; i++) {
+ String privKey = prepSet.toArray()[i].toString().substring(43);
+ cpsClients.put(i, cps.customClient(privKey));
+
+ }
+ // ICX swap purpose
+ godClient._transfer(addressMap.get("dex"),BigInteger.valueOf(200).multiply(EXA),"transferICX to dex");
+
+ }
+
+ @Test
+ @Order(1)
+ public void name() {
+ ownerClient.cpsCore.name();
+ }
+
+
+ @DisplayName("register all preps")
+ @Test
+ @Order(1)
+ public void registerPrep() {
+
+ // expected Prep address
+ List expectedPrepAddress = new ArrayList<>(cpsClients.size());
+ for (CPSClient prepClient : cpsClients.values()) {
+ prepClient.cpsCore.registerPrep();
+ expectedPrepAddress.add(prepClient.getAddress().toString());
+
+ }
+
+ // actual prep address
+ List