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 28a60e1..55d82b2 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);
+ private 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);
@@ -41,6 +45,7 @@ public class CPFTreasury extends SetterGetter implements CPFTreasuryInterface {
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 DictDB councilManagersReward = Context.newDictDB(COUNCIL_MANAGERS_REWARD, BigInteger.class);
public CPFTreasury(@Optional Address cpsScore) {
@@ -278,7 +283,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());
}
}
}
@@ -336,7 +341,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);
}
@@ -399,6 +404,70 @@ 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 rewardPool = finalFund.subtract(initialFund).multiply(BigInteger.valueOf(2).divide(BigInteger.valueOf(100)));
+ return Map.of(INITIAL_FUND, initialFund,
+ FINAL_FUND, finalFund,
+ "rewardPool", rewardPool);
+ }
+
+ @External
+ public void distributeRewardToFundManagers() {
+ validateCpsScore();
+
+ 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("rewardPool");
+
+
+ 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) {
@@ -489,7 +558,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++) {
@@ -499,12 +568,26 @@ 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);
+ }
+
+ private static boolean containsInArrayDb(T value, ArrayDB array) {
+ boolean contains = false;
+ if (array == null || value == null) {
+ return contains;
+ }
+
+ for (int i = 0; i < array.size(); i++) {
+ if (array.get(i) != null && array.get(i).equals(value)) {
+ contains = true;
+ break;
+ }
+ }
+ return contains;
}
-
//EventLogs
@Override
@EventLog(indexed = 1)
@@ -529,4 +612,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 0645ebc..072d01b 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";
@@ -51,6 +56,7 @@ public class Constants {
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 int sICXICXPoolID = 1;
public static final int sICXBNUSDPoolID = 2;
diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java
index 1adcb30..3687cab 100644
--- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java
+++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/CPSCore.java
@@ -1260,6 +1260,7 @@ public void updatePeriod() {
period.periodName.set(TRANSITION_PERIOD);
period.previousPeriodName.set(APPLICATION_PERIOD);
period.updatePeriodIndex.set(updateIndex + 1);
+ callScore(getCpfTreasuryScore(), "setRewardPool", "finalFund");
updateProposalsResult();
PeriodUpdate("Period Update State 1/4. Period Updated to Transition Period. " +
@@ -1292,6 +1293,8 @@ public void updatePeriod() {
period.periodCount.set(period.periodCount.getOrDefault(0) + 1);
burn(proposalFees.get(), null);
proposalFees.set(BigInteger.ZERO);
+ callScore(getCpfTreasuryScore(), "distributeRewardToFundManagers");
+
}
}
@@ -1430,16 +1433,16 @@ private void updateProgressReportResult() {
boolean extended = MilestoneDb.extensionFlag.at(milestonePrefix).getOrDefault(false);
int finalPeriodToSubmit = proposalPeriod + completionPeriod;
- if (getPeriodCount() < finalPeriodToSubmit){
- milestonePassed +=1;
- }else if (getPeriodCount() >= finalPeriodToSubmit && !extended) {
- milestonePassed += 1;
- String proposalPrefix = proposalPrefix(_ipfs_hash);
- int project_duration = (int) _proposal_details.get(PROJECT_DURATION);
- MilestoneDb.extensionFlag.at(milestonePrefix).set(true);
- ProposalDataDb.projectDuration.at(proposalPrefix).set(project_duration + 1);
- MilestoneDb.completionPeriod.at(milestonePrefix).set(completionPeriod + 1);
- }
+ if (getPeriodCount() < finalPeriodToSubmit) {
+ milestonePassed += 1;
+ } else if (getPeriodCount() >= finalPeriodToSubmit && !extended) {
+ milestonePassed += 1;
+ String proposalPrefix = proposalPrefix(_ipfs_hash);
+ int project_duration = (int) _proposal_details.get(PROJECT_DURATION);
+ MilestoneDb.extensionFlag.at(milestonePrefix).set(true);
+ ProposalDataDb.projectDuration.at(proposalPrefix).set(project_duration + 1);
+ MilestoneDb.completionPeriod.at(milestonePrefix).set(completionPeriod + 1);
+ }
updateMilestoneDB(milestonePrefix);
}
} else {
@@ -2676,24 +2679,24 @@ public Boolean hasTwoThirdsMajority(String key, boolean isMilestone) {
//error: milestonedb doesnt have total votes or voters
Map milestoneDbData = MilestoneDb.getDataFromMilestoneDB(key);
- BigInteger totalVotes = isMilestone ? (BigInteger)milestoneDbData.get(TOTAL_VOTES) : ProgressReportDataDb.totalVotes.at(key).getOrDefault(BigInteger.ZERO);
- int totalVoters = isMilestone ? (Integer)milestoneDbData.get(TOTAL_VOTERS) : ProgressReportDataDb.totalVoters.at(key).getOrDefault(0);
-
+ BigInteger totalVotes = isMilestone ? (BigInteger) milestoneDbData.get(TOTAL_VOTES) : ProgressReportDataDb.totalVotes.at(key).getOrDefault(BigInteger.ZERO);
+ int totalVoters = isMilestone ? (Integer) milestoneDbData.get(TOTAL_VOTERS) : ProgressReportDataDb.totalVoters.at(key).getOrDefault(0);
+
BigInteger approveVotes = isMilestone ? MilestoneDb.approvedVotes.at(key).getOrDefault(BigInteger.ZERO) : ProgressReportDataDb.approvedVotes.at(key).getOrDefault(BigInteger.ZERO);
int approveVoters = isMilestone ? MilestoneDb.approveVoters.at(key).size() : ProgressReportDataDb.approveVoters.at(key).size();
-
+
//need to give vote weights = 100 (arbitrary)
boolean voteWeightCheck = approveVotes.multiply(BigInteger.valueOf(3)).compareTo(totalVotes.multiply(BigInteger.valueOf(2))) >= 0;
boolean voterCountCheck = approveVoters * 3 >= totalVoters * 2;
-
+
return voteWeightCheck && voterCountCheck;
}
-
+
public List getCouncilManagers() {
return callScore(List.class, getCpfTreasuryScore(), "getCouncilManagers");
}
-
+
public boolean getCouncilFlag() {
return callScore(boolean.class, getCpfTreasuryScore(), "getCouncilFlag");
}